remove copyright field from plugins
[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
20
21 /* #define GST_DEBUG_ENABLED */
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 #include <string.h>
26
27 #include "gstavidemux.h"
28 #include "gstavimux.h"
29
30 GST_DEBUG_CATEGORY_STATIC (avidemux_debug);
31 #define GST_CAT_DEFAULT avidemux_debug
32
33 /* AviDemux signals and args */
34 enum {
35   /* FILL ME */
36   LAST_SIGNAL
37 };
38
39 enum {
40   ARG_0,
41   ARG_BITRATE,
42   ARG_METADATA,
43   ARG_STREAMINFO,
44   /* FILL ME */
45 };
46
47 GST_PAD_TEMPLATE_FACTORY (sink_templ,
48   "sink",
49   GST_PAD_SINK,
50   GST_PAD_ALWAYS,
51   GST_CAPS_NEW (
52     "avidemux_sink",
53     "video/x-msvideo",
54       NULL
55   )
56 );
57
58 static void     gst_avi_demux_base_init         (gpointer g_class);
59 static void     gst_avi_demux_class_init        (GstAviDemuxClass *klass);
60 static void     gst_avi_demux_init              (GstAviDemux *avi_demux);
61
62 static void     gst_avi_demux_loop              (GstElement  *element);
63
64 static gboolean gst_avi_demux_send_event        (GstElement  *element,
65                                                  GstEvent    *event);
66
67 static const GstEventMask *
68                 gst_avi_demux_get_event_mask    (GstPad      *pad);
69 static gboolean gst_avi_demux_handle_src_event  (GstPad      *pad,
70                                                  GstEvent    *event);
71 static const GstFormat *
72                 gst_avi_demux_get_src_formats   (GstPad      *pad); 
73 static const GstQueryType *
74                 gst_avi_demux_get_src_query_types (GstPad    *pad);
75 static gboolean gst_avi_demux_handle_src_query  (GstPad      *pad,
76                                                  GstQueryType type, 
77                                                  GstFormat   *format,
78                                                  gint64      *value);
79 static gboolean gst_avi_demux_src_convert       (GstPad      *pad,
80                                                  GstFormat    src_format,
81                                                  gint64       src_value,
82                                                  GstFormat   *dest_format,
83                                                  gint64      *dest_value);
84
85 static GstElementStateReturn
86                 gst_avi_demux_change_state      (GstElement  *element);
87
88 static void     gst_avi_demux_get_property      (GObject     *object,
89                                                  guint        prop_id,  
90                                                  GValue      *value,
91                                                  GParamSpec  *pspec);
92
93 static GstCaps * gst_avi_demux_audio_caps (guint16 codec_id,
94     gst_riff_strf_auds *strf, GstAviDemux *avi_demux);
95 static GstCaps * gst_avi_demux_video_caps (guint32 codec_fcc,
96     gst_riff_strh *strh, gst_riff_strf_vids *strf,
97     GstAviDemux *avi_demux);
98 static GstCaps * gst_avi_demux_iavs_caps (void);
99
100 static GstPadTemplate *videosrctempl, *audiosrctempl;
101 static GstElementClass *parent_class = NULL;
102 /*static guint gst_avi_demux_signals[LAST_SIGNAL] = { 0 }; */
103
104 GType
105 gst_avi_demux_get_type(void) 
106 {
107   static GType avi_demux_type = 0;
108
109   if (!avi_demux_type) {
110     static const GTypeInfo avi_demux_info = {
111       sizeof(GstAviDemuxClass),      
112       gst_avi_demux_base_init,
113       NULL,
114       (GClassInitFunc)gst_avi_demux_class_init,
115       NULL,
116       NULL,
117       sizeof(GstAviDemux),
118       0,
119       (GInstanceInitFunc)gst_avi_demux_init,
120     };
121     avi_demux_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviDemux", &avi_demux_info, 0);
122   }
123   return avi_demux_type;
124 }
125
126 static void
127 gst_avi_demux_base_init (gpointer g_class)
128 {
129   static GstElementDetails gst_avi_demux_details = GST_ELEMENT_DETAILS (
130     "Avi demuxer",
131     "Codec/Demuxer",
132     "Demultiplex an avi file into audio and video",
133     "Erik Walthinsen <omega@cse.ogi.edu>\n"
134     "Wim Taymans <wim.taymans@chello.be>"
135   );
136   static guint32 vid_list[] = {
137     GST_MAKE_FOURCC('I','4','2','0'),
138     GST_MAKE_FOURCC('Y','U','Y','2'),
139     GST_MAKE_FOURCC('M','J','P','G'),
140     GST_MAKE_FOURCC('D','V','S','D'),
141     GST_MAKE_FOURCC('W','M','V','1'),
142     GST_MAKE_FOURCC('W','M','V','2'),
143     GST_MAKE_FOURCC('M','P','G','4'),
144     GST_MAKE_FOURCC('M','P','4','2'),
145     GST_MAKE_FOURCC('M','P','4','3'),
146     GST_MAKE_FOURCC('H','F','Y','U'),
147     GST_MAKE_FOURCC('D','I','V','3'),
148     GST_MAKE_FOURCC('M','P','E','G'),
149     GST_MAKE_FOURCC('H','2','6','3'),
150     GST_MAKE_FOURCC('D','I','V','X'),
151     GST_MAKE_FOURCC('X','V','I','D'),
152     GST_MAKE_FOURCC('3','I','V','1'),
153     0 /* end */
154   };
155   static gint aud_list[] = {
156     GST_RIFF_WAVE_FORMAT_MPEGL3,
157     GST_RIFF_WAVE_FORMAT_MPEGL12,
158     GST_RIFF_WAVE_FORMAT_PCM,
159     GST_RIFF_WAVE_FORMAT_VORBIS1,
160     GST_RIFF_WAVE_FORMAT_A52,
161     GST_RIFF_WAVE_FORMAT_ALAW,
162     GST_RIFF_WAVE_FORMAT_MULAW,
163     -1 /* end */
164   };
165   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
166   gint i = 0;
167   GstCaps *audcaps = NULL, *vidcaps = NULL, *temp;
168
169   for (i = 0; aud_list[i] != -1; i++) {
170     temp = gst_avi_demux_audio_caps (aud_list[i], NULL, NULL);
171     audcaps = gst_caps_append (audcaps, temp);
172   }
173   audiosrctempl = gst_pad_template_new ("audio_%02d",
174                                         GST_PAD_SRC,
175                                         GST_PAD_SOMETIMES,
176                                         audcaps, NULL);
177   for (i = 0; vid_list[i] != 0; i++) {
178     temp = gst_avi_demux_video_caps (vid_list[i], NULL, NULL, NULL);
179     vidcaps = gst_caps_append (vidcaps, temp);
180   }
181   vidcaps = gst_caps_append (vidcaps,
182                              gst_avi_demux_iavs_caps ());
183   videosrctempl = gst_pad_template_new ("video_%02d",
184                                         GST_PAD_SRC,
185                                         GST_PAD_SOMETIMES,
186                                         vidcaps, NULL);
187   gst_element_class_add_pad_template (element_class, audiosrctempl);
188   gst_element_class_add_pad_template (element_class, videosrctempl);
189   gst_element_class_add_pad_template (element_class,
190         GST_PAD_TEMPLATE_GET (sink_templ));
191   gst_element_class_set_details (element_class, &gst_avi_demux_details);
192
193 }
194
195 static void
196 gst_avi_demux_class_init (GstAviDemuxClass *klass) 
197 {
198   GObjectClass *gobject_class;
199   GstElementClass *gstelement_class;
200
201   gobject_class = (GObjectClass*)klass;
202   gstelement_class = (GstElementClass*)klass;
203
204   g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_BITRATE,
205     g_param_spec_long ("bitrate","bitrate","bitrate",
206                        G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
207   g_object_class_install_property (gobject_class, ARG_METADATA,
208     g_param_spec_boxed ("metadata", "Metadata", "Metadata",
209                         GST_TYPE_CAPS, G_PARAM_READABLE));
210   g_object_class_install_property (gobject_class, ARG_STREAMINFO,
211     g_param_spec_boxed ("streaminfo", "Streaminfo", "Streaminfo",
212                         GST_TYPE_CAPS, G_PARAM_READABLE));
213
214   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
215   
216   gobject_class->get_property = gst_avi_demux_get_property;
217   
218   gstelement_class->change_state = gst_avi_demux_change_state;
219   gstelement_class->send_event = gst_avi_demux_send_event;
220 }
221
222 static void 
223 gst_avi_demux_init (GstAviDemux *avi_demux) 
224 {
225   GST_FLAG_SET (avi_demux, GST_ELEMENT_EVENT_AWARE);
226                                 
227   avi_demux->sinkpad = gst_pad_new_from_template (
228                   GST_PAD_TEMPLATE_GET (sink_templ), "sink");
229   gst_element_add_pad (GST_ELEMENT (avi_demux), avi_demux->sinkpad);
230
231   gst_element_set_loop_function (GST_ELEMENT (avi_demux), gst_avi_demux_loop);
232 }
233
234 static gboolean
235 gst_avi_demux_avih (GstAviDemux *avi_demux)
236 {
237   gst_riff_avih *avih;
238   guint8 *avihdata;
239   GstByteStream  *bs = avi_demux->bs;
240   guint32 got_bytes;
241
242   got_bytes = gst_bytestream_peek_bytes (bs, &avihdata, sizeof (gst_riff_avih));
243   avih = (gst_riff_avih *) avihdata;
244
245   if (got_bytes == sizeof (gst_riff_avih)) {
246     avi_demux->avih.us_frame    = GUINT32_FROM_LE (avih->us_frame);
247     avi_demux->avih.max_bps     = GUINT32_FROM_LE (avih->max_bps);
248     avi_demux->avih.pad_gran    = GUINT32_FROM_LE (avih->pad_gran);
249     avi_demux->avih.flags       = GUINT32_FROM_LE (avih->flags);
250     avi_demux->avih.tot_frames  = GUINT32_FROM_LE (avih->tot_frames);
251     avi_demux->avih.init_frames = GUINT32_FROM_LE (avih->init_frames);
252     avi_demux->avih.streams     = GUINT32_FROM_LE (avih->streams);
253     avi_demux->avih.bufsize     = GUINT32_FROM_LE (avih->bufsize);
254     avi_demux->avih.width       = GUINT32_FROM_LE (avih->width);
255     avi_demux->avih.height      = GUINT32_FROM_LE (avih->height);
256     avi_demux->avih.scale       = GUINT32_FROM_LE (avih->scale);
257     avi_demux->avih.rate        = GUINT32_FROM_LE (avih->rate);
258     avi_demux->avih.start       = GUINT32_FROM_LE (avih->start);
259     avi_demux->avih.length      = GUINT32_FROM_LE (avih->length);
260
261     GST_INFO ( "gst_avi_demux: avih tag found");
262     GST_INFO ( "gst_avi_demux:  us_frame    %d", avi_demux->avih.us_frame);
263     GST_INFO ( "gst_avi_demux:  max_bps     %d", avi_demux->avih.max_bps);
264     GST_INFO ( "gst_avi_demux:  pad_gran    %d", avi_demux->avih.pad_gran);
265     GST_INFO ( "gst_avi_demux:  flags       0x%08x", avi_demux->avih.flags);
266     GST_INFO ( "gst_avi_demux:  tot_frames  %d", avi_demux->avih.tot_frames);
267     GST_INFO ( "gst_avi_demux:  init_frames %d", avi_demux->avih.init_frames);
268     GST_INFO ( "gst_avi_demux:  streams     %d", avi_demux->avih.streams);
269     GST_INFO ( "gst_avi_demux:  bufsize     %d", avi_demux->avih.bufsize);
270     GST_INFO ( "gst_avi_demux:  width       %d", avi_demux->avih.width);
271     GST_INFO ( "gst_avi_demux:  height      %d", avi_demux->avih.height);
272     GST_INFO ( "gst_avi_demux:  scale       %d", avi_demux->avih.scale);
273     GST_INFO ( "gst_avi_demux:  rate        %d", avi_demux->avih.rate);
274     GST_INFO ( "gst_avi_demux:  start       %d", avi_demux->avih.start);
275     GST_INFO ( "gst_avi_demux:  length      %d", avi_demux->avih.length);
276
277     return TRUE;
278   }
279   return FALSE;
280 }
281
282 static gboolean 
283 gst_avi_demux_strh (GstAviDemux *avi_demux)
284 {
285   gst_riff_strh *strh;
286   guint8 *strhdata;
287   GstByteStream  *bs = avi_demux->bs;
288   guint32 got_bytes;
289
290   got_bytes = gst_bytestream_peek_bytes (bs, &strhdata, sizeof (gst_riff_strh));
291   strh = (gst_riff_strh *) strhdata;
292
293   if (got_bytes == sizeof (gst_riff_strh)) {
294     avi_stream_context *target;
295
296     avi_demux->fcc_type = GUINT32_FROM_LE (strh->type);
297
298     target = &avi_demux->stream[avi_demux->num_streams];
299
300     target->num = avi_demux->num_streams;
301
302     target->strh.type           = avi_demux->fcc_type;
303     target->strh.fcc_handler    = GUINT32_FROM_LE (strh->fcc_handler);
304     target->strh.flags          = GUINT32_FROM_LE (strh->flags);
305     target->strh.priority       = GUINT32_FROM_LE (strh->priority);
306     target->strh.init_frames    = GUINT32_FROM_LE (strh->init_frames);
307     target->strh.scale          = GUINT32_FROM_LE (strh->scale);
308     target->strh.rate           = GUINT32_FROM_LE (strh->rate);
309     target->strh.start          = GUINT32_FROM_LE (strh->start);
310     target->strh.length         = GUINT32_FROM_LE (strh->length);
311     target->strh.bufsize        = GUINT32_FROM_LE (strh->bufsize);
312     target->strh.quality        = GUINT32_FROM_LE (strh->quality);
313     target->strh.samplesize     = GUINT32_FROM_LE (strh->samplesize);
314
315     if (!target->strh.scale)
316       target->strh.scale = 1; /* avoid division by zero */
317     if (!target->strh.rate)
318       target->strh.rate = 1; /* avoid division by zero */
319
320     GST_INFO ( "gst_avi_demux: strh tag found");
321     GST_INFO ( "gst_avi_demux:  type        0x%08x (%s)", 
322                   target->strh.type, gst_riff_id_to_fourcc (strh->type));
323     GST_INFO ( "gst_avi_demux:  fcc_handler 0x%08x (%s)", 
324                   target->strh.fcc_handler, gst_riff_id_to_fourcc (strh->fcc_handler));
325     GST_INFO ( "gst_avi_demux:  flags       0x%08x", strh->flags);
326     GST_INFO ( "gst_avi_demux:  priority    %d", target->strh.priority);
327     GST_INFO ( "gst_avi_demux:  init_frames %d", target->strh.init_frames);
328     GST_INFO ( "gst_avi_demux:  scale       %d", target->strh.scale);
329     GST_INFO ( "gst_avi_demux:  rate        %d", target->strh.rate);
330     GST_INFO ( "gst_avi_demux:  start       %d", target->strh.start);
331     GST_INFO ( "gst_avi_demux:  length      %d", target->strh.length);
332     GST_INFO ( "gst_avi_demux:  bufsize     %d", target->strh.bufsize);
333     GST_INFO ( "gst_avi_demux:  quality     %d", target->strh.quality);
334     GST_INFO ( "gst_avi_demux:  samplesize  %d", target->strh.samplesize);
335
336     target->delay = 0LL;
337     target->total_bytes = 0LL;
338     target->total_frames = 0;
339     target->end_pos = -1;
340     target->current_frame = 0;
341     target->current_byte = 0;
342     target->need_flush = FALSE;
343     target->skip = 0;
344
345     avi_demux->avih.bufsize = MAX (avi_demux->avih.bufsize, target->strh.bufsize);
346
347     return TRUE;
348   }
349   return FALSE;
350 }
351
352 static void
353 gst_avi_demux_dmlh (GstAviDemux *avi_demux)
354 {
355   gst_riff_dmlh *dmlh;
356   guint8 *dmlhdata;
357   GstByteStream  *bs = avi_demux->bs;
358   guint32 got_bytes;
359
360   got_bytes = gst_bytestream_peek_bytes (bs, &dmlhdata, sizeof (gst_riff_dmlh));
361   dmlh = (gst_riff_dmlh *) dmlhdata;
362 }
363
364 static void
365 gst_avi_demux_strn (GstAviDemux *avi_demux, gint len)
366 {
367   gchar *name;
368   guint8 *namedata;
369   GstByteStream  *bs = avi_demux->bs;
370   guint32 got_bytes;
371
372   got_bytes = gst_bytestream_peek_bytes (bs, &namedata, len);
373   name = (gchar *) namedata;
374   if (got_bytes != len)
375     return;
376
377   GST_DEBUG ("Stream name: \"%s\"", name);
378 }
379
380 static void
381 gst_avi_demux_metadata (GstAviDemux *avi_demux, gint len)
382 {
383   guint32 got_bytes;
384   GstByteStream  *bs = avi_demux->bs;
385   gst_riff_chunk *temp_chunk, chunk;
386   guint8 *tempdata;
387   gchar *name, *type;
388   GstProps *props;
389   GstPropsEntry *entry;
390
391   props = gst_props_empty_new ();
392
393   while (len > 0) {
394     got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
395     temp_chunk = (gst_riff_chunk *) tempdata;
396     
397     /* fixup for our big endian friends */
398     chunk.id = GUINT32_FROM_LE (temp_chunk->id);
399     chunk.size = GUINT32_FROM_LE (temp_chunk->size);
400
401     gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
402     if (got_bytes != sizeof (gst_riff_chunk))
403       return;
404     len -= sizeof (gst_riff_chunk);
405
406     /* don't care about empty entries - move on */
407     if (chunk.size == 0)
408       continue;
409
410     got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, chunk.size);
411     name = (gchar *) tempdata;
412     gst_bytestream_flush (bs, (chunk.size + 1) & ~1);
413     if (got_bytes != chunk.size)
414       return;
415     len -= ((chunk.size + 1) & ~1);
416
417     /* we now have an info string in 'name' of type 'chunk.id' - find 'type' */
418     switch (chunk.id) {
419       case GST_RIFF_INFO_IARL:
420         type = "Location";
421         break;
422       case GST_RIFF_INFO_IART:
423         type = "Artist";
424         break;
425       case GST_RIFF_INFO_ICMS:
426         type = "Commissioner";
427         break;
428       case GST_RIFF_INFO_ICMT:
429         type = "Comment";
430         break;
431       case GST_RIFF_INFO_ICOP:
432         type = "Copyright";
433         break;
434       case GST_RIFF_INFO_ICRD:
435         type = "Creation Date";
436         break;
437       case GST_RIFF_INFO_ICRP:
438         type = "Cropped";
439         break;
440       case GST_RIFF_INFO_IDIM:
441         type = "Dimensions";
442         break;
443       case GST_RIFF_INFO_IDPI:
444         type = "Dots per Inch";
445         break;
446       case GST_RIFF_INFO_IENG:
447         type = "Engineer";
448         break;
449       case GST_RIFF_INFO_IGNR:
450         type = "Genre";
451         break;
452       case GST_RIFF_INFO_IKEY:
453         type = "Keywords";
454         break;
455       case GST_RIFF_INFO_ILGT:
456         type = "Lightness";
457         break;
458       case GST_RIFF_INFO_IMED:
459         type = "Medium";
460         break;
461       case GST_RIFF_INFO_INAM:
462         type = "Title"; /* "Name" */
463         break;
464       case GST_RIFF_INFO_IPLT:
465         type = "Palette";
466         break;
467       case GST_RIFF_INFO_IPRD:
468         type = "Product";
469         break;
470       case GST_RIFF_INFO_ISBJ:
471         type = "Subject";
472         break;
473       case GST_RIFF_INFO_ISFT:
474         type = "Encoder"; /* "Software" */
475         break;
476       case GST_RIFF_INFO_ISHP:
477         type = "Sharpness";
478         break;
479       case GST_RIFF_INFO_ISRC:
480         type = "Source";
481         break;
482       case GST_RIFF_INFO_ISRF:
483         type = "Source Form";
484         break;
485       case GST_RIFF_INFO_ITCH:
486         type = "Technician";
487         break;
488       default:
489         type = NULL;
490         break;
491     }
492
493     if (type) {
494       /* create props entry */
495       entry = gst_props_entry_new (type, GST_PROPS_STRING (name));
496       gst_props_add_entry (props, entry);
497     }
498   }
499
500   gst_props_debug(props);
501
502   gst_caps_replace_sink (&avi_demux->metadata,
503                          gst_caps_new("avi_metadata",
504                                       "application/x-gst-metadata",
505                                         props));
506
507   g_object_notify(G_OBJECT(avi_demux), "metadata");
508 }
509
510 static void
511 gst_avi_demux_streaminfo (GstAviDemux *avi_demux)
512 {
513   GstProps *props;
514
515   props = gst_props_empty_new ();
516
517   /* compression formats are added later - a bit hacky */
518
519   gst_caps_replace_sink (&avi_demux->streaminfo,
520                          gst_caps_new("avi_streaminfo",
521                                       "application/x-gst-streaminfo",
522                                       props));
523
524   /*g_object_notify(G_OBJECT(avi_demux), "streaminfo");*/
525 }
526
527 /* video/audio pad/caps stuff */
528
529 #ifdef G_HAVE_ISO_VARARGS
530
531 #define GST_AVI_VID_CAPS_NEW(name, mimetype, ...)               \
532         (strf != NULL) ?                                        \
533         GST_CAPS_NEW (name,                                     \
534                       mimetype,                                 \
535                       "width",  GST_PROPS_INT (width),          \
536                       "height", GST_PROPS_INT (height),         \
537                       "framerate", GST_PROPS_FLOAT (framerate), \
538                       __VA_ARGS__)                              \
539         :                                                       \
540         GST_CAPS_NEW (name,                                     \
541                       mimetype,                                 \
542                       "width",  GST_PROPS_INT_RANGE (16, 4096), \
543                       "height", GST_PROPS_INT_RANGE (16, 4096), \
544                       "framerate", GST_PROPS_FLOAT_RANGE (0., G_MAXFLOAT), \
545                       __VA_ARGS__)
546
547 #elif defined(G_HAVE_GNUC_VARARGS)
548
549 #define GST_AVI_VID_CAPS_NEW(name, mimetype, props...)          \
550         (strf != NULL) ?                                        \
551         GST_CAPS_NEW (name,                                     \
552                       mimetype,                                 \
553                       "width",  GST_PROPS_INT (width),          \
554                       "height", GST_PROPS_INT (height),         \
555                       "framerate", GST_PROPS_FLOAT (framerate), \
556                       ##props)                                  \
557         :                                                       \
558         GST_CAPS_NEW (name,                                     \
559                       mimetype,                                 \
560                       "width",  GST_PROPS_INT_RANGE (16, 4096), \
561                       "height", GST_PROPS_INT_RANGE (16, 4096), \
562                       "framerate", GST_PROPS_FLOAT_RANGE (0., G_MAXFLOAT), \
563                       ##props)
564 #endif
565
566 static GstCaps *
567 gst_avi_demux_video_caps (guint32 codec_fcc,
568                           gst_riff_strh *strh,
569                           gst_riff_strf_vids *strf,
570                           GstAviDemux *avi_demux)
571 {
572   GstCaps *caps = NULL;
573   gchar *codecname = NULL;
574   gint width = -1, height = -1;
575   gdouble framerate = 0.;
576
577   if (strf != NULL) {
578     width = GUINT32_FROM_LE (strf->width);
579     height = GUINT32_FROM_LE (strf->height);
580   }
581   if (strh != NULL) {
582     framerate = 1. * GUINT32_FROM_LE (strh->rate) /
583                 GUINT32_FROM_LE (strh->scale); /* fps */
584   }
585
586   switch (codec_fcc) {
587     case GST_MAKE_FOURCC('I','4','2','0'):
588     case GST_MAKE_FOURCC('Y','U','Y','2'):
589       caps = GST_AVI_VID_CAPS_NEW (
590                   "avidemux_video_src_raw",
591                   "video/x-raw-yuv",
592                     "format",  GST_PROPS_FOURCC (codec_fcc)
593                 );
594       codecname = g_strdup_printf("Raw Video (" GST_FOURCC_FORMAT ")",
595                                   GST_FOURCC_ARGS(codec_fcc));
596       break;
597
598     case GST_MAKE_FOURCC('M','J','P','G'): /* YUY2 MJPEG */
599     case GST_MAKE_FOURCC('J','P','E','G'): /* generic (mostly RGB) MJPEG */
600     case GST_MAKE_FOURCC('P','I','X','L'): /* Miro/Pinnacle fourccs */
601     case GST_MAKE_FOURCC('V','I','X','L'): /* Miro/Pinnacle fourccs */
602       caps = GST_AVI_VID_CAPS_NEW (
603                   "avidemux_video_src_jpeg",
604                   "video/x-jpeg",
605                     NULL
606                 );
607       codecname = g_strdup_printf("Motion-JPEG (" GST_FOURCC_FORMAT ")",
608                                   GST_FOURCC_ARGS(codec_fcc));
609       break;
610
611     case GST_MAKE_FOURCC('H','F','Y','U'):
612       caps = GST_AVI_VID_CAPS_NEW (
613                   "avidemux_video_src_hfyu",
614                   "video/x-huffyuv",
615                     NULL
616                 );
617       codecname = g_strdup_printf("HuffYUV (" GST_FOURCC_FORMAT ")",
618                                   GST_FOURCC_ARGS(codec_fcc));
619       break;
620
621     case GST_MAKE_FOURCC('M','P','E','G'):
622     case GST_MAKE_FOURCC('M','P','G','I'):
623       caps = GST_AVI_VID_CAPS_NEW (
624                   "avidemux_video_src_mpeg",
625                   "video/mpeg",
626                     "systemstream", GST_PROPS_BOOLEAN (FALSE),
627                     "mpegversion", GST_PROPS_BOOLEAN (1)
628                 );
629       codecname = g_strdup_printf("MPEG-1 (" GST_FOURCC_FORMAT ")",
630                                   GST_FOURCC_ARGS(codec_fcc));
631       break;
632
633     case GST_MAKE_FOURCC('H','2','6','3'):
634     case GST_MAKE_FOURCC('i','2','6','3'):
635     case GST_MAKE_FOURCC('L','2','6','3'):
636     case GST_MAKE_FOURCC('M','2','6','3'):
637     case GST_MAKE_FOURCC('V','D','O','W'):
638     case GST_MAKE_FOURCC('V','I','V','O'):
639     case GST_MAKE_FOURCC('x','2','6','3'):
640       caps = GST_AVI_VID_CAPS_NEW (
641                   "avidemux_video_src_263",
642                   "video/x-h263",
643                     NULL
644                 );
645       codecname = g_strdup_printf("H263-compatible (" GST_FOURCC_FORMAT ")",
646                                   GST_FOURCC_ARGS(codec_fcc));
647       break;
648
649     case GST_MAKE_FOURCC('D','I','V','3'):
650     case GST_MAKE_FOURCC('D','I','V','4'):
651     case GST_MAKE_FOURCC('D','I','V','5'):
652       caps = GST_AVI_VID_CAPS_NEW (
653                   "avidemux_video_src_divx3",
654                   "video/x-divx",
655                     "divxversion", GST_PROPS_INT(3)
656                 );
657       codecname = g_strdup_printf("DivX-3.x (" GST_FOURCC_FORMAT ")",
658                                   GST_FOURCC_ARGS(codec_fcc));
659       break;
660
661     case GST_MAKE_FOURCC('d','i','v','x'):
662     case GST_MAKE_FOURCC('D','I','V','X'):
663     case GST_MAKE_FOURCC('D','X','5','0'):
664       caps = GST_AVI_VID_CAPS_NEW (
665                   "avidemux_video_src_divx5",
666                   "video/x-divx",
667                     "divxversion", GST_PROPS_INT(5)
668                 );
669       codecname = g_strdup_printf("DivX 4.x/5.x (" GST_FOURCC_FORMAT ")",
670                                   GST_FOURCC_ARGS(codec_fcc));
671       break;
672
673     case GST_MAKE_FOURCC('X','V','I','D'):
674     case GST_MAKE_FOURCC('x','v','i','d'):
675       caps = GST_AVI_VID_CAPS_NEW (
676                   "avidemux_video_src",
677                   "video/x-xvid",
678                     NULL
679                 );
680       codecname = g_strdup_printf("XviD (" GST_FOURCC_FORMAT ")",
681                                   GST_FOURCC_ARGS(codec_fcc));
682       break;
683
684     case GST_MAKE_FOURCC('M','P','G','4'):
685       caps = GST_AVI_VID_CAPS_NEW (
686                   "avidemux_video_src",
687                   "video/x-msmpeg",
688                     "msmpegversion", GST_PROPS_INT (41)
689                 );
690       codecname = g_strdup_printf("MS MPEG-4.1 (" GST_FOURCC_FORMAT ")",
691                                   GST_FOURCC_ARGS(codec_fcc));
692       break;
693
694     case GST_MAKE_FOURCC('M','P','4','2'):
695       caps = GST_AVI_VID_CAPS_NEW (
696                   "avidemux_video_src",
697                   "video/x-msmpeg",
698                     "msmpegversion", GST_PROPS_INT (42)
699                 );
700       codecname = g_strdup_printf("MS MPEG-4.2 (" GST_FOURCC_FORMAT ")",
701                                   GST_FOURCC_ARGS(codec_fcc));
702       break;
703
704     case GST_MAKE_FOURCC('M','P','4','3'):
705       caps = GST_AVI_VID_CAPS_NEW (
706                   "avidemux_video_src",
707                   "video/x-msmpeg",
708                     "msmpegversion", GST_PROPS_INT (43)
709                 );
710       codecname = g_strdup_printf("MS MPEG-4.3 (" GST_FOURCC_FORMAT ")",
711                                   GST_FOURCC_ARGS(codec_fcc));
712       break;
713
714     case GST_MAKE_FOURCC('3','I','V','1'):
715     case GST_MAKE_FOURCC('3','I','V','2'):
716       caps = GST_AVI_VID_CAPS_NEW (
717                   "avidemux_video_src_3ivx",
718                   "video/x-3ivx",
719                     NULL
720                 );
721       codecname = g_strdup_printf("3ivX (" GST_FOURCC_FORMAT ")",
722                                   GST_FOURCC_ARGS(codec_fcc));
723       break;
724
725     case GST_MAKE_FOURCC('D','V','S','D'):
726     case GST_MAKE_FOURCC('d','v','s','d'):
727       caps = GST_AVI_VID_CAPS_NEW (
728                   "avidemux_video_src",
729                   "video/x-dv",
730                     "systemstream", GST_PROPS_BOOLEAN (FALSE)
731                 );
732       codecname = g_strdup_printf("Digital Video type 2 (" GST_FOURCC_FORMAT ")",
733                                   GST_FOURCC_ARGS(codec_fcc));
734       break;
735
736     case GST_MAKE_FOURCC('W','M','V','1'):
737       caps = GST_AVI_VID_CAPS_NEW (
738                   "avidemux_video_src_wmv1",
739                   "video/x-wmv",
740                     "wmvversion", GST_PROPS_INT (1)
741                 );
742       codecname = g_strdup_printf("Windows Media Format 1 ("
743                                   GST_FOURCC_FORMAT ")",
744                                   GST_FOURCC_ARGS(codec_fcc));
745       break;
746
747     case GST_MAKE_FOURCC('W','M','V','2'):
748       caps = GST_AVI_VID_CAPS_NEW (
749                   "avidemux_video_src_wmv2",
750                   "video/x-wmv",
751                     "wmvversion", GST_PROPS_INT (2)
752                 );
753       codecname = g_strdup_printf("Windows Media Format 2 ("
754                                   GST_FOURCC_FORMAT ")",
755                                   GST_FOURCC_ARGS(codec_fcc));
756       break;
757
758     default:
759       g_warning ("avidemux: unkown video format " GST_FOURCC_FORMAT,
760                  GST_FOURCC_ARGS(codec_fcc));
761       break;
762   }
763
764   /* set video codec info on streaminfo caps */
765   if (avi_demux != NULL && codecname != NULL) {
766     GstPropsEntry *entry;
767     entry = gst_props_entry_new("videocodec",
768                                 GST_PROPS_STRING(codecname));
769     gst_props_add_entry(avi_demux->streaminfo->properties, entry);
770   }
771   if (codecname != NULL) {
772     g_free(codecname);
773   }
774
775   return caps;
776 }
777
778 static void 
779 gst_avi_demux_strf_vids (GstAviDemux *avi_demux)
780 {
781   gst_riff_strf_vids *strf;
782   gst_riff_strh *strh;
783   guint8 *strfdata;
784   GstPad *srcpad;
785   GstCaps *caps = NULL;
786   avi_stream_context *stream;
787   GstByteStream  *bs = avi_demux->bs;
788   guint32 got_bytes;
789   gchar *padname;
790
791   got_bytes = gst_bytestream_peek_bytes (bs, &strfdata, sizeof (gst_riff_strf_vids));
792   strf = (gst_riff_strf_vids *) strfdata;
793   if (got_bytes != sizeof (gst_riff_strf_vids))
794     return;
795
796   padname = g_strdup_printf ("video_%02d", avi_demux->num_v_streams);
797   srcpad =  gst_pad_new_from_template (videosrctempl, padname);
798   g_free (padname);
799
800   /* let's try some gstreamer-like mime-type caps */
801   strh = &avi_demux->stream[avi_demux->num_streams].strh;
802   caps = gst_avi_demux_video_caps (GUINT32_FROM_LE(strf->compression),
803                                    strh, strf, avi_demux);
804
805   if (caps != NULL) {
806     gst_pad_try_set_caps (srcpad, caps);
807   }
808   gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
809   gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
810   gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
811   gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
812   gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
813   gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
814
815   stream = &avi_demux->stream[avi_demux->num_streams];
816   stream->pad = srcpad;
817   gst_pad_set_element_private (srcpad, stream);
818   avi_demux->num_streams++;
819   avi_demux->num_v_streams++;
820
821   gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
822 }
823
824 #ifdef G_HAVE_ISO_VARARGS
825
826 #define GST_AVI_AUD_CAPS_NEW(name, mimetype, ...)                       \
827         (strf != NULL) ?                                                \
828         GST_CAPS_NEW (name,                                             \
829                       mimetype,                                         \
830                       "rate",     GST_PROPS_INT (rate),                 \
831                       "channels", GST_PROPS_INT (channels),             \
832                       __VA_ARGS__)                                      \
833         :                                                               \
834         GST_CAPS_NEW (name,                                             \
835                       mimetype,                                         \
836                       "rate",     GST_PROPS_INT_RANGE (8000, 96000),    \
837                       "channels", GST_PROPS_INT_RANGE (1, 2),           \
838                       __VA_ARGS__)
839
840
841 #elif defined(G_HAVE_GNUC_VARARGS)
842
843 #define GST_AVI_AUD_CAPS_NEW(name, mimetype, props...)                  \
844         (strf != NULL) ?                                                \
845         GST_CAPS_NEW (name,                                             \
846                       mimetype,                                         \
847                       "rate",     GST_PROPS_INT (rate),                 \
848                       "channels", GST_PROPS_INT (channels),             \
849                       ##props)                                          \
850         :                                                               \
851         GST_CAPS_NEW (name,                                             \
852                       mimetype,                                         \
853                       "rate",     GST_PROPS_INT_RANGE (8000, 96000),    \
854                       "channels", GST_PROPS_INT_RANGE (1, 2),           \
855                       ##props)
856 #endif
857
858 static GstCaps *
859 gst_avi_demux_audio_caps (guint16 codec_id,
860                           gst_riff_strf_auds *strf,
861                           GstAviDemux *avi_demux)
862 {
863   GstCaps *caps = NULL;
864   gchar *codecname = NULL;
865   gint rate = -1, channels = -1;
866
867   if (strf != NULL) {
868     rate = GUINT32_FROM_LE (strf->rate);
869     channels = GUINT16_FROM_LE (strf->channels);
870   }
871
872   switch (codec_id) {
873     case GST_RIFF_WAVE_FORMAT_MPEGL3: /* mp3 */
874       caps = GST_AVI_AUD_CAPS_NEW ("avi_demux_audio_src_mp3",
875                                    "audio/mpeg",
876                                      "layer", GST_PROPS_INT (3));
877       codecname = g_strdup_printf("MPEG-1 layer 3 audio (0x%04x)",
878                                   codec_id);
879       break;
880
881     case GST_RIFF_WAVE_FORMAT_MPEGL12: /* mp1 or mp2 */
882       caps = GST_AVI_AUD_CAPS_NEW ("avi_demux_audio_src_mp12",
883                                    "audio/mpeg",
884                                      "layer", GST_PROPS_INT (2));
885       codecname = g_strdup_printf("MPEG-1 layer 1/2 audio (0x%04x)",
886                                   codec_id);
887       break;
888
889     case GST_RIFF_WAVE_FORMAT_PCM: /* PCM/wav */ {
890       GstPropsEntry *width = NULL, *depth = NULL, *signedness = NULL;
891
892       if (strf != NULL) {
893         gint ba = GUINT16_FROM_LE (strf->blockalign);
894         gint ch = GUINT16_FROM_LE (strf->channels);
895         gint ws = GUINT16_FROM_LE (strf->size);
896
897         width = gst_props_entry_new ("width",
898                                      GST_PROPS_INT (ba * 8 / ch));
899         depth = gst_props_entry_new ("depth",
900                                      GST_PROPS_INT (ws));
901         signedness = gst_props_entry_new ("signed",
902                                           GST_PROPS_BOOLEAN (ws != 8));
903       } else {
904         signedness = gst_props_entry_new ("signed",
905                                           GST_PROPS_LIST (
906                                             GST_PROPS_BOOLEAN (TRUE),
907                                             GST_PROPS_BOOLEAN (FALSE)));
908         width = gst_props_entry_new ("width",
909                                      GST_PROPS_LIST (
910                                        GST_PROPS_INT (8),
911                                        GST_PROPS_INT (16)));
912         depth = gst_props_entry_new ("depth",
913                                      GST_PROPS_LIST (
914                                        GST_PROPS_INT (8),
915                                        GST_PROPS_INT (16)));
916       }
917
918       caps = GST_AVI_AUD_CAPS_NEW ("avi_demux_audio_src_pcm",
919                                    "audio/x-raw-int",
920                                      "endianness",
921                                        GST_PROPS_INT (G_LITTLE_ENDIAN));
922       gst_props_add_entry (caps->properties, width);
923       gst_props_add_entry (caps->properties, depth);
924       gst_props_add_entry (caps->properties, signedness);
925
926       codecname = g_strdup_printf("Raw PCM/WAV (0x%04x)",
927                                   codec_id);
928     }
929       break;
930
931     case GST_RIFF_WAVE_FORMAT_MULAW:
932       if (strf != NULL && strf->size != 8) {
933         g_warning ("invalid depth (%d) of mulaw audio, overwriting.",
934                    strf->size);
935       }
936       caps = GST_AVI_AUD_CAPS_NEW ("avidemux_audio_src",
937                                    "audio/x-mulaw",
938                                      NULL);
939       codecname = g_strdup_printf("A-law encoded (0x%04x)",
940                                   codec_id);
941       break;
942
943     case GST_RIFF_WAVE_FORMAT_ALAW:
944       if (strf != NULL && strf->size != 8) {
945         g_warning ("invalid depth (%d) of alaw audio, overwriting.",
946                    strf->size);
947       }
948       caps = GST_AVI_AUD_CAPS_NEW ("avidemux_audio_src",
949                                    "audio/x-alaw",
950                                      NULL);
951       codecname = g_strdup_printf("A-law encoded (0x%04x)",
952                                   codec_id);
953       break;
954
955     case GST_RIFF_WAVE_FORMAT_VORBIS1: /* ogg/vorbis mode 1 */
956     case GST_RIFF_WAVE_FORMAT_VORBIS2: /* ogg/vorbis mode 2 */
957     case GST_RIFF_WAVE_FORMAT_VORBIS3: /* ogg/vorbis mode 3 */
958     case GST_RIFF_WAVE_FORMAT_VORBIS1PLUS: /* ogg/vorbis mode 1+ */
959     case GST_RIFF_WAVE_FORMAT_VORBIS2PLUS: /* ogg/vorbis mode 2+ */
960     case GST_RIFF_WAVE_FORMAT_VORBIS3PLUS: /* ogg/vorbis mode 3+ */
961       caps = GST_AVI_AUD_CAPS_NEW ("asf_demux_audio_src_vorbis",
962                                    "audio/x-vorbis",
963                                      NULL);
964       codecname = g_strdup_printf("Vorbis (0x%04x)",
965                                   codec_id);
966       break;
967
968     case GST_RIFF_WAVE_FORMAT_A52:
969       caps = GST_AVI_AUD_CAPS_NEW ("asf_demux_audio_src_ac3",
970                                    "audio/x-ac3",
971                                      NULL);
972       codecname = g_strdup_printf("AC-3 (0x%04x)",
973                                   codec_id);
974       break;
975
976     default:
977       g_warning ("avidemux: unkown audio format 0x%04x",
978                  codec_id);
979       break;
980   }
981
982   if (avi_demux != NULL && codecname != NULL) {
983     /* set audio codec in streaminfo */
984     GstPropsEntry *entry;
985     entry = gst_props_entry_new("audiocodec",
986                                 GST_PROPS_STRING(codecname));
987     gst_props_add_entry(avi_demux->streaminfo->properties, entry);
988   }
989   if (codecname != NULL) {
990     g_free (codecname);
991   }
992
993   return caps;
994 }
995
996 static void 
997 gst_avi_demux_strf_auds (GstAviDemux *avi_demux)
998 {
999   gst_riff_strf_auds *strf;
1000   guint8 *strfdata;
1001   GstPad *srcpad;
1002   GstCaps *caps = NULL;
1003   avi_stream_context *stream;
1004   GstByteStream  *bs = avi_demux->bs;
1005   guint32 got_bytes;
1006   gchar *padname;
1007
1008   got_bytes = gst_bytestream_peek_bytes (bs, &strfdata, sizeof (gst_riff_strf_auds));
1009   strf = (gst_riff_strf_auds *) strfdata;
1010   if (got_bytes != sizeof (gst_riff_strf_auds))
1011     return;
1012
1013   GST_INFO ( "gst_avi_demux: strf tag found in context auds");
1014   GST_INFO ( "gst_avi_demux:  format      %d", GUINT16_FROM_LE (strf->format));
1015   GST_INFO ( "gst_avi_demux:  channels    %d", GUINT16_FROM_LE (strf->channels));
1016   GST_INFO ( "gst_avi_demux:  rate        %d", GUINT32_FROM_LE (strf->rate));
1017   GST_INFO ( "gst_avi_demux:  av_bps      %d", GUINT32_FROM_LE (strf->av_bps));
1018   GST_INFO ( "gst_avi_demux:  blockalign  %d", GUINT16_FROM_LE (strf->blockalign));
1019   GST_INFO ( "gst_avi_demux:  size        %d", GUINT16_FROM_LE (strf->size));
1020
1021   padname = g_strdup_printf ("audio_%02d", 
1022                              avi_demux->num_a_streams);
1023   srcpad =  gst_pad_new_from_template (audiosrctempl, padname);
1024   g_free (padname);
1025
1026   caps = gst_avi_demux_audio_caps (GUINT16_FROM_LE (strf->format),
1027                                    strf, avi_demux);
1028
1029   if (caps != NULL) {
1030     gst_pad_try_set_caps(srcpad, caps);
1031   }
1032   gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
1033   gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
1034   gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
1035   gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
1036   gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
1037   gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
1038
1039   stream = &avi_demux->stream[avi_demux->num_streams];
1040   stream->pad = srcpad;
1041   gst_pad_set_element_private (srcpad, stream);
1042   avi_demux->num_streams++;
1043   avi_demux->num_a_streams++;
1044
1045   gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
1046 }
1047
1048 static GstCaps *
1049 gst_avi_demux_iavs_caps (void)
1050 {
1051   return GST_CAPS_NEW ("avi_type_dv", 
1052                        "video/x-dv", 
1053                          "systemstream", GST_PROPS_BOOLEAN (TRUE));
1054 }
1055
1056 static void 
1057 gst_avi_demux_strf_iavs (GstAviDemux *avi_demux)
1058 {
1059   gst_riff_strf_iavs *strf;
1060   guint8 *strfdata;
1061   GstPad *srcpad;
1062   GstCaps *caps = NULL;
1063   avi_stream_context *stream;
1064   GstByteStream  *bs = avi_demux->bs;
1065   guint32 got_bytes;
1066   gchar *padname;
1067   GstPropsEntry *entry;
1068
1069   got_bytes = gst_bytestream_peek_bytes (bs, &strfdata, sizeof (gst_riff_strf_iavs));
1070   strf = (gst_riff_strf_iavs *) strfdata;
1071   if (got_bytes != sizeof (gst_riff_strf_iavs))
1072     return;
1073
1074   GST_INFO ( "gst_avi_demux: strf tag found in context iavs");
1075   GST_INFO ( "gst_avi_demux:  DVAAuxSrc   %08x", GUINT32_FROM_LE (strf->DVAAuxSrc));
1076   GST_INFO ( "gst_avi_demux:  DVAAuxCtl   %08x", GUINT32_FROM_LE (strf->DVAAuxCtl));
1077   GST_INFO ( "gst_avi_demux:  DVAAuxSrc1  %08x", GUINT32_FROM_LE (strf->DVAAuxSrc1));
1078   GST_INFO ( "gst_avi_demux:  DVAAuxCtl1  %08x", GUINT32_FROM_LE (strf->DVAAuxCtl1));
1079   GST_INFO ( "gst_avi_demux:  DVVAuxSrc   %08x", GUINT32_FROM_LE (strf->DVVAuxSrc));
1080   GST_INFO ( "gst_avi_demux:  DVVAuxCtl   %08x", GUINT32_FROM_LE (strf->DVVAuxCtl));
1081   GST_INFO ( "gst_avi_demux:  DVReserved1 %08x", GUINT32_FROM_LE (strf->DVReserved1));
1082   GST_INFO ( "gst_avi_demux:  DVReserved2 %08x", GUINT32_FROM_LE (strf->DVReserved2));
1083
1084   padname = g_strdup_printf ("video_%02d", 
1085                              avi_demux->num_v_streams);
1086   srcpad =  gst_pad_new_from_template (videosrctempl, padname);
1087   g_free (padname);
1088
1089   caps = gst_avi_demux_iavs_caps ();
1090   entry = gst_props_entry_new("videocodec",
1091                               GST_PROPS_STRING("Digital Video type 1"));
1092   gst_props_add_entry(avi_demux->streaminfo->properties, entry);
1093
1094   if (caps != NULL) {
1095     gst_pad_try_set_caps(srcpad, caps);
1096   }
1097   gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
1098   gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
1099   gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
1100   gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
1101   gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
1102   gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
1103
1104   stream = &avi_demux->stream[avi_demux->num_streams];
1105   stream->pad = srcpad;
1106   gst_pad_set_element_private (srcpad, stream);
1107   avi_demux->num_streams++;
1108   avi_demux->num_v_streams++;
1109
1110   gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
1111 }
1112
1113 static void
1114 gst_avi_debug_entry (const gchar *prefix, gst_avi_index_entry *entry)
1115 {
1116   GST_DEBUG ("%s: %05d %d %08llx %05d %14" G_GINT64_FORMAT " %08x %08x (%d) %08x", 
1117                   prefix, entry->index_nr, entry->stream_nr, 
1118                   (unsigned long long)entry->bytes_before, 
1119                   entry->frames_before, entry->ts, entry->flags, entry->offset, 
1120                   entry->offset, entry->size);
1121 }
1122
1123 static void
1124 gst_avi_demux_parse_index (GstAviDemux *avi_demux,
1125                           gulong filepos, gulong offset)
1126 {
1127   GstBuffer *buf;
1128   gulong index_size;
1129   guint32 got_bytes;
1130   gint i;
1131   gst_riff_index_entry *entry;
1132   guint32 id;
1133
1134   if (!gst_bytestream_seek (avi_demux->bs, filepos + offset, GST_SEEK_METHOD_SET)) {
1135     GST_INFO ( "avidemux: could not seek to index");
1136     return;
1137   }
1138   do {
1139     guint32 remaining;
1140     GstEvent *event;
1141   
1142     got_bytes = gst_bytestream_read (avi_demux->bs, &buf, 8);
1143     if (got_bytes == 8)
1144       break;
1145
1146     gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
1147     gst_event_unref (event);
1148   } while (TRUE);
1149
1150   if (GST_BUFFER_OFFSET (buf) != filepos + offset || GST_BUFFER_SIZE (buf) != 8) {
1151     GST_INFO ( "avidemux: could not get index, got %" G_GINT64_FORMAT " %d, expected %ld", 
1152                     GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf), filepos + offset);
1153     goto end;
1154   }
1155
1156   id = GUINT32_FROM_LE (*(guint32 *)GST_BUFFER_DATA (buf));
1157
1158   if (id != GST_RIFF_TAG_idx1) {
1159     GST_INFO ( "avidemux: no index found");
1160     goto end;
1161   }
1162
1163   index_size = GUINT32_FROM_LE(*(guint32 *)(GST_BUFFER_DATA (buf) + 4));
1164   gst_buffer_unref (buf);
1165
1166   gst_bytestream_size_hint (avi_demux->bs, index_size);
1167
1168   got_bytes = gst_bytestream_read (avi_demux->bs, &buf, index_size);
1169   if (got_bytes < index_size) {
1170     GST_INFO ( "avidemux: error reading index");
1171     goto end;
1172   }
1173
1174   avi_demux->index_size = index_size/sizeof(gst_riff_index_entry);
1175   GST_INFO ( "avidemux: index size %lu", avi_demux->index_size);
1176
1177   avi_demux->index_entries = g_malloc (avi_demux->index_size * sizeof (gst_avi_index_entry));
1178
1179   entry = (gst_riff_index_entry *) GST_BUFFER_DATA (buf);
1180
1181   for (i = 0; i < avi_demux->index_size; i++) {
1182     avi_stream_context *stream;
1183     gint stream_nr;
1184     gst_avi_index_entry *target = &avi_demux->index_entries[i];
1185     GstFormat format;
1186     guint32 id;
1187
1188     id = GUINT32_FROM_LE (entry[i].id);
1189     stream_nr = CHUNKID_TO_STREAMNR (id);
1190     if (stream_nr > avi_demux->num_streams || stream_nr < 0) {
1191       avi_demux->index_entries[i].stream_nr = -1;
1192       continue;
1193     }
1194
1195     target->stream_nr = stream_nr;
1196     stream = &avi_demux->stream[stream_nr];
1197
1198     target->index_nr = i;
1199     target->flags    = GUINT32_FROM_LE (entry[i].flags);
1200     target->size     = GUINT32_FROM_LE (entry[i].size);
1201     target->offset   = GUINT32_FROM_LE (entry[i].offset);
1202
1203     /* figure out if the index is 0 based or relative to the MOVI start */
1204     if (i == 0) {
1205       if (target->offset < filepos)
1206         avi_demux->index_offset = filepos - 4;
1207       else
1208         avi_demux->index_offset = 0;
1209     }
1210
1211     target->bytes_before = stream->total_bytes;
1212     target->frames_before = stream->total_frames;
1213
1214     format = GST_FORMAT_TIME;
1215     if (stream->strh.type == GST_RIFF_FCC_auds) {
1216       /* all audio frames are keyframes */
1217       target->flags |= GST_RIFF_IF_KEYFRAME;
1218     }
1219       
1220     /* constant rate stream */
1221     if (stream->strh.samplesize && stream->strh.type == GST_RIFF_FCC_auds) {
1222       gst_pad_convert (stream->pad, GST_FORMAT_BYTES, stream->total_bytes,
1223                                  &format, &target->ts);
1224     }
1225     /* VBR stream */
1226     else {
1227       gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT, stream->total_frames,
1228                                  &format, &target->ts);
1229     }
1230     gst_avi_debug_entry ("index", target);
1231
1232     stream->total_bytes += target->size;
1233     stream->total_frames++;
1234   }
1235   for (i = 0; i < avi_demux->num_streams; i++) {
1236     avi_stream_context *stream;
1237
1238     stream = &avi_demux->stream[i];
1239     GST_DEBUG ("stream %i: %d frames, %" G_GINT64_FORMAT " bytes", 
1240                i, stream->total_frames, stream->total_bytes);
1241   }
1242   gst_buffer_unref (buf);
1243
1244 end:
1245   GST_DEBUG ("index offset at %08lx", filepos);
1246
1247   if (!gst_bytestream_seek (avi_demux->bs, filepos, GST_SEEK_METHOD_SET)) {
1248     GST_INFO ( "avidemux: could not seek back to movi");
1249     return;
1250   }
1251 }
1252
1253 static gst_avi_index_entry*
1254 gst_avi_demux_index_next (GstAviDemux *avi_demux, gint stream_nr, gint start, guint32 flags)
1255 {
1256   gint i;
1257   gst_avi_index_entry *entry = NULL;
1258
1259   for (i = start; i < avi_demux->index_size; i++) {
1260     entry = &avi_demux->index_entries[i];
1261
1262     if (entry->stream_nr == stream_nr && (entry->flags & flags) == flags) {
1263       break;
1264     }
1265   }
1266
1267   return entry;
1268 }
1269
1270 static gst_avi_index_entry*
1271 gst_avi_demux_index_entry_for_time (GstAviDemux *avi_demux, gint stream_nr, guint64 time, guint32 flags)
1272 {
1273   gst_avi_index_entry *entry = NULL, *last_entry = NULL;
1274   gint i;
1275
1276   i = -1;
1277   do {
1278     entry = gst_avi_demux_index_next (avi_demux, stream_nr, i + 1, flags);
1279     if (!entry)
1280       return NULL;
1281
1282     i = entry->index_nr;
1283
1284     if (entry->ts <= time) {
1285       last_entry = entry;
1286     }
1287   }
1288   while (entry->ts <= time);
1289
1290   return last_entry;
1291 }
1292
1293 static const GstFormat*
1294 gst_avi_demux_get_src_formats (GstPad *pad) 
1295 {
1296   avi_stream_context *stream = gst_pad_get_element_private (pad);
1297
1298   static const GstFormat src_a_formats[] = {
1299     GST_FORMAT_TIME,
1300     GST_FORMAT_BYTES,
1301     GST_FORMAT_DEFAULT,
1302     0
1303   };
1304   static const GstFormat src_v_formats[] = {
1305     GST_FORMAT_TIME,
1306     GST_FORMAT_DEFAULT,
1307     0
1308   };
1309
1310   return (stream->strh.type == GST_RIFF_FCC_auds ? src_a_formats : src_v_formats);
1311 }
1312
1313 static gboolean
1314 gst_avi_demux_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
1315                            GstFormat *dest_format, gint64 *dest_value)
1316 {
1317   gboolean res = TRUE;
1318   avi_stream_context *stream = gst_pad_get_element_private (pad);
1319
1320   if (stream->strh.type != GST_RIFF_FCC_auds && 
1321       (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
1322     return FALSE;
1323
1324   switch (src_format) {
1325     case GST_FORMAT_TIME:
1326       switch (*dest_format) {
1327         case GST_FORMAT_BYTES:
1328           *dest_value = src_value * stream->strh.rate / (stream->strh.scale * GST_SECOND);
1329           break;
1330         case GST_FORMAT_DEFAULT:
1331           *dest_value = src_value * stream->strh.rate / (stream->strh.scale * GST_SECOND);
1332           break;
1333         default:
1334           res = FALSE;
1335           break;
1336       }
1337       break;
1338     case GST_FORMAT_BYTES:
1339       switch (*dest_format) {
1340         case GST_FORMAT_TIME:
1341           *dest_value = ((gfloat)src_value) * GST_SECOND / stream->strh.rate;
1342           break;
1343         default:
1344           res = FALSE;
1345           break;
1346       }
1347       break;
1348     case GST_FORMAT_DEFAULT:
1349       switch (*dest_format) {
1350         case GST_FORMAT_TIME:
1351           *dest_value = ((((gfloat)src_value) * stream->strh.scale)  / stream->strh.rate) * GST_SECOND;
1352           break;
1353         default:
1354           res = FALSE;
1355           break;
1356       }
1357       break;
1358     default:
1359       res = FALSE;
1360   }
1361
1362   return res;
1363 }
1364
1365 static const GstQueryType*
1366 gst_avi_demux_get_src_query_types (GstPad *pad) 
1367 {
1368   static const GstQueryType src_types[] = {
1369     GST_QUERY_TOTAL,
1370     GST_QUERY_POSITION,
1371     0
1372   };
1373
1374   return src_types;
1375 }
1376
1377 static gboolean
1378 gst_avi_demux_handle_src_query (GstPad *pad, GstQueryType type, 
1379                                 GstFormat *format, gint64 *value)
1380 {
1381   gboolean res = TRUE;
1382   //GstAviDemux *avi_demux = GST_AVI_DEMUX (gst_pad_get_parent (pad));
1383   avi_stream_context *stream = gst_pad_get_element_private (pad);
1384
1385   switch (type) {
1386     case GST_QUERY_TOTAL:
1387       switch (*format) {
1388         case GST_FORMAT_TIME:
1389           *value = (((gfloat)stream->strh.scale) * stream->strh.length / stream->strh.rate) * GST_SECOND;
1390           break;
1391         case GST_FORMAT_BYTES:
1392           if (stream->strh.type == GST_RIFF_FCC_auds) {
1393             *value = stream->total_bytes;
1394           }
1395           else
1396             res = FALSE;
1397           break;
1398         case GST_FORMAT_DEFAULT:
1399           if (stream->strh.type == GST_RIFF_FCC_auds)
1400             *value = stream->strh.length * stream->strh.samplesize;
1401           else if (stream->strh.type == GST_RIFF_FCC_vids)
1402             *value = stream->strh.length;
1403           else
1404             res = FALSE;
1405           break;
1406         default:
1407           res = FALSE;
1408           break;
1409       }
1410       break;
1411     case GST_QUERY_POSITION:
1412       switch (*format) {
1413         case GST_FORMAT_TIME:
1414           if (stream->strh.samplesize && stream->strh.type == GST_RIFF_FCC_auds) {
1415             //*value = (((gfloat)stream->current_byte) * stream->strh.scale / stream->strh.rate) * GST_SECOND;
1416             *value = ((gfloat)stream->current_byte) * GST_SECOND / stream->strh.rate;
1417           }
1418           else {
1419             *value = (((gfloat)stream->current_frame) * stream->strh.scale / stream->strh.rate) * GST_SECOND;
1420           }
1421           break;
1422         case GST_FORMAT_BYTES:
1423           *value = stream->current_byte;
1424           break;
1425         case GST_FORMAT_DEFAULT:
1426           if (stream->strh.samplesize && stream->strh.type == GST_RIFF_FCC_auds) 
1427             *value = stream->current_byte * stream->strh.samplesize;
1428           else 
1429             *value = stream->current_frame;
1430           break;
1431         default:
1432           res = FALSE;
1433           break;
1434       }
1435       break;
1436     default:
1437       res = FALSE;
1438       break;
1439   }
1440
1441   return res;
1442 }
1443
1444 static gint32
1445 gst_avi_demux_sync_streams (GstAviDemux *avi_demux, guint64 time)
1446 {
1447   gint i;
1448   guint32 min_index = G_MAXUINT;
1449   avi_stream_context *stream;
1450   gst_avi_index_entry *entry;
1451
1452   for (i = 0; i < avi_demux->num_streams; i++) {
1453     stream = &avi_demux->stream[i];
1454
1455     GST_DEBUG ("finding %d for time %" G_GINT64_FORMAT, i, time);
1456
1457     entry = gst_avi_demux_index_entry_for_time (avi_demux, stream->num, time, GST_RIFF_IF_KEYFRAME);
1458     if (entry) {
1459       gst_avi_debug_entry ("sync entry", entry);
1460
1461       min_index = MIN (entry->index_nr, min_index);
1462     }
1463   }
1464   GST_DEBUG ("first index at %d", min_index);
1465   
1466   /* now we know the entry we need to sync on. calculate number of frames to
1467    * skip fro there on and the stream stats */
1468   for (i = 0; i < avi_demux->num_streams; i++) {
1469     gst_avi_index_entry *next_entry;
1470     stream = &avi_demux->stream[i];
1471
1472     /* next entry */
1473     next_entry = gst_avi_demux_index_next (avi_demux, stream->num, min_index, 0);
1474     /* next entry with keyframe */
1475     entry = gst_avi_demux_index_next (avi_demux, stream->num, min_index, GST_RIFF_IF_KEYFRAME);
1476     gst_avi_debug_entry ("final sync", entry);
1477
1478     stream->current_byte = next_entry->bytes_before;
1479     stream->current_frame = next_entry->frames_before;
1480     stream->skip = entry->frames_before - next_entry->frames_before;
1481
1482     GST_DEBUG ("%d skip %d", stream->num, stream->skip);
1483   }
1484   GST_DEBUG ("final index at %d", min_index);
1485
1486   return min_index;
1487 }
1488
1489 static gboolean
1490 gst_avi_demux_send_event (GstElement *element, GstEvent *event)
1491 {
1492   const GList *pads;
1493
1494   pads = gst_element_get_pad_list (element);
1495
1496   while (pads) { 
1497     GstPad *pad = GST_PAD (pads->data);
1498
1499     if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
1500       /* we ref the event here as we might have to try again if the event
1501        * failed on this pad */
1502       gst_event_ref (event);
1503       if (gst_avi_demux_handle_src_event (pad, event)) {
1504         gst_event_unref (event);
1505         return TRUE;
1506       }
1507     }
1508     
1509     pads = g_list_next (pads);
1510   }
1511   
1512   gst_event_unref (event);
1513   return FALSE;
1514 }
1515
1516 static const GstEventMask*
1517 gst_avi_demux_get_event_mask (GstPad *pad)
1518 {
1519   static const GstEventMask masks[] = {
1520     { GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
1521     { GST_EVENT_SEEK_SEGMENT, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
1522     { 0, }
1523   };
1524
1525   return masks;
1526 }
1527         
1528 static gboolean
1529 gst_avi_demux_handle_src_event (GstPad *pad, GstEvent *event)
1530 {
1531   gboolean res = TRUE;
1532   GstAviDemux *avi_demux = GST_AVI_DEMUX (gst_pad_get_parent (pad));
1533   avi_stream_context *stream;
1534   
1535   stream = gst_pad_get_element_private (pad);
1536
1537   switch (GST_EVENT_TYPE (event)) {
1538     case GST_EVENT_SEEK_SEGMENT:
1539       stream->end_pos = GST_EVENT_SEEK_ENDOFFSET (event);
1540     case GST_EVENT_SEEK:
1541       GST_DEBUG ("seek format %d, %08x", GST_EVENT_SEEK_FORMAT (event), stream->strh.type);
1542       switch (GST_EVENT_SEEK_FORMAT (event)) {
1543         case GST_FORMAT_BYTES:
1544         case GST_FORMAT_DEFAULT:
1545           break;
1546         case GST_FORMAT_TIME:
1547         {
1548           gst_avi_index_entry *seek_entry, *entry;
1549           gint64 desired_offset = GST_EVENT_SEEK_OFFSET (event);
1550           guint32 flags;
1551           guint64 min_index;
1552           
1553
1554           /* no seek on audio yet */
1555           if (stream->strh.type == GST_RIFF_FCC_auds) {
1556             res = FALSE;
1557             goto done;
1558           }
1559           GST_DEBUG ("seeking to %" G_GINT64_FORMAT, desired_offset);
1560
1561           flags = GST_RIFF_IF_KEYFRAME;
1562
1563           entry = gst_avi_demux_index_entry_for_time (avi_demux, stream->num, desired_offset, GST_RIFF_IF_KEYFRAME);
1564           if (entry) {
1565             desired_offset = entry->ts;
1566             min_index = gst_avi_demux_sync_streams (avi_demux, desired_offset);
1567             seek_entry = &avi_demux->index_entries[min_index];
1568             
1569             gst_avi_debug_entry ("syncing to entry", seek_entry);
1570             
1571             avi_demux->seek_offset = seek_entry->offset + avi_demux->index_offset;
1572             avi_demux->seek_pending = TRUE;
1573             avi_demux->last_seek = seek_entry->ts;
1574           }
1575           else {
1576             GST_DEBUG ("no index entry found for time %" G_GINT64_FORMAT, desired_offset);
1577             res = FALSE;
1578           }
1579           break;
1580         }
1581         default:
1582           res = FALSE;
1583           break;
1584       }
1585       break;
1586     default:
1587       res = FALSE;
1588       break;
1589   }
1590
1591 done:
1592   gst_event_unref (event);
1593
1594   return res;
1595 }
1596
1597 static gboolean
1598 gst_avi_demux_handle_sink_event (GstAviDemux *avi_demux)
1599 {
1600   guint32 remaining;
1601   GstEvent *event;
1602   GstEventType type;
1603   gboolean res = TRUE;
1604   
1605   gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
1606
1607   type = event? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
1608   GST_DEBUG ("avidemux: event %p %d", event, type); 
1609
1610   switch (type) {
1611     case GST_EVENT_EOS:
1612       gst_bytestream_flush (avi_demux->bs, remaining);
1613       gst_pad_event_default (avi_demux->sinkpad, event);
1614       res = FALSE;
1615       goto done;
1616     case GST_EVENT_FLUSH:
1617       g_warning ("flush event");
1618       break;
1619     case GST_EVENT_DISCONTINUOUS:
1620     {
1621       gint i;
1622       GstEvent *discont;
1623
1624       for (i = 0; i < avi_demux->num_streams; i++) {
1625         avi_stream_context *stream = &avi_demux->stream[i];
1626
1627         if (GST_PAD_IS_USABLE (stream->pad)) {
1628           GST_DEBUG ("sending discont on %d %" G_GINT64_FORMAT " + %" G_GINT64_FORMAT " = %" G_GINT64_FORMAT, 
1629                         i, avi_demux->last_seek, stream->delay, avi_demux->last_seek + stream->delay);
1630
1631           discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, 
1632                         avi_demux->last_seek + stream->delay , NULL);
1633
1634           gst_pad_push (stream->pad, GST_DATA (discont));
1635         }
1636       }
1637       break;
1638     }
1639     default:
1640       g_warning ("unhandled event %d", type);
1641       break;
1642   }
1643
1644   gst_event_unref (event);
1645
1646 done:
1647
1648   return res;
1649 }
1650
1651
1652 static void
1653 gst_avi_demux_loop (GstElement *element)
1654 {
1655   GstAviDemux *avi_demux;
1656   gst_riff_riff chunk;
1657   guint32 flush = 0;
1658   guint32 got_bytes;
1659   GstByteStream *bs;
1660   guint64 pos;
1661
1662   avi_demux = GST_AVI_DEMUX (element);
1663
1664   bs = avi_demux->bs;
1665
1666   if (avi_demux->seek_pending) {
1667     GST_DEBUG ("avidemux: seek pending to %" G_GINT64_FORMAT " %08llx", 
1668                   avi_demux->seek_offset, (unsigned long long)avi_demux->seek_offset);
1669
1670     if (!gst_bytestream_seek (avi_demux->bs, 
1671                               avi_demux->seek_offset, 
1672                               GST_SEEK_METHOD_SET)) 
1673     {
1674       GST_INFO ( "avidemux: could not seek");
1675     }
1676     avi_demux->seek_pending = FALSE;
1677   }
1678
1679   pos = gst_bytestream_tell (bs);
1680   do {
1681     gst_riff_riff *temp_chunk;
1682     guint8 *tempdata;
1683     guint32 skipsize;
1684
1685     /* read first two dwords to get chunktype and size */
1686     while (TRUE) {
1687       got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
1688       temp_chunk = (gst_riff_riff *) tempdata;
1689       if (got_bytes < sizeof (gst_riff_chunk)) {
1690         if (!gst_avi_demux_handle_sink_event (avi_demux))
1691           return;
1692       }
1693       else break;
1694     }
1695
1696     chunk.id = GUINT32_FROM_LE (temp_chunk->id);
1697     chunk.size = GUINT32_FROM_LE (temp_chunk->size);
1698
1699     switch (chunk.id) {
1700       case GST_RIFF_TAG_RIFF:
1701       case GST_RIFF_TAG_LIST:
1702         /* read complete list chunk */
1703         while (TRUE) {
1704           got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_list));
1705           temp_chunk = (gst_riff_riff *) tempdata;
1706           if (got_bytes < sizeof (gst_riff_list)) {
1707             if (!gst_avi_demux_handle_sink_event (avi_demux))
1708               return;
1709           }
1710           else break;
1711         }
1712         chunk.type = GUINT32_FROM_LE (temp_chunk->type);
1713         skipsize = sizeof (gst_riff_list);
1714         break;
1715       default:
1716         skipsize = sizeof (gst_riff_chunk);
1717         break;
1718     }
1719     gst_bytestream_flush_fast (bs, skipsize);
1720   } 
1721   while (FALSE);
1722
1723   /* need to flush an even number of bytes at the end */
1724   flush = (chunk.size + 1) & ~1;
1725
1726   switch (avi_demux->state) {
1727     case GST_AVI_DEMUX_START:
1728       if (chunk.id != GST_RIFF_TAG_RIFF && 
1729           chunk.type != GST_RIFF_RIFF_AVI) {
1730         gst_element_error (element, "This doesn't appear to be an AVI file %08x %08x", chunk.id, chunk.type);
1731         return;
1732       }
1733       avi_demux->state = GST_AVI_DEMUX_HEADER;
1734       /* we are not going to flush lists */
1735       flush = 0;
1736       break;
1737     case GST_AVI_DEMUX_HEADER:
1738       GST_DEBUG ("riff tag: %4.4s %08x", (gchar *)&chunk.id, chunk.size);
1739       switch (chunk.id) {
1740         case GST_RIFF_TAG_LIST:
1741           GST_DEBUG ("list type: %4.4s", (gchar *)&chunk.type);
1742           switch (chunk.type) {
1743             case GST_RIFF_LIST_movi:
1744             {
1745               guint64 filepos;
1746
1747               filepos = gst_bytestream_tell (bs);
1748
1749               gst_avi_demux_parse_index (avi_demux, filepos , chunk.size - 4);
1750               
1751               if (avi_demux->avih.bufsize) {
1752                 gst_bytestream_size_hint (avi_demux->bs, avi_demux->avih.bufsize);
1753               }
1754
1755               avi_demux->state = GST_AVI_DEMUX_MOVI;
1756               /* and tell the bastards that we have stream info too */
1757               gst_props_debug(avi_demux->streaminfo->properties);
1758               g_object_notify(G_OBJECT(avi_demux), "streaminfo");
1759               break;
1760             }
1761             case GST_RIFF_LIST_INFO:
1762               gst_avi_demux_metadata (avi_demux, chunk.size);
1763               break;
1764             default:
1765               break;
1766           }
1767           flush = 0;
1768           break;
1769         case GST_RIFF_TAG_avih:
1770           gst_avi_demux_avih (avi_demux);
1771           break;
1772         case GST_RIFF_TAG_strh:
1773           gst_avi_demux_strh (avi_demux);
1774           break;
1775         case GST_RIFF_TAG_strf:
1776           switch (avi_demux->fcc_type) {
1777             case GST_RIFF_FCC_vids:
1778               gst_avi_demux_strf_vids (avi_demux);
1779               break;
1780             case GST_RIFF_FCC_auds:
1781               gst_avi_demux_strf_auds (avi_demux);
1782               break;
1783             case GST_RIFF_FCC_iavs:
1784               gst_avi_demux_strf_iavs (avi_demux);
1785               break;
1786             case GST_RIFF_FCC_pads:
1787             case GST_RIFF_FCC_txts:
1788             default:
1789               GST_INFO ( "gst_avi_demux_chain: strh type %s not supported", 
1790                           gst_riff_id_to_fourcc (avi_demux->fcc_type));
1791               break;
1792           }
1793           break;
1794         case GST_RIFF_TAG_strn:
1795           gst_avi_demux_strn (avi_demux, chunk.size);
1796           break;
1797         case GST_RIFF_TAG_dmlh:
1798           gst_avi_demux_dmlh (avi_demux);
1799           break;
1800         case GST_RIFF_TAG_JUNK:
1801         case GST_RIFF_ISFT:
1802           break;
1803         default:
1804           GST_DEBUG ("  *****  unknown chunkid %08x", chunk.id);
1805           break;
1806       }
1807       break;
1808     case GST_AVI_DEMUX_MOVI:
1809       switch (chunk.id) {
1810         case GST_RIFF_00dc:
1811         case GST_RIFF_00db:
1812         case GST_RIFF_00__:
1813         case GST_RIFF_01wb:
1814         {
1815           gint stream_id;
1816           avi_stream_context *stream;
1817           gint64 next_ts;
1818           GstFormat format;
1819
1820           stream_id = CHUNKID_TO_STREAMNR (chunk.id);
1821                    
1822           stream = &avi_demux->stream[stream_id];
1823
1824           GST_LOG_OBJECT (avi_demux, "gst_avi_demux_chain: tag found %08x size %08x stream_id %d",
1825                     chunk.id, chunk.size, stream_id);
1826
1827           format = GST_FORMAT_TIME;
1828           gst_pad_query (stream->pad, GST_QUERY_POSITION, &format, &next_ts);
1829
1830           if (stream->strh.init_frames == stream->current_frame && stream->delay == 0)
1831             stream->delay = next_ts;
1832
1833           stream->current_frame++;
1834           stream->current_byte += chunk.size;
1835
1836           if (stream->skip) {
1837             stream->skip--;
1838           }
1839           else {
1840             if (GST_PAD_IS_USABLE (stream->pad)) {
1841               if (next_ts >= stream->end_pos) {
1842                 gst_pad_push (stream->pad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
1843                 GST_DEBUG ("end stream %d: %" G_GINT64_FORMAT " %d %" G_GINT64_FORMAT, 
1844                            stream_id, next_ts, stream->current_frame - 1,
1845                            stream->end_pos);
1846               }
1847               else {
1848                 GstBuffer *buf;
1849                 guint32   got_bytes;
1850
1851                 if (chunk.size) {
1852                   GstClockTime dur_ts;
1853                   got_bytes = gst_bytestream_peek (avi_demux->bs, &buf, chunk.size);
1854                   
1855                   GST_BUFFER_TIMESTAMP (buf) = next_ts;
1856
1857                   gst_pad_query (stream->pad, GST_QUERY_POSITION, &format, &dur_ts);
1858                   GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
1859
1860                   if (stream->need_flush) {
1861                     /* FIXME, do some flush event here */
1862                     stream->need_flush = FALSE;
1863                   }
1864                   GST_LOG_OBJECT (avi_demux, "send stream %d: %" 
1865                              G_GINT64_FORMAT " %d %" G_GINT64_FORMAT " %08x", 
1866                              stream_id, next_ts, stream->current_frame - 1,
1867                              stream->delay, chunk.size);
1868
1869                   gst_pad_push(stream->pad, GST_DATA (buf));
1870                 }
1871               }
1872             }
1873           }
1874           break;
1875         }
1876         default:
1877           GST_DEBUG ("  *****  unknown chunkid %08x", chunk.id);
1878           break;
1879       }
1880       break;
1881   }
1882
1883   while (flush) {
1884     gboolean res;
1885     
1886     res = gst_bytestream_flush (avi_demux->bs, flush);
1887     if (!res) {
1888       guint32 remaining;
1889       GstEvent *event;
1890
1891       gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
1892       gst_event_unref (event);
1893     }
1894     else
1895       break;
1896   }
1897 }
1898
1899 static GstElementStateReturn
1900 gst_avi_demux_change_state (GstElement *element)
1901 {
1902   GstAviDemux *avi_demux = GST_AVI_DEMUX (element);
1903
1904   switch (GST_STATE_TRANSITION (element)) {
1905     case GST_STATE_NULL_TO_READY:
1906       break;
1907     case GST_STATE_READY_TO_PAUSED:
1908       avi_demux->bs = gst_bytestream_new (avi_demux->sinkpad);
1909       avi_demux->last_seek = 0;
1910       avi_demux->state = GST_AVI_DEMUX_START;
1911       avi_demux->num_streams = 0;
1912       avi_demux->num_v_streams = 0;
1913       avi_demux->num_a_streams = 0;
1914       avi_demux->index_entries = NULL;
1915       avi_demux->index_size = 0;
1916       avi_demux->seek_pending = 0;
1917       avi_demux->metadata = NULL;
1918       gst_avi_demux_streaminfo(avi_demux);
1919       break;
1920     case GST_STATE_PAUSED_TO_PLAYING:
1921       break;
1922     case GST_STATE_PLAYING_TO_PAUSED:
1923       break;
1924     case GST_STATE_PAUSED_TO_READY:
1925       gst_bytestream_destroy (avi_demux->bs);
1926       gst_caps_replace (&avi_demux->metadata, NULL);
1927       gst_caps_replace (&avi_demux->streaminfo, NULL);
1928       break;
1929     case GST_STATE_READY_TO_NULL:
1930       break;
1931     default:
1932       break;
1933   }
1934
1935   parent_class->change_state (element);
1936
1937   return GST_STATE_SUCCESS;
1938 }
1939
1940 static void
1941 gst_avi_demux_get_property (GObject *object, guint prop_id, GValue *value,
1942                             GParamSpec *pspec)
1943 {
1944   GstAviDemux *src;
1945
1946   g_return_if_fail (GST_IS_AVI_DEMUX (object));
1947
1948   src = GST_AVI_DEMUX (object);
1949
1950   switch (prop_id) {
1951     case ARG_BITRATE:
1952       break;
1953     case ARG_METADATA:
1954       g_value_set_boxed(value, src->metadata);
1955       break;
1956     case ARG_STREAMINFO:
1957       g_value_set_boxed(value, src->streaminfo);
1958       break;
1959     default:
1960       break;
1961   }
1962 }
1963
1964 static gboolean
1965 plugin_init (GstPlugin *plugin)
1966 {
1967   if (!gst_library_load ("gstbytestream"))
1968     return FALSE;
1969   if (!gst_library_load ("gstriff"))
1970     return FALSE;
1971   if (!gst_library_load("gstvideo"))
1972     return FALSE;
1973
1974   GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux", 0, "Demuxer for AVI video");
1975   
1976   if (!gst_element_register (plugin, "avidemux", GST_RANK_PRIMARY,
1977         GST_TYPE_AVI_DEMUX)) {
1978     return FALSE;
1979   }
1980
1981   if (!gst_element_register (plugin, "avimux", GST_RANK_PRIMARY,
1982         GST_TYPE_AVIMUX)) {
1983     return FALSE;
1984   }
1985
1986   return TRUE;
1987 }
1988
1989
1990 GST_PLUGIN_DEFINE (
1991   GST_VERSION_MAJOR,
1992   GST_VERSION_MINOR,
1993   "avimux",
1994   "AVI stream handling",
1995   plugin_init,
1996   VERSION,
1997   GST_LICENSE,
1998   GST_PACKAGE,
1999   GST_ORIGIN
2000 )
2001