change NULL to (NULL) for GST_ELEMENT_ERROR
[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), 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       padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
867       templ = gst_element_class_get_pad_template (klass, "video_%02d");
868       caps = gst_riff_create_video_caps (strf.vids->compression, strh, strf.vids);
869       g_free (strf.vids);
870       avi->num_v_streams++;
871       break;
872     case GST_RIFF_FCC_auds:
873       padname = g_strdup_printf ("audio_%02d", avi->num_a_streams);
874       templ = gst_element_class_get_pad_template (klass, "audio_%02d");
875       caps = gst_riff_create_audio_caps (strf.auds->format, strh, strf.auds);
876       g_free (strf.auds);
877       avi->num_a_streams++;
878       break;
879     case GST_RIFF_FCC_iavs:
880       padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
881       templ = gst_element_class_get_pad_template (klass, "video_%02d");
882       caps = gst_riff_create_iavs_caps (strh->fcc_handler, strh, strf.iavs);
883       g_free (strf.iavs);
884       avi->num_v_streams++;
885       break;
886     default:
887       g_assert (0);
888   }
889
890   /* set proper settings and add it */
891   pad =  gst_pad_new_from_template (templ, padname);
892   g_free (padname);
893
894   gst_pad_set_formats_function (pad, gst_avi_demux_get_src_formats);
895   gst_pad_set_event_mask_function (pad, gst_avi_demux_get_event_mask);
896   gst_pad_set_event_function (pad, gst_avi_demux_handle_src_event);
897   gst_pad_set_query_type_function (pad, gst_avi_demux_get_src_query_types);
898   gst_pad_set_query_function (pad, gst_avi_demux_handle_src_query);
899   gst_pad_set_convert_function (pad, gst_avi_demux_src_convert);
900   gst_pad_set_getcaps_function (pad, gst_avi_demux_src_getcaps);
901
902   stream = &avi->stream[avi->num_streams];
903   stream->caps = caps ? caps : gst_caps_new_empty ();
904   stream->pad = pad;
905   stream->strh = strh;
906   stream->num = avi->num_streams;
907   stream->delay = 0LL;
908   stream->total_bytes = 0LL;
909   stream->total_frames = 0;
910   stream->current_frame = 0;
911   stream->current_byte = 0;
912   stream->current_entry = -1;
913   stream->skip = 0;
914   gst_pad_set_element_private (pad, stream);
915   avi->num_streams++;
916
917   /* auto-negotiates */
918   gst_element_add_pad (GST_ELEMENT (avi), pad);
919
920   return TRUE;
921
922 skip_stream:
923   while (TRUE) {
924     if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
925       return FALSE;
926     if (avi->level_up) {
927       avi->level_up--;
928       break;
929     }
930     if (!gst_riff_read_skip (riff))
931       return FALSE;
932   }
933
934   /* add a "NULL" stream */
935   avi->num_streams++;
936
937   return TRUE; /* recoverable */
938 }
939
940 /*
941  * Read an openDML-2.0 extension header.
942  */
943
944 static gboolean
945 gst_avi_demux_stream_odml (GstAviDemux *avi)
946 {
947   GstRiffRead *riff = GST_RIFF_READ (avi);
948   guint32 tag;
949
950   /* read contents */
951   while (TRUE) {
952     if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
953       return FALSE;
954     else if (avi->level_up) {
955       avi->level_up--;
956       break;
957     }
958
959     switch (tag) {
960       case GST_RIFF_TAG_dmlh: {
961         gst_riff_dmlh dmlh, *_dmlh;
962         GstBuffer *buf;
963
964         if (!gst_riff_read_data (riff, &tag, &buf))
965           return FALSE;
966         if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_dmlh)) {
967           g_warning ("DMLH entry is too small (%d bytes, %d needed)",
968                      GST_BUFFER_SIZE (buf), sizeof (gst_riff_dmlh));
969           gst_buffer_unref (buf);
970           break;
971         }
972         _dmlh = (gst_riff_dmlh *) GST_BUFFER_DATA (buf);
973         dmlh.totalframes = GUINT32_FROM_LE (_dmlh->totalframes);
974
975         GST_INFO ("dmlh tag found:");
976         GST_INFO (" totalframes: %u", dmlh.totalframes);
977
978         avi->num_frames = dmlh.totalframes;
979         gst_buffer_unref (buf);
980         break;
981       }
982
983       default:
984         GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
985                      GST_FOURCC_ARGS (tag));
986         /* fall-through */
987
988       case GST_RIFF_TAG_JUNK:
989         if (!gst_riff_read_skip (riff))
990           return FALSE;
991         break;
992     }
993
994     if (avi->level_up) {
995       avi->level_up--;
996       break;
997     }
998   }
999
1000   return TRUE;
1001 }
1002
1003 /*
1004  * Seek to index, read it, seek back.
1005  */
1006
1007 gboolean
1008 gst_avi_demux_stream_index (GstAviDemux *avi)
1009 {
1010   GstBuffer *buf = NULL;
1011   guint i;
1012   GstEvent *event;
1013   GstRiffRead *riff = GST_RIFF_READ (avi);
1014   guint64 pos_before, pos_after, length;
1015   guint32 tag;
1016
1017   /* first, we need to know the current position (to seek back
1018    * when we're done) and the total length of the file. */
1019   length = gst_bytestream_length (riff->bs);
1020   pos_before = gst_bytestream_tell (riff->bs);
1021
1022   /* skip movi */
1023   if (!gst_riff_read_skip (riff))
1024     return FALSE;
1025
1026   /* assure that we've got data left */
1027   pos_after = gst_bytestream_tell (riff->bs);
1028   if (pos_after + 8 > length) {
1029     g_warning ("File said that it has an index, but there is no index data!");
1030     goto end;
1031   }
1032
1033   /* assure that it's an index */
1034   if (!(tag = gst_riff_peek_tag (riff, NULL)))
1035     return FALSE;
1036   if (tag != GST_RIFF_TAG_idx1) {
1037     g_warning ("No index after data, but " GST_FOURCC_FORMAT,
1038                GST_FOURCC_ARGS (tag));
1039     goto end;
1040   }
1041
1042   /* read index */
1043   if (!gst_riff_read_data (riff, &tag, &buf))
1044     return FALSE;
1045
1046   /* parse all entries */
1047   avi->index_size = GST_BUFFER_SIZE (buf) / sizeof (gst_riff_index_entry);
1048   avi->index_entries = g_malloc (avi->index_size * sizeof (gst_avi_index_entry));
1049   GST_INFO ("%u index entries", avi->index_size);
1050
1051   for (i = 0; i < avi->index_size; i++) {
1052     gst_riff_index_entry entry, *_entry;
1053     avi_stream_context *stream;
1054     gint stream_nr;
1055     gst_avi_index_entry *target;
1056     GstFormat format;
1057
1058     _entry = &((gst_riff_index_entry *) GST_BUFFER_DATA (buf))[i];
1059     entry.id     = GUINT32_FROM_LE (_entry->id);
1060     entry.offset = GUINT32_FROM_LE (_entry->offset);
1061     entry.flags  = GUINT32_FROM_LE (_entry->flags);
1062     entry.size   = GUINT32_FROM_LE (_entry->size);
1063     target = &avi->index_entries[i];
1064
1065     stream_nr = CHUNKID_TO_STREAMNR (entry.id);
1066     if (stream_nr >= avi->num_streams || stream_nr < 0) {
1067       g_warning ("Index entry %d has invalid stream nr %d",
1068                  i, stream_nr);
1069       target->stream_nr = -1;
1070       continue;
1071     }
1072     target->stream_nr = stream_nr;
1073     stream = &avi->stream[stream_nr];
1074
1075     target->index_nr = i;
1076     target->flags    = entry.flags;
1077     target->size     = entry.size;
1078     target->offset   = entry.offset;
1079
1080     /* figure out if the index is 0 based or relative to the MOVI start */
1081     if (i == 0) {
1082       if (target->offset < pos_before)
1083         avi->index_offset = pos_before + 8;
1084       else
1085         avi->index_offset = 0;
1086     }
1087
1088     target->bytes_before = stream->total_bytes;
1089     target->frames_before = stream->total_frames;
1090
1091     format = GST_FORMAT_TIME;
1092     if (stream->strh->type == GST_RIFF_FCC_auds) {
1093       /* all audio frames are keyframes */
1094       target->flags |= GST_RIFF_IF_KEYFRAME;
1095     }
1096       
1097     if (stream->strh->samplesize && stream->strh->type == GST_RIFF_FCC_auds) {
1098       /* constant rate stream */
1099       gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
1100                        stream->total_bytes, &format, &target->ts);
1101     } else {
1102       /* VBR stream */
1103       gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
1104                        stream->total_frames, &format, &target->ts);
1105     }
1106
1107     stream->total_bytes += target->size;
1108     stream->total_frames++;
1109   }
1110
1111   /* debug our indexes */
1112   for (i = 0; i < avi->num_streams; i++) {
1113     avi_stream_context *stream;
1114
1115     stream = &avi->stream[i];
1116     GST_DEBUG ("stream %u: %u frames, %" G_GINT64_FORMAT " bytes", 
1117                i, stream->total_frames, stream->total_bytes);
1118   }
1119
1120 end:
1121   if (buf)
1122     gst_buffer_unref (buf);
1123
1124   /* seek back to the data */
1125   if (!(event = gst_riff_read_seek (riff, pos_before)))
1126     return FALSE;
1127   gst_event_unref (event);
1128
1129   return TRUE;
1130 }
1131
1132 /*
1133  * Scan the file for all chunks to "create" a new index.
1134  */
1135
1136 gboolean
1137 gst_avi_demux_stream_scan (GstAviDemux *avi)
1138 {
1139   //GstRiffRead *riff = GST_RIFF_READ (avi);
1140
1141   /* FIXME */
1142
1143   return TRUE;
1144 }
1145
1146 /*
1147  * Read full AVI headers.
1148  */
1149
1150 gboolean
1151 gst_avi_demux_stream_header (GstAviDemux *avi)
1152 {
1153   GstRiffRead *riff = GST_RIFF_READ (avi);
1154   guint32 tag, flags, streams;
1155
1156   /* the header consists of a 'hdrl' LIST tag */
1157   if (!(tag = gst_riff_peek_tag (riff, NULL)))
1158     return FALSE;
1159   if (tag != GST_RIFF_TAG_LIST) {
1160     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1161                        ("Invalid AVI header (no LIST at start): "
1162                        GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1163     return FALSE;
1164   }
1165   if (!gst_riff_read_list (riff, &tag))
1166     return FALSE;
1167   if (tag != GST_RIFF_LIST_hdrl) {
1168     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1169                        ("Invalid AVI header (no hdrl at start): "
1170                        GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1171     return FALSE;
1172   }
1173
1174   /* the hdrl starts with a 'avih' header */
1175   if (!(tag = gst_riff_peek_tag (riff, NULL)))
1176     return FALSE;
1177   if (tag != GST_RIFF_TAG_avih) {
1178     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1179                        ("Invalid AVI header (no avih at start): "
1180                        GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1181     return FALSE;
1182   }
1183   if (!gst_avi_demux_stream_avih (avi, &flags, &streams))
1184     return FALSE;
1185
1186   /* now, read the elements from the header until the end */
1187   while (TRUE) {
1188     if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
1189       return FALSE;
1190     else if (avi->level_up) {
1191       avi->level_up--;
1192       break;
1193     }
1194
1195     switch (tag) {
1196       case GST_RIFF_TAG_LIST:
1197         if (!(tag = gst_riff_peek_list (riff)))
1198           return FALSE;
1199
1200         switch (tag) {
1201           case GST_RIFF_LIST_strl:
1202             if (!gst_riff_read_list (riff, &tag) ||
1203                 !gst_avi_demux_add_stream (avi))
1204               return FALSE;
1205             break;
1206
1207           case GST_RIFF_LIST_odml:
1208             if (!gst_riff_read_list (riff, &tag) ||
1209                 !gst_avi_demux_stream_odml (avi))
1210               return FALSE;
1211             break;
1212
1213           default:
1214             GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " in AVI header",
1215                          GST_FOURCC_ARGS (tag));
1216             /* fall-through */
1217
1218           case GST_RIFF_TAG_JUNK:
1219             if (!gst_riff_read_skip (riff))
1220               return FALSE;
1221             break;
1222         }
1223
1224         break;
1225
1226       default:
1227         GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
1228                      GST_FOURCC_ARGS (tag));
1229         /* fall-through */
1230
1231       case GST_RIFF_TAG_JUNK:
1232         if (!gst_riff_read_skip (riff))
1233           return FALSE;
1234         break;
1235     }
1236
1237     if (avi->level_up) {
1238       avi->level_up--;
1239       break;
1240     }
1241   }
1242
1243   if (avi->num_streams != streams) {
1244     g_warning ("Stream header mentioned %d streams, but %d available",
1245                streams, avi->num_streams);
1246   }
1247
1248   /* we've got streaminfo now */
1249   g_object_notify (G_OBJECT(avi), "streaminfo");
1250
1251   /* Now, find the data (i.e. skip all junk between header and data) */
1252   while (1) {
1253     if (!(tag = gst_riff_peek_tag (riff, NULL)))
1254       return FALSE;
1255     if (tag != GST_RIFF_TAG_LIST) {
1256       if (!gst_riff_read_skip (riff))
1257         return FALSE;
1258       continue;
1259     }
1260     if (!(tag = gst_riff_peek_list (riff)))
1261       return FALSE;
1262     if (tag != GST_RIFF_LIST_movi) {
1263       if (tag == GST_RIFF_LIST_INFO) {
1264         if (!gst_riff_read_list (riff, &tag) ||
1265             !gst_riff_read_info (riff))
1266          return FALSE;
1267       } else  if (!gst_riff_read_skip (riff)) {
1268         return FALSE;
1269       }
1270       continue;
1271     }
1272     break;
1273   }
1274
1275   /* create or read stream index (for seeking) */
1276   if (flags & GST_RIFF_AVIH_HASINDEX) {
1277     if (!gst_avi_demux_stream_index (avi))
1278       return FALSE;
1279   } else {
1280     if (!gst_avi_demux_stream_scan (avi))
1281       return FALSE;
1282   }
1283
1284   return TRUE;
1285 }
1286
1287 /*
1288  * Handle seek.
1289  */
1290
1291 static gboolean
1292 gst_avi_demux_handle_seek (GstAviDemux *avi)
1293 {
1294   GstRiffRead *riff = GST_RIFF_READ (avi);
1295   guint i;
1296   GstEvent *event;
1297
1298   /* FIXME: if we seek in an openDML file, we will have multiple
1299    * primary levels. Seeking in between those will cause havoc. */
1300
1301   if (!(event = gst_riff_read_seek (riff, avi->seek_offset)))
1302     return FALSE;
1303   gst_event_unref (event);
1304
1305   for (i = 0; i < avi->num_streams; i++) {
1306     avi_stream_context *stream = &avi->stream[i];
1307
1308     if (GST_PAD_IS_USABLE (stream->pad)) {
1309       event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, 
1310                                 avi->last_seek + stream->delay , NULL);
1311       gst_pad_push (stream->pad, GST_DATA (event));
1312     }
1313   }
1314
1315   return TRUE;
1316 }
1317
1318 /*
1319  * Read data.
1320  */
1321
1322 gboolean
1323 gst_avi_demux_stream_data (GstAviDemux *avi)
1324 {
1325   GstRiffRead *riff = GST_RIFF_READ (avi);
1326   guint32 tag;
1327   guint stream_nr;
1328   gst_avi_index_entry *entry;
1329
1330   if (avi->seek_offset != (guint64) -1) {
1331     if (!gst_avi_demux_handle_seek (avi))
1332       return FALSE;
1333     avi->seek_offset = (guint64) -1;
1334   }
1335
1336   /* peek first (for the end of this 'list/movi' section) */
1337   if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
1338     return FALSE;
1339
1340   /* if we're at top-level, we didn't read the 'movi'
1341    * list tag yet. This can also be 'AVIX' in case of
1342    * openDML-2.0 AVI files. Lastly, it might be idx1,
1343    * in which case we skip it so we come at EOS. */
1344   while (g_list_length (riff->level) < 2) {
1345     if (!(tag = gst_riff_peek_tag (riff, NULL)))
1346       return FALSE;
1347
1348     switch (tag) {
1349       case GST_RIFF_TAG_LIST:
1350         if (!(tag = gst_riff_peek_list (riff)))
1351           return FALSE;
1352
1353         switch (tag) {
1354           case GST_RIFF_LIST_AVIX:
1355           case GST_RIFF_LIST_movi:
1356             if (!gst_riff_read_list (riff, &tag))
1357               return FALSE;
1358             /* we're now going to read buffers! */
1359             break;
1360
1361           default:
1362             GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " before AVI data",
1363                          GST_FOURCC_ARGS (tag));
1364             /* fall-through */
1365
1366           case GST_RIFF_TAG_JUNK:
1367             if (!gst_riff_read_skip (riff))
1368               return FALSE;
1369             break;
1370         }
1371
1372         break;
1373
1374       default:
1375         GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " before AVI data",
1376                      GST_FOURCC_ARGS (tag));
1377         /* fall-through */
1378
1379       case GST_RIFF_TAG_idx1:
1380       case GST_RIFF_TAG_JUNK:
1381         if (!gst_riff_read_skip (riff))
1382           return FALSE;
1383         break;
1384     }
1385   }
1386
1387   /* And then, we get the data */
1388   if (!(tag = gst_riff_peek_tag (riff, NULL)))
1389     return FALSE;
1390   stream_nr = CHUNKID_TO_STREAMNR (tag);
1391   if (stream_nr < 0 || stream_nr >= avi->num_streams) {
1392     /* recoverable */
1393     g_warning ("Invalid stream ID %d (" GST_FOURCC_FORMAT ")",
1394                stream_nr, GST_FOURCC_ARGS (tag));
1395     if (!gst_riff_read_skip (riff))
1396       return FALSE;
1397   } else {
1398     avi_stream_context *stream;
1399     GstClockTime next_ts;
1400     GstFormat format;
1401     GstBuffer *buf;
1402
1403     /* get buffer */
1404     if (!gst_riff_read_data (riff, &tag, &buf))
1405       return FALSE;
1406
1407     /* get time of this buffer */
1408     stream = &avi->stream[stream_nr];
1409     entry = gst_avi_demux_index_next (avi, stream_nr,
1410                                       stream->current_entry + 1, 0);
1411     if (entry) {
1412       stream->current_entry = entry->index_nr;
1413       if (entry->flags & GST_RIFF_IF_KEYFRAME) {
1414         GST_BUFFER_FLAG_SET (buf, GST_BUFFER_KEY_UNIT);
1415       }
1416     }
1417     format = GST_FORMAT_TIME;
1418     gst_pad_query (stream->pad, GST_QUERY_POSITION,
1419                    &format, &next_ts);
1420
1421     /* set delay (if any) */
1422     if (stream->strh->init_frames == stream->current_frame &&
1423         stream->delay == 0)
1424       stream->delay = next_ts;
1425
1426     stream->current_frame++;
1427     stream->current_byte += GST_BUFFER_SIZE (buf);
1428
1429     /* should we skip this data? */
1430     if (stream->skip) {
1431       stream->skip--;
1432       gst_buffer_unref (buf);
1433     } else {
1434       if (!stream->pad || !GST_PAD_IS_USABLE (stream->pad)) {
1435         gst_buffer_unref (buf);
1436       } else {
1437         GstClockTime dur_ts;
1438
1439         GST_BUFFER_TIMESTAMP (buf) = next_ts;
1440         gst_pad_query (stream->pad, GST_QUERY_POSITION,
1441                        &format, &dur_ts);
1442         GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
1443
1444         gst_pad_push (stream->pad, GST_DATA (buf));
1445       }
1446     }
1447   }
1448
1449   return TRUE;
1450 }
1451
1452 static void
1453 gst_avi_demux_loop (GstElement *element)
1454 {
1455   GstAviDemux *avi = GST_AVI_DEMUX (element);
1456
1457   switch (avi->state) {
1458     case GST_AVI_DEMUX_START:
1459       if (!gst_avi_demux_stream_init (avi))
1460         return;
1461       avi->state = GST_AVI_DEMUX_HEADER;
1462       /* fall-through */
1463
1464     case GST_AVI_DEMUX_HEADER:
1465       if (!gst_avi_demux_stream_header (avi))
1466         return;
1467       avi->state = GST_AVI_DEMUX_MOVI;
1468       /* fall-through */
1469
1470     case GST_AVI_DEMUX_MOVI:
1471       if (!gst_avi_demux_stream_data (avi))
1472         return;
1473       break;
1474
1475     default:
1476       g_assert (0);
1477   }
1478 }
1479
1480 static GstElementStateReturn
1481 gst_avi_demux_change_state (GstElement *element)
1482 {
1483   GstAviDemux *avi = GST_AVI_DEMUX (element);
1484
1485   switch (GST_STATE_TRANSITION (element)) {
1486     case GST_STATE_READY_TO_PAUSED:
1487       gst_avi_demux_streaminfo (avi);
1488       break;
1489     case GST_STATE_PAUSED_TO_READY:
1490       gst_avi_demux_reset (avi);
1491       break;
1492     default:
1493       break;
1494   }
1495
1496   if (GST_ELEMENT_CLASS (parent_class)->change_state)
1497     return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1498
1499   return GST_STATE_SUCCESS;
1500 }
1501
1502 static void
1503 gst_avi_demux_get_property (GObject    *object,
1504                             guint       prop_id,
1505                             GValue     *value,
1506                             GParamSpec *pspec)
1507 {
1508   GstAviDemux *avi = GST_AVI_DEMUX (object);
1509
1510   switch (prop_id) {
1511     case ARG_STREAMINFO:
1512       g_value_set_boxed (value, avi->streaminfo);
1513       break;
1514     default:
1515       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1516       break;
1517   }
1518 }