1b50b98ef250f36fcc8b0063977fcd1b1f157e10
[platform/upstream/gst-plugins-good.git] / gst / avi / gstavidemux.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 /* Element-Checklist-Version: 5 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <string.h>
26
27 #include "gst/riff/riff-media.h"
28 #include "gstavidemux.h"
29 #include "avi-ids.h"
30
31 GST_DEBUG_CATEGORY_STATIC (avidemux_debug);
32 #define GST_CAT_DEFAULT avidemux_debug
33
34 /* AviDemux signals and args */
35 enum {
36   /* FILL ME */
37   LAST_SIGNAL
38 };
39
40 enum {
41   ARG_0,
42   ARG_STREAMINFO,
43   /* FILL ME */
44 };
45
46 static GstStaticPadTemplate sink_templ =
47 GST_STATIC_PAD_TEMPLATE (
48   "sink",
49   GST_PAD_SINK,
50   GST_PAD_ALWAYS,
51   GST_STATIC_CAPS ("video/x-msvideo")
52 );
53
54 static void     gst_avi_demux_base_init         (GstAviDemuxClass *klass);
55 static void     gst_avi_demux_class_init        (GstAviDemuxClass *klass);
56 static void     gst_avi_demux_init              (GstAviDemux *avi);
57
58 static void     gst_avi_demux_reset             (GstAviDemux *avi);
59 static void     gst_avi_demux_loop              (GstElement  *element);
60
61 static gboolean gst_avi_demux_send_event        (GstElement  *element,
62                                                  GstEvent    *event);
63
64 static const GstEventMask *
65                 gst_avi_demux_get_event_mask    (GstPad      *pad);
66 static gboolean gst_avi_demux_handle_src_event  (GstPad      *pad,
67                                                  GstEvent    *event);
68 static const GstFormat *
69                 gst_avi_demux_get_src_formats   (GstPad      *pad); 
70 static const GstQueryType *
71                 gst_avi_demux_get_src_query_types (GstPad    *pad);
72 static gboolean gst_avi_demux_handle_src_query  (GstPad      *pad,
73                                                  GstQueryType type, 
74                                                  GstFormat   *format,
75                                                  gint64      *value);
76 static gboolean gst_avi_demux_src_convert       (GstPad      *pad,
77                                                  GstFormat    src_format,
78                                                  gint64       src_value,
79                                                  GstFormat   *dest_format,
80                                                  gint64      *dest_value);
81
82 static GstElementStateReturn
83                 gst_avi_demux_change_state      (GstElement  *element);
84
85 static void     gst_avi_demux_get_property      (GObject     *object,
86                                                  guint        prop_id,  
87                                                  GValue      *value,
88                                                  GParamSpec  *pspec);
89
90 static GstRiffReadClass *parent_class = NULL;
91 /*static guint gst_avi_demux_signals[LAST_SIGNAL] = { 0 }; */
92
93 GType
94 gst_avi_demux_get_type(void) 
95 {
96   static GType avi_demux_type = 0;
97
98   if (!avi_demux_type) {
99     static const GTypeInfo avi_demux_info = {
100       sizeof (GstAviDemuxClass),      
101       (GBaseInitFunc) gst_avi_demux_base_init,
102       NULL,
103       (GClassInitFunc) gst_avi_demux_class_init,
104       NULL,
105       NULL,
106       sizeof (GstAviDemux),
107       0,
108       (GInstanceInitFunc) gst_avi_demux_init,
109     };
110
111     avi_demux_type =
112         g_type_register_static (GST_TYPE_RIFF_READ,
113                                 "GstAviDemux",
114                                 &avi_demux_info, 0);
115   }
116
117   return avi_demux_type;
118 }
119
120 static void
121 gst_avi_demux_base_init (GstAviDemuxClass *klass)
122 {
123   static GstElementDetails gst_avi_demux_details = GST_ELEMENT_DETAILS (
124     "Avi demuxer",
125     "Codec/Demuxer",
126     "Demultiplex an avi file into audio and video",
127     "Erik Walthinsen <omega@cse.ogi.edu>\n"
128     "Wim Taymans <wim.taymans@chello.be>\n"
129     "Ronald Bultje <rbultje@ronald.bitfreak.net>"
130   );
131   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
132   GstPadTemplate *videosrctempl, *audiosrctempl;
133   GstCaps *audcaps, *vidcaps;
134
135   audcaps = gst_riff_create_audio_template_caps ();
136   audiosrctempl = gst_pad_template_new ("audio_%02d",
137                                         GST_PAD_SRC,
138                                         GST_PAD_SOMETIMES,
139                                         audcaps);
140
141   vidcaps = gst_riff_create_video_template_caps ();
142   gst_caps_append (vidcaps, gst_riff_create_iavs_template_caps ());
143   videosrctempl = gst_pad_template_new ("video_%02d",
144                                         GST_PAD_SRC,
145                                         GST_PAD_SOMETIMES,
146                                         vidcaps);
147
148   gst_element_class_add_pad_template (element_class, audiosrctempl);
149   gst_element_class_add_pad_template (element_class, videosrctempl);
150   gst_element_class_add_pad_template (element_class,
151       gst_static_pad_template_get (&sink_templ));
152   gst_element_class_set_details (element_class, &gst_avi_demux_details);
153 }
154
155 static void
156 gst_avi_demux_class_init (GstAviDemuxClass *klass) 
157 {
158   GObjectClass *gobject_class;
159   GstElementClass *gstelement_class;
160
161   gobject_class = (GObjectClass*)klass;
162   gstelement_class = (GstElementClass*)klass;
163
164   g_object_class_install_property (gobject_class, ARG_STREAMINFO,
165     g_param_spec_boxed ("streaminfo", "Streaminfo", "Streaminfo",
166                         GST_TYPE_CAPS, G_PARAM_READABLE));
167
168   GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux",
169                            0, "Demuxer for AVI streams");
170
171   parent_class = g_type_class_ref (GST_TYPE_RIFF_READ);
172   
173   gobject_class->get_property = gst_avi_demux_get_property;
174   
175   gstelement_class->change_state = gst_avi_demux_change_state;
176   gstelement_class->send_event = gst_avi_demux_send_event;
177 }
178
179 static void 
180 gst_avi_demux_init (GstAviDemux *avi) 
181 {
182   GST_FLAG_SET (avi, GST_ELEMENT_EVENT_AWARE);
183
184   avi->sinkpad = gst_pad_new_from_template (
185         gst_static_pad_template_get (&sink_templ), "sink");
186   gst_element_add_pad (GST_ELEMENT (avi), avi->sinkpad);
187   GST_RIFF_READ (avi)->sinkpad = avi->sinkpad;
188
189   gst_element_set_loop_function (GST_ELEMENT (avi), gst_avi_demux_loop);
190   gst_avi_demux_reset (avi);
191
192   avi->streaminfo = NULL;
193   avi->index_entries = NULL;
194   memset (&avi->stream, 0, sizeof (avi->stream));
195 }
196
197 static void
198 gst_avi_demux_reset (GstAviDemux *avi)
199 {
200   gint i;
201
202   for (i = 0; i < avi->num_streams; i++) {
203     g_free (avi->stream[i].strh);
204     gst_element_remove_pad (GST_ELEMENT (avi), avi->stream[i].pad);
205   }
206   memset (&avi->stream, 0, sizeof (avi->stream));
207
208   avi->num_streams = 0;
209   avi->num_v_streams = 0;
210   avi->num_a_streams = 0;
211
212   avi->state = GST_AVI_DEMUX_START;
213   avi->level_up = 0;
214
215   if (avi->index_entries) {
216     g_free (avi->index_entries);
217     avi->index_entries = NULL;
218   }
219   avi->index_size = 0;
220
221   avi->num_frames = 0;
222   avi->us_per_frame = 0;
223
224   avi->seek_offset = (guint64) -1;
225
226   gst_caps_replace (&avi->streaminfo, NULL);
227 }
228
229 static void
230 gst_avi_demux_streaminfo (GstAviDemux *avi)
231 {
232   /* compression formats are added later - a bit hacky */
233
234   gst_caps_replace (&avi->streaminfo,
235       gst_caps_new_simple ("application/x-gst-streaminfo", NULL));
236
237   /*g_object_notify(G_OBJECT(avi), "streaminfo");*/
238 }
239
240 static gst_avi_index_entry *
241 gst_avi_demux_index_next (GstAviDemux *avi,
242                           gint         stream_nr,
243                           gint         start,
244                           guint32      flags)
245 {
246   gint i;
247   gst_avi_index_entry *entry = NULL;
248
249   for (i = start; i < avi->index_size; i++) {
250     entry = &avi->index_entries[i];
251
252     if (entry->stream_nr == stream_nr && (entry->flags & flags) == flags) {
253       break;
254     }
255   }
256
257   return entry;
258 }
259
260 static gst_avi_index_entry *
261 gst_avi_demux_index_entry_for_time (GstAviDemux *avi,
262                                     gint         stream_nr,
263                                     guint64      time,
264                                     guint32      flags)
265 {
266   gst_avi_index_entry *entry = NULL, *last_entry = NULL;
267   gint i;
268
269   i = -1;
270   do {
271     entry = gst_avi_demux_index_next (avi, stream_nr, i + 1, flags);
272     if (!entry)
273       return NULL;
274
275     i = entry->index_nr;
276
277     if (entry->ts <= time) {
278       last_entry = entry;
279     }
280   } while (entry->ts <= time);
281
282   return last_entry;
283 }
284
285 static gst_avi_index_entry *
286 gst_avi_demux_index_entry_for_byte (GstAviDemux *avi,
287                                     gint         stream_nr,
288                                     guint64      byte,
289                                     guint32      flags)
290 {
291   gst_avi_index_entry *entry = NULL, *last_entry = NULL;
292   gint i;
293
294   i = -1;
295   do {
296     entry = gst_avi_demux_index_next (avi, stream_nr, i + 1, flags);
297     if (!entry)
298       return NULL;
299
300     i = entry->index_nr;
301
302     if (entry->bytes_before <= byte) {
303       last_entry = entry;
304     }
305   } while (entry->bytes_before <= byte);
306
307   return last_entry;
308 }
309
310 static gst_avi_index_entry *
311 gst_avi_demux_index_entry_for_frame (GstAviDemux *avi,
312                                      gint         stream_nr,
313                                      guint32      frame,
314                                      guint32      flags)
315 {
316   gst_avi_index_entry *entry = NULL, *last_entry = NULL;
317   gint i;
318
319   i = -1;
320   do {
321     entry = gst_avi_demux_index_next (avi, stream_nr, i + 1, flags);
322     if (!entry)
323       return NULL;
324
325     i = entry->index_nr;
326
327     if (entry->frames_before <= frame) {
328       last_entry = entry;
329     }
330   } while (entry->frames_before <= frame);
331
332   return last_entry;
333 }
334
335 static const GstFormat *
336 gst_avi_demux_get_src_formats (GstPad *pad) 
337 {
338   avi_stream_context *stream = gst_pad_get_element_private (pad);
339
340   static const GstFormat src_a_formats[] = {
341     GST_FORMAT_TIME,
342     GST_FORMAT_BYTES,
343     GST_FORMAT_DEFAULT,
344     0
345   };
346   static const GstFormat src_v_formats[] = {
347     GST_FORMAT_TIME,
348     GST_FORMAT_DEFAULT,
349     0
350   };
351
352   return (stream->strh->type == GST_RIFF_FCC_auds ?
353           src_a_formats : src_v_formats);
354 }
355
356 static gboolean
357 gst_avi_demux_src_convert (GstPad    *pad,
358                            GstFormat  src_format,
359                            gint64     src_value,
360                            GstFormat *dest_format,
361                            gint64    *dest_value)
362 {
363   gboolean res = TRUE;
364   /*GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));*/
365   avi_stream_context *stream = gst_pad_get_element_private (pad);
366
367   if (stream->strh->type != GST_RIFF_FCC_auds && 
368       (src_format == GST_FORMAT_BYTES ||
369        *dest_format == GST_FORMAT_BYTES))
370     return FALSE;
371
372   switch (src_format) {
373     case GST_FORMAT_TIME:
374       switch (*dest_format) {
375         case GST_FORMAT_BYTES:
376           *dest_value = src_value * stream->strh->rate /
377                         (stream->strh->scale * GST_SECOND);
378           break;
379         case GST_FORMAT_DEFAULT:
380           *dest_value = src_value * stream->strh->rate /
381                         (stream->strh->scale * GST_SECOND);
382           break;
383         default:
384           res = FALSE;
385           break;
386       }
387       break;
388     case GST_FORMAT_BYTES:
389       switch (*dest_format) {
390         case GST_FORMAT_TIME:
391           *dest_value = ((gfloat) src_value) * GST_SECOND / stream->strh->rate;
392           break;
393         default:
394           res = FALSE;
395           break;
396       }
397       break;
398     case GST_FORMAT_DEFAULT:
399       switch (*dest_format) {
400         case GST_FORMAT_TIME:
401           *dest_value = ((((gfloat) src_value) * stream->strh->scale)  /
402                         stream->strh->rate) * GST_SECOND;
403           break;
404         default:
405           res = FALSE;
406           break;
407       }
408       break;
409     default:
410       res = FALSE;
411   }
412
413   return res;
414 }
415
416 static const GstQueryType *
417 gst_avi_demux_get_src_query_types (GstPad *pad) 
418 {
419   static const GstQueryType src_types[] = {
420     GST_QUERY_TOTAL,
421     GST_QUERY_POSITION,
422     0
423   };
424
425   return src_types;
426 }
427
428 static gboolean
429 gst_avi_demux_handle_src_query (GstPad      *pad,
430                                 GstQueryType type, 
431                                 GstFormat   *format,
432                                 gint64      *value)
433 {
434   gboolean res = TRUE;
435   /*GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));*/
436   avi_stream_context *stream = gst_pad_get_element_private (pad);
437
438   switch (type) {
439     case GST_QUERY_TOTAL:
440       switch (*format) {
441         case GST_FORMAT_TIME:
442           *value = (((gfloat) stream->strh->scale) * stream->strh->length /
443                         stream->strh->rate) * GST_SECOND;
444           break;
445         case GST_FORMAT_BYTES:
446           if (stream->strh->type == GST_RIFF_FCC_auds) {
447             *value = stream->total_bytes;
448           }
449           else
450             res = FALSE;
451           break;
452         case GST_FORMAT_DEFAULT:
453           if (stream->strh->type == GST_RIFF_FCC_auds)
454             *value = stream->strh->length * stream->strh->samplesize;
455           else if (stream->strh->type == GST_RIFF_FCC_vids)
456             *value = stream->strh->length;
457           else
458             res = FALSE;
459           break;
460         default:
461           res = FALSE;
462           break;
463       }
464       break;
465     case GST_QUERY_POSITION:
466       switch (*format) {
467         case GST_FORMAT_TIME:
468           if (stream->strh->samplesize &&
469               stream->strh->type == GST_RIFF_FCC_auds) {
470             *value = ((gfloat) stream->current_byte) * GST_SECOND /
471                         stream->strh->rate;
472           }
473           else {
474             *value = (((gfloat) stream->current_frame) * stream->strh->scale /
475                         stream->strh->rate) * GST_SECOND;
476           }
477           break;
478         case GST_FORMAT_BYTES:
479           *value = stream->current_byte;
480           break;
481         case GST_FORMAT_DEFAULT:
482           if (stream->strh->samplesize &&
483               stream->strh->type == GST_RIFF_FCC_auds) 
484             *value = stream->current_byte * stream->strh->samplesize;
485           else 
486             *value = stream->current_frame;
487           break;
488         default:
489           res = FALSE;
490           break;
491       }
492       break;
493     default:
494       res = FALSE;
495       break;
496   }
497
498   return res;
499 }
500
501 static GstCaps *
502 gst_avi_demux_src_getcaps (GstPad *pad)
503 {
504   avi_stream_context *stream = gst_pad_get_element_private (pad);
505
506   return gst_caps_copy (stream->caps);
507 }
508
509 static gint32
510 gst_avi_demux_sync_streams (GstAviDemux *avi,
511                             guint64      time)
512 {
513   gint i;
514   guint32 min_index = G_MAXUINT;
515   avi_stream_context *stream;
516   gst_avi_index_entry *entry;
517
518   for (i = 0; i < avi->num_streams; i++) {
519     stream = &avi->stream[i];
520
521     GST_DEBUG ("finding %d for time %" G_GINT64_FORMAT, i, time);
522
523     entry = gst_avi_demux_index_entry_for_time (avi, stream->num, time,
524                                                 GST_RIFF_IF_KEYFRAME);
525     if (entry) {
526       min_index = MIN (entry->index_nr, min_index);
527     }
528   }
529   GST_DEBUG ("first index at %d", min_index);
530   
531   /* now we know the entry we need to sync on. calculate number of frames to
532    * skip fro there on and the stream stats */
533   for (i = 0; i < avi->num_streams; i++) {
534     gst_avi_index_entry *next_entry;
535     stream = &avi->stream[i];
536
537     /* next entry */
538     next_entry = gst_avi_demux_index_next (avi, stream->num,
539                                            min_index, 0);
540     /* next entry with keyframe */
541     entry = gst_avi_demux_index_next (avi, stream->num, min_index,
542                                       GST_RIFF_IF_KEYFRAME);
543
544     stream->current_byte = next_entry->bytes_before;
545     stream->current_frame = next_entry->frames_before;
546     stream->skip = entry->frames_before - next_entry->frames_before;
547
548     GST_DEBUG ("%d skip %d", stream->num, stream->skip);
549   }
550
551   GST_DEBUG ("final index at %d", min_index);
552
553   return min_index;
554 }
555
556 static gboolean
557 gst_avi_demux_send_event (GstElement *element,
558                           GstEvent   *event)
559 {
560   const GList *pads;
561
562   pads = gst_element_get_pad_list (element);
563
564   while (pads) { 
565     GstPad *pad = GST_PAD (pads->data);
566
567     if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
568       /* we ref the event here as we might have to try again if the event
569        * failed on this pad */
570       gst_event_ref (event);
571       if (gst_avi_demux_handle_src_event (pad, event)) {
572         gst_event_unref (event);
573
574         return TRUE;
575       }
576     }
577     
578     pads = g_list_next (pads);
579   }
580   
581   gst_event_unref (event);
582
583   return FALSE;
584 }
585
586 static const GstEventMask *
587 gst_avi_demux_get_event_mask (GstPad *pad)
588 {
589   static const GstEventMask masks[] = {
590     { GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
591     { 0, }
592   };
593
594   return masks;
595 }
596         
597 static gboolean
598 gst_avi_demux_handle_src_event (GstPad   *pad,
599                                 GstEvent *event)
600 {
601   gboolean res = TRUE;
602   GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
603   avi_stream_context *stream;
604   
605   stream = gst_pad_get_element_private (pad);
606
607   switch (GST_EVENT_TYPE (event)) {
608     case GST_EVENT_SEEK:
609       GST_DEBUG ("seek format %d, %08x", GST_EVENT_SEEK_FORMAT (event),
610                  stream->strh->type);
611
612       switch (GST_EVENT_SEEK_FORMAT (event)) {
613         case GST_FORMAT_BYTES:
614         case GST_FORMAT_DEFAULT:
615         case GST_FORMAT_TIME: {
616           gst_avi_index_entry *seek_entry, *entry = NULL;
617           gint64 desired_offset = GST_EVENT_SEEK_OFFSET (event);
618           guint32 flags;
619           guint64 min_index;
620
621           /* no seek on audio yet */
622           if (stream->strh->type == GST_RIFF_FCC_auds) {
623             res = FALSE;
624             goto done;
625           }
626           GST_DEBUG ("seeking to %" G_GINT64_FORMAT, desired_offset);
627
628           flags = GST_RIFF_IF_KEYFRAME;
629           switch (GST_EVENT_SEEK_FORMAT (event)) {
630             case GST_FORMAT_BYTES:
631               entry = gst_avi_demux_index_entry_for_byte (avi, stream->num,
632                                                           desired_offset,
633                                                           flags);
634               break;
635             case GST_FORMAT_DEFAULT:
636               entry = gst_avi_demux_index_entry_for_frame (avi, stream->num,
637                                                            desired_offset,
638                                                            flags);
639               break;
640             case GST_FORMAT_TIME:
641               entry = gst_avi_demux_index_entry_for_time (avi, stream->num,
642                                                           desired_offset,
643                                                           flags);
644               break;
645           }
646
647           if (entry) {
648             min_index = gst_avi_demux_sync_streams (avi, entry->ts);
649             seek_entry = &avi->index_entries[min_index];
650
651             avi->seek_offset = seek_entry->offset + avi->index_offset;
652             avi->last_seek = entry->ts;
653           } else {
654             GST_DEBUG ("no index entry found for format=%d value=%"
655                        G_GINT64_FORMAT, GST_EVENT_SEEK_FORMAT (event),
656                        desired_offset);
657             res = FALSE;
658           }
659           break;
660         }
661         default:
662           res = FALSE;
663           break;
664       }
665       break;
666     default:
667       res = FALSE;
668       break;
669   }
670
671 done:
672   gst_event_unref (event);
673
674   return res;
675 }
676
677 /*
678  * "Open" a RIFF file.
679  */
680
681 gboolean
682 gst_avi_demux_stream_init (GstAviDemux *avi)
683 {
684   GstRiffRead *riff = GST_RIFF_READ (avi);
685   guint32 doctype;
686
687   if (!gst_riff_read_header (riff, &doctype))
688     return FALSE;
689   if (doctype != GST_RIFF_RIFF_AVI) {
690     GST_ELEMENT_ERROR (avi, STREAM, WRONG_TYPE, (NULL), (NULL));
691     return FALSE;
692   }
693
694   return TRUE;
695 }
696
697 /*
698  * Read 'avih' header.
699  */
700
701 gboolean
702 gst_avi_demux_stream_avih (GstAviDemux *avi,
703                            guint32     *flags,
704                            guint32     *streams)
705 {
706   GstRiffRead *riff = GST_RIFF_READ (avi);
707   guint32 tag;
708   GstBuffer *buf;
709   gst_riff_avih avih, *_avih;
710
711   if (!gst_riff_read_data (riff, &tag, &buf))
712     return FALSE;
713
714   if (tag != GST_RIFF_TAG_avih) {
715     g_warning ("Not a avih chunk");
716     gst_buffer_unref (buf);
717     return FALSE;
718   }
719   if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_avih)) {
720     g_warning ("Too small avih (%d available, %d needed)",
721                GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_avih));
722     gst_buffer_unref (buf);
723     return FALSE;
724   }
725
726   _avih = (gst_riff_avih *) GST_BUFFER_DATA (buf);
727   avih.us_frame    = GUINT32_FROM_LE (_avih->us_frame);
728   avih.max_bps     = GUINT32_FROM_LE (_avih->max_bps);
729   avih.pad_gran    = GUINT32_FROM_LE (_avih->pad_gran);
730   avih.flags       = GUINT32_FROM_LE (_avih->flags);
731   avih.tot_frames  = GUINT32_FROM_LE (_avih->tot_frames);
732   avih.init_frames = GUINT32_FROM_LE (_avih->init_frames);
733   avih.streams     = GUINT32_FROM_LE (_avih->streams);
734   avih.bufsize     = GUINT32_FROM_LE (_avih->bufsize);
735   avih.width       = GUINT32_FROM_LE (_avih->width);
736   avih.height      = GUINT32_FROM_LE (_avih->height);
737   avih.scale       = GUINT32_FROM_LE (_avih->scale);
738   avih.rate        = GUINT32_FROM_LE (_avih->rate);
739   avih.start       = GUINT32_FROM_LE (_avih->start);
740   avih.length      = GUINT32_FROM_LE (_avih->length);
741
742   /* debug stuff */
743   GST_INFO ("avih tag found:");
744   GST_INFO (" us_frame    %u",     avih.us_frame);
745   GST_INFO (" max_bps     %u",     avih.max_bps);
746   GST_INFO (" pad_gran    %u",     avih.pad_gran);
747   GST_INFO (" flags       0x%08x", avih.flags);
748   GST_INFO (" tot_frames  %u",     avih.tot_frames);
749   GST_INFO (" init_frames %u",     avih.init_frames);
750   GST_INFO (" streams     %u",     avih.streams);
751   GST_INFO (" bufsize     %u",     avih.bufsize);
752   GST_INFO (" width       %u",     avih.width);
753   GST_INFO (" height      %u",     avih.height);
754   GST_INFO (" scale       %u",     avih.scale);
755   GST_INFO (" rate        %u",     avih.rate);
756   GST_INFO (" start       %u",     avih.start);
757   GST_INFO (" length      %u",     avih.length);
758
759   avi->num_frames = avih.tot_frames;
760   avi->us_per_frame = avih.us_frame;
761   *streams = avih.streams;
762   *flags = avih.flags;
763
764   gst_buffer_unref (buf);
765
766   return TRUE;
767 }
768
769 /*
770  * Add a stream.
771  */
772
773 static gboolean
774 gst_avi_demux_add_stream (GstAviDemux *avi)
775 {
776   GstElementClass *klass = GST_ELEMENT_GET_CLASS (avi);
777   GstRiffRead *riff = GST_RIFF_READ (avi);
778   guint32 tag;
779   gst_riff_strh *strh;
780   gchar *name = NULL, *padname = NULL;
781   GstCaps *caps = NULL;
782   GstPadTemplate *templ = NULL;
783   GstPad *pad;
784   avi_stream_context *stream;
785   union {
786     gst_riff_strf_vids *vids;
787     gst_riff_strf_auds *auds;
788     gst_riff_strf_iavs *iavs;
789   } strf;
790
791   /* the stream starts with a 'strh' header */
792   if (!(tag = gst_riff_peek_tag (riff, NULL)))
793     return FALSE;
794   if (tag != GST_RIFF_TAG_strh) {
795     g_warning ("Invalid stream header (no strh at begin)");
796     goto skip_stream;
797   }
798   if (!gst_riff_read_strh (riff, &strh))
799     return FALSE;
800
801   /* then comes a 'strf' of that specific type */
802   if (!(tag = gst_riff_peek_tag (riff, NULL)))
803     return FALSE;
804   if (tag != GST_RIFF_TAG_strf) {
805     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
806                        ("Invalid AVI header (no strf as second tag)"));
807     goto skip_stream;
808   }
809   switch (strh->type) {
810     case GST_RIFF_FCC_vids:
811       if (!gst_riff_read_strf_vids (riff, &strf.vids))
812         return FALSE;
813       break;
814     case GST_RIFF_FCC_auds:
815       if (!gst_riff_read_strf_auds (riff, &strf.auds))
816         return FALSE;
817       break;
818     case GST_RIFF_FCC_iavs:
819       if (!gst_riff_read_strf_iavs (riff, &strf.iavs))
820         return FALSE;
821       break;
822     default:
823       g_warning ("Unknown stream type " GST_FOURCC_FORMAT,
824                  GST_FOURCC_ARGS (strh->type));
825       goto skip_stream;
826   }
827
828   /* read other things */
829   while (TRUE) {
830     if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
831       return FALSE;
832     else if (avi->level_up) {
833       avi->level_up--;
834       break;
835     }
836
837     switch (tag) {
838       case GST_RIFF_TAG_strn:
839         if (name)
840           g_free (name);
841         if (!gst_riff_read_ascii (riff, &tag, &name))
842           return FALSE;
843         break;
844
845       default:
846         GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
847                      GST_FOURCC_ARGS (tag));
848         /* fall-through */
849
850       case GST_RIFF_TAG_strd: /* what is this? */
851       case GST_RIFF_TAG_JUNK:
852         if (!gst_riff_read_skip (riff))
853           return FALSE;
854         break;
855     }
856
857     if (avi->level_up) {
858       avi->level_up--;
859       break;
860     }
861   }
862
863   /* create stream name + pad */
864   switch (strh->type) {
865     case GST_RIFF_FCC_vids:
866     {
867       char *codec_name = NULL;
868       GstTagList *list = gst_tag_list_new ();
869       padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
870       templ = gst_element_class_get_pad_template (klass, "video_%02d");
871       caps = gst_riff_create_video_caps (strf.vids->compression, strh,
872                                          strf.vids, &codec_name);
873       gst_tag_list_add (list, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
874                         codec_name, NULL);
875       gst_element_found_tags (GST_ELEMENT (avi), list);
876       gst_tag_list_free (list);
877       if (codec_name) g_free (codec_name);
878       g_free (strf.vids);
879       avi->num_v_streams++;
880       break;
881     }
882     case GST_RIFF_FCC_auds:
883     {
884       char *codec_name = NULL;
885       GstTagList *list = gst_tag_list_new ();
886       padname = g_strdup_printf ("audio_%02d", avi->num_a_streams);
887       templ = gst_element_class_get_pad_template (klass, "audio_%02d");
888       caps = gst_riff_create_audio_caps (strf.auds->format, strh, strf.auds,
889                                          &codec_name);
890       gst_tag_list_add (list, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
891                         codec_name, NULL);
892       gst_element_found_tags (GST_ELEMENT (avi), list);
893       gst_tag_list_free (list);
894       if (codec_name) g_free (codec_name);
895       g_free (strf.auds);
896       avi->num_a_streams++;
897       break;
898     }
899     case GST_RIFF_FCC_iavs:
900     {
901       char *codec_name = NULL;
902       GstTagList *list = gst_tag_list_new ();
903       padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
904       templ = gst_element_class_get_pad_template (klass, "video_%02d");
905       caps = gst_riff_create_iavs_caps (strh->fcc_handler, strh, strf.iavs,
906                                         &codec_name);
907       gst_tag_list_add (list, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
908                         codec_name, NULL);
909       gst_element_found_tags (GST_ELEMENT (avi), list);
910       gst_tag_list_free (list);
911       if (codec_name) g_free (codec_name);
912       g_free (strf.iavs);
913       avi->num_v_streams++;
914       break;
915     }
916     default:
917       g_assert (0);
918   }
919
920   /* set proper settings and add it */
921   pad =  gst_pad_new_from_template (templ, padname);
922   g_free (padname);
923
924   gst_pad_set_formats_function (pad, gst_avi_demux_get_src_formats);
925   gst_pad_set_event_mask_function (pad, gst_avi_demux_get_event_mask);
926   gst_pad_set_event_function (pad, gst_avi_demux_handle_src_event);
927   gst_pad_set_query_type_function (pad, gst_avi_demux_get_src_query_types);
928   gst_pad_set_query_function (pad, gst_avi_demux_handle_src_query);
929   gst_pad_set_convert_function (pad, gst_avi_demux_src_convert);
930   gst_pad_set_getcaps_function (pad, gst_avi_demux_src_getcaps);
931
932   stream = &avi->stream[avi->num_streams];
933   stream->caps = caps ? caps : gst_caps_new_empty ();
934   stream->pad = pad;
935   stream->strh = strh;
936   stream->num = avi->num_streams;
937   stream->delay = 0LL;
938   stream->total_bytes = 0LL;
939   stream->total_frames = 0;
940   stream->current_frame = 0;
941   stream->current_byte = 0;
942   stream->current_entry = -1;
943   stream->skip = 0;
944   gst_pad_set_element_private (pad, stream);
945   avi->num_streams++;
946
947   /* auto-negotiates */
948   gst_element_add_pad (GST_ELEMENT (avi), pad);
949
950   return TRUE;
951
952 skip_stream:
953   while (TRUE) {
954     if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
955       return FALSE;
956     if (avi->level_up) {
957       avi->level_up--;
958       break;
959     }
960     if (!gst_riff_read_skip (riff))
961       return FALSE;
962   }
963
964   /* add a "NULL" stream */
965   avi->num_streams++;
966
967   return TRUE; /* recoverable */
968 }
969
970 /*
971  * Read an openDML-2.0 extension header.
972  */
973
974 static gboolean
975 gst_avi_demux_stream_odml (GstAviDemux *avi)
976 {
977   GstRiffRead *riff = GST_RIFF_READ (avi);
978   guint32 tag;
979
980   /* read contents */
981   while (TRUE) {
982     if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
983       return FALSE;
984     else if (avi->level_up) {
985       avi->level_up--;
986       break;
987     }
988
989     switch (tag) {
990       case GST_RIFF_TAG_dmlh: {
991         gst_riff_dmlh dmlh, *_dmlh;
992         GstBuffer *buf;
993
994         if (!gst_riff_read_data (riff, &tag, &buf))
995           return FALSE;
996         if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_dmlh)) {
997           g_warning ("DMLH entry is too small (%d bytes, %d needed)",
998                      GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_dmlh));
999           gst_buffer_unref (buf);
1000           break;
1001         }
1002         _dmlh = (gst_riff_dmlh *) GST_BUFFER_DATA (buf);
1003         dmlh.totalframes = GUINT32_FROM_LE (_dmlh->totalframes);
1004
1005         GST_INFO ("dmlh tag found:");
1006         GST_INFO (" totalframes: %u", dmlh.totalframes);
1007
1008         avi->num_frames = dmlh.totalframes;
1009         gst_buffer_unref (buf);
1010         break;
1011       }
1012
1013       default:
1014         GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
1015                      GST_FOURCC_ARGS (tag));
1016         /* fall-through */
1017
1018       case GST_RIFF_TAG_JUNK:
1019         if (!gst_riff_read_skip (riff))
1020           return FALSE;
1021         break;
1022     }
1023
1024     if (avi->level_up) {
1025       avi->level_up--;
1026       break;
1027     }
1028   }
1029
1030   return TRUE;
1031 }
1032
1033 /*
1034  * Seek to index, read it, seek back.
1035  */
1036
1037 gboolean
1038 gst_avi_demux_stream_index (GstAviDemux *avi)
1039 {
1040   GstBuffer *buf = NULL;
1041   guint i;
1042   GstEvent *event;
1043   GstRiffRead *riff = GST_RIFF_READ (avi);
1044   guint64 pos_before, pos_after, length;
1045   guint32 tag;
1046
1047   /* first, we need to know the current position (to seek back
1048    * when we're done) and the total length of the file. */
1049   length = gst_bytestream_length (riff->bs);
1050   pos_before = gst_bytestream_tell (riff->bs);
1051
1052   /* skip movi */
1053   if (!gst_riff_read_skip (riff))
1054     return FALSE;
1055
1056   /* assure that we've got data left */
1057   pos_after = gst_bytestream_tell (riff->bs);
1058   if (pos_after + 8 > length) {
1059     g_warning ("File said that it has an index, but there is no index data!");
1060     goto end;
1061   }
1062
1063   /* assure that it's an index */
1064   if (!(tag = gst_riff_peek_tag (riff, NULL)))
1065     return FALSE;
1066   if (tag != GST_RIFF_TAG_idx1) {
1067     g_warning ("No index after data, but " GST_FOURCC_FORMAT,
1068                GST_FOURCC_ARGS (tag));
1069     goto end;
1070   }
1071
1072   /* read index */
1073   if (!gst_riff_read_data (riff, &tag, &buf))
1074     return FALSE;
1075
1076   /* parse all entries */
1077   avi->index_size = GST_BUFFER_SIZE (buf) / sizeof (gst_riff_index_entry);
1078   avi->index_entries = g_malloc (avi->index_size * sizeof (gst_avi_index_entry));
1079   GST_INFO ("%u index entries", avi->index_size);
1080
1081   for (i = 0; i < avi->index_size; i++) {
1082     gst_riff_index_entry entry, *_entry;
1083     avi_stream_context *stream;
1084     gint stream_nr;
1085     gst_avi_index_entry *target;
1086     GstFormat format;
1087
1088     _entry = &((gst_riff_index_entry *) GST_BUFFER_DATA (buf))[i];
1089     entry.id     = GUINT32_FROM_LE (_entry->id);
1090     entry.offset = GUINT32_FROM_LE (_entry->offset);
1091     entry.flags  = GUINT32_FROM_LE (_entry->flags);
1092     entry.size   = GUINT32_FROM_LE (_entry->size);
1093     target = &avi->index_entries[i];
1094
1095     stream_nr = CHUNKID_TO_STREAMNR (entry.id);
1096     if (stream_nr >= avi->num_streams || stream_nr < 0) {
1097       g_warning ("Index entry %d has invalid stream nr %d",
1098                  i, stream_nr);
1099       target->stream_nr = -1;
1100       continue;
1101     }
1102     target->stream_nr = stream_nr;
1103     stream = &avi->stream[stream_nr];
1104
1105     target->index_nr = i;
1106     target->flags    = entry.flags;
1107     target->size     = entry.size;
1108     target->offset   = entry.offset;
1109
1110     /* figure out if the index is 0 based or relative to the MOVI start */
1111     if (i == 0) {
1112       if (target->offset < pos_before)
1113         avi->index_offset = pos_before + 8;
1114       else
1115         avi->index_offset = 0;
1116     }
1117
1118     target->bytes_before = stream->total_bytes;
1119     target->frames_before = stream->total_frames;
1120
1121     format = GST_FORMAT_TIME;
1122     if (stream->strh->type == GST_RIFF_FCC_auds) {
1123       /* all audio frames are keyframes */
1124       target->flags |= GST_RIFF_IF_KEYFRAME;
1125     }
1126       
1127     if (stream->strh->samplesize && stream->strh->type == GST_RIFF_FCC_auds) {
1128       /* constant rate stream */
1129       gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
1130                        stream->total_bytes, &format, &target->ts);
1131     } else {
1132       /* VBR stream */
1133       gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
1134                        stream->total_frames, &format, &target->ts);
1135     }
1136
1137     stream->total_bytes += target->size;
1138     stream->total_frames++;
1139   }
1140
1141   /* debug our indexes */
1142   for (i = 0; i < avi->num_streams; i++) {
1143     avi_stream_context *stream;
1144
1145     stream = &avi->stream[i];
1146     GST_DEBUG ("stream %u: %u frames, %" G_GINT64_FORMAT " bytes", 
1147                i, stream->total_frames, stream->total_bytes);
1148   }
1149
1150 end:
1151   if (buf)
1152     gst_buffer_unref (buf);
1153
1154   /* seek back to the data */
1155   if (!(event = gst_riff_read_seek (riff, pos_before)))
1156     return FALSE;
1157   gst_event_unref (event);
1158
1159   return TRUE;
1160 }
1161
1162 /*
1163  * Scan the file for all chunks to "create" a new index.
1164  */
1165
1166 gboolean
1167 gst_avi_demux_stream_scan (GstAviDemux *avi)
1168 {
1169   //GstRiffRead *riff = GST_RIFF_READ (avi);
1170
1171   /* FIXME */
1172
1173   return TRUE;
1174 }
1175
1176 /*
1177  * Read full AVI headers.
1178  */
1179
1180 gboolean
1181 gst_avi_demux_stream_header (GstAviDemux *avi)
1182 {
1183   GstRiffRead *riff = GST_RIFF_READ (avi);
1184   guint32 tag, flags, streams;
1185
1186   /* the header consists of a 'hdrl' LIST tag */
1187   if (!(tag = gst_riff_peek_tag (riff, NULL)))
1188     return FALSE;
1189   if (tag != GST_RIFF_TAG_LIST) {
1190     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1191                        ("Invalid AVI header (no LIST at start): "
1192                        GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1193     return FALSE;
1194   }
1195   if (!gst_riff_read_list (riff, &tag))
1196     return FALSE;
1197   if (tag != GST_RIFF_LIST_hdrl) {
1198     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1199                        ("Invalid AVI header (no hdrl at start): "
1200                        GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1201     return FALSE;
1202   }
1203
1204   /* the hdrl starts with a 'avih' header */
1205   if (!(tag = gst_riff_peek_tag (riff, NULL)))
1206     return FALSE;
1207   if (tag != GST_RIFF_TAG_avih) {
1208     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1209                        ("Invalid AVI header (no avih at start): "
1210                        GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1211     return FALSE;
1212   }
1213   if (!gst_avi_demux_stream_avih (avi, &flags, &streams))
1214     return FALSE;
1215
1216   /* now, read the elements from the header until the end */
1217   while (TRUE) {
1218     if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
1219       return FALSE;
1220     else if (avi->level_up) {
1221       avi->level_up--;
1222       break;
1223     }
1224
1225     switch (tag) {
1226       case GST_RIFF_TAG_LIST:
1227         if (!(tag = gst_riff_peek_list (riff)))
1228           return FALSE;
1229
1230         switch (tag) {
1231           case GST_RIFF_LIST_strl:
1232             if (!gst_riff_read_list (riff, &tag) ||
1233                 !gst_avi_demux_add_stream (avi))
1234               return FALSE;
1235             break;
1236
1237           case GST_RIFF_LIST_odml:
1238             if (!gst_riff_read_list (riff, &tag) ||
1239                 !gst_avi_demux_stream_odml (avi))
1240               return FALSE;
1241             break;
1242
1243           default:
1244             GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " in AVI header",
1245                          GST_FOURCC_ARGS (tag));
1246             /* fall-through */
1247
1248           case GST_RIFF_TAG_JUNK:
1249             if (!gst_riff_read_skip (riff))
1250               return FALSE;
1251             break;
1252         }
1253
1254         break;
1255
1256       default:
1257         GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
1258                      GST_FOURCC_ARGS (tag));
1259         /* fall-through */
1260
1261       case GST_RIFF_TAG_JUNK:
1262         if (!gst_riff_read_skip (riff))
1263           return FALSE;
1264         break;
1265     }
1266
1267     if (avi->level_up) {
1268       avi->level_up--;
1269       break;
1270     }
1271   }
1272
1273   if (avi->num_streams != streams) {
1274     g_warning ("Stream header mentioned %d streams, but %d available",
1275                streams, avi->num_streams);
1276   }
1277
1278   /* we've got streaminfo now */
1279   g_object_notify (G_OBJECT(avi), "streaminfo");
1280
1281   /* Now, find the data (i.e. skip all junk between header and data) */
1282   while (1) {
1283     if (!(tag = gst_riff_peek_tag (riff, NULL)))
1284       return FALSE;
1285     if (tag != GST_RIFF_TAG_LIST) {
1286       if (!gst_riff_read_skip (riff))
1287         return FALSE;
1288       continue;
1289     }
1290     if (!(tag = gst_riff_peek_list (riff)))
1291       return FALSE;
1292     if (tag != GST_RIFF_LIST_movi) {
1293       if (tag == GST_RIFF_LIST_INFO) {
1294         if (!gst_riff_read_list (riff, &tag) ||
1295             !gst_riff_read_info (riff))
1296          return FALSE;
1297       } else  if (!gst_riff_read_skip (riff)) {
1298         return FALSE;
1299       }
1300       continue;
1301     }
1302     break;
1303   }
1304
1305   /* create or read stream index (for seeking) */
1306   if (flags & GST_RIFF_AVIH_HASINDEX) {
1307     if (!gst_avi_demux_stream_index (avi))
1308       return FALSE;
1309   } else {
1310     if (!gst_avi_demux_stream_scan (avi))
1311       return FALSE;
1312   }
1313
1314   return TRUE;
1315 }
1316
1317 /*
1318  * Handle seek.
1319  */
1320
1321 static gboolean
1322 gst_avi_demux_handle_seek (GstAviDemux *avi)
1323 {
1324   GstRiffRead *riff = GST_RIFF_READ (avi);
1325   guint i;
1326   GstEvent *event;
1327
1328   /* FIXME: if we seek in an openDML file, we will have multiple
1329    * primary levels. Seeking in between those will cause havoc. */
1330
1331   if (!(event = gst_riff_read_seek (riff, avi->seek_offset)))
1332     return FALSE;
1333   gst_event_unref (event);
1334
1335   for (i = 0; i < avi->num_streams; i++) {
1336     avi_stream_context *stream = &avi->stream[i];
1337
1338     if (GST_PAD_IS_USABLE (stream->pad)) {
1339       event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, 
1340                                 avi->last_seek + stream->delay , NULL);
1341       gst_pad_push (stream->pad, GST_DATA (event));
1342     }
1343   }
1344
1345   return TRUE;
1346 }
1347
1348 /*
1349  * Read data.
1350  */
1351
1352 gboolean
1353 gst_avi_demux_stream_data (GstAviDemux *avi)
1354 {
1355   GstRiffRead *riff = GST_RIFF_READ (avi);
1356   guint32 tag;
1357   guint stream_nr;
1358   gst_avi_index_entry *entry;
1359
1360   if (avi->seek_offset != (guint64) -1) {
1361     if (!gst_avi_demux_handle_seek (avi))
1362       return FALSE;
1363     avi->seek_offset = (guint64) -1;
1364   }
1365
1366   /* peek first (for the end of this 'list/movi' section) */
1367   if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
1368     return FALSE;
1369
1370   /* if we're at top-level, we didn't read the 'movi'
1371    * list tag yet. This can also be 'AVIX' in case of
1372    * openDML-2.0 AVI files. Lastly, it might be idx1,
1373    * in which case we skip it so we come at EOS. */
1374   while (g_list_length (riff->level) < 2) {
1375     if (!(tag = gst_riff_peek_tag (riff, NULL)))
1376       return FALSE;
1377
1378     switch (tag) {
1379       case GST_RIFF_TAG_LIST:
1380         if (!(tag = gst_riff_peek_list (riff)))
1381           return FALSE;
1382
1383         switch (tag) {
1384           case GST_RIFF_LIST_AVIX:
1385           case GST_RIFF_LIST_movi:
1386             if (!gst_riff_read_list (riff, &tag))
1387               return FALSE;
1388             /* we're now going to read buffers! */
1389             break;
1390
1391           default:
1392             GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " before AVI data",
1393                          GST_FOURCC_ARGS (tag));
1394             /* fall-through */
1395
1396           case GST_RIFF_TAG_JUNK:
1397             if (!gst_riff_read_skip (riff))
1398               return FALSE;
1399             break;
1400         }
1401
1402         break;
1403
1404       default:
1405         GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " before AVI data",
1406                      GST_FOURCC_ARGS (tag));
1407         /* fall-through */
1408
1409       case GST_RIFF_TAG_idx1:
1410       case GST_RIFF_TAG_JUNK:
1411         if (!gst_riff_read_skip (riff))
1412           return FALSE;
1413         break;
1414     }
1415   }
1416
1417   /* And then, we get the data */
1418   if (!(tag = gst_riff_peek_tag (riff, NULL)))
1419     return FALSE;
1420   stream_nr = CHUNKID_TO_STREAMNR (tag);
1421   if (stream_nr < 0 || stream_nr >= avi->num_streams) {
1422     /* recoverable */
1423     g_warning ("Invalid stream ID %d (" GST_FOURCC_FORMAT ")",
1424                stream_nr, GST_FOURCC_ARGS (tag));
1425     if (!gst_riff_read_skip (riff))
1426       return FALSE;
1427   } else {
1428     avi_stream_context *stream;
1429     GstClockTime next_ts;
1430     GstFormat format;
1431     GstBuffer *buf;
1432
1433     /* get buffer */
1434     if (!gst_riff_read_data (riff, &tag, &buf))
1435       return FALSE;
1436
1437     /* get time of this buffer */
1438     stream = &avi->stream[stream_nr];
1439     entry = gst_avi_demux_index_next (avi, stream_nr,
1440                                       stream->current_entry + 1, 0);
1441     if (entry) {
1442       stream->current_entry = entry->index_nr;
1443       if (entry->flags & GST_RIFF_IF_KEYFRAME) {
1444         GST_BUFFER_FLAG_SET (buf, GST_BUFFER_KEY_UNIT);
1445       }
1446     }
1447     format = GST_FORMAT_TIME;
1448     gst_pad_query (stream->pad, GST_QUERY_POSITION,
1449                    &format, &next_ts);
1450
1451     /* set delay (if any) */
1452     if (stream->strh->init_frames == stream->current_frame &&
1453         stream->delay == 0)
1454       stream->delay = next_ts;
1455
1456     stream->current_frame++;
1457     stream->current_byte += GST_BUFFER_SIZE (buf);
1458
1459     /* should we skip this data? */
1460     if (stream->skip) {
1461       stream->skip--;
1462       gst_buffer_unref (buf);
1463     } else {
1464       if (!stream->pad || !GST_PAD_IS_USABLE (stream->pad)) {
1465         gst_buffer_unref (buf);
1466       } else {
1467         GstClockTime dur_ts;
1468
1469         GST_BUFFER_TIMESTAMP (buf) = next_ts;
1470         gst_pad_query (stream->pad, GST_QUERY_POSITION,
1471                        &format, &dur_ts);
1472         GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
1473
1474         gst_pad_push (stream->pad, GST_DATA (buf));
1475       }
1476     }
1477   }
1478
1479   return TRUE;
1480 }
1481
1482 static void
1483 gst_avi_demux_loop (GstElement *element)
1484 {
1485   GstAviDemux *avi = GST_AVI_DEMUX (element);
1486
1487   switch (avi->state) {
1488     case GST_AVI_DEMUX_START:
1489       if (!gst_avi_demux_stream_init (avi))
1490         return;
1491       avi->state = GST_AVI_DEMUX_HEADER;
1492       /* fall-through */
1493
1494     case GST_AVI_DEMUX_HEADER:
1495       if (!gst_avi_demux_stream_header (avi))
1496         return;
1497       avi->state = GST_AVI_DEMUX_MOVI;
1498       /* fall-through */
1499
1500     case GST_AVI_DEMUX_MOVI:
1501       if (!gst_avi_demux_stream_data (avi))
1502         return;
1503       break;
1504
1505     default:
1506       g_assert (0);
1507   }
1508 }
1509
1510 static GstElementStateReturn
1511 gst_avi_demux_change_state (GstElement *element)
1512 {
1513   GstAviDemux *avi = GST_AVI_DEMUX (element);
1514
1515   switch (GST_STATE_TRANSITION (element)) {
1516     case GST_STATE_READY_TO_PAUSED:
1517       gst_avi_demux_streaminfo (avi);
1518       break;
1519     case GST_STATE_PAUSED_TO_READY:
1520       gst_avi_demux_reset (avi);
1521       break;
1522     default:
1523       break;
1524   }
1525
1526   if (GST_ELEMENT_CLASS (parent_class)->change_state)
1527     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1528
1529   return GST_STATE_SUCCESS;
1530 }
1531
1532 static void
1533 gst_avi_demux_get_property (GObject    *object,
1534                             guint       prop_id,
1535                             GValue     *value,
1536                             GParamSpec *pspec)
1537 {
1538   GstAviDemux *avi = GST_AVI_DEMUX (object);
1539
1540   switch (prop_id) {
1541     case ARG_STREAMINFO:
1542       g_value_set_boxed (value, avi->streaminfo);
1543       break;
1544     default:
1545       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1546       break;
1547   }
1548 }