6bddcfe6f6826f84f8bd8c5dfedea7207c182205
[platform/upstream/gstreamer.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 #include <string.h>
23
24 #include "gstavidemux.h"
25
26
27 /* elementfactory information */
28 static GstElementDetails gst_avi_demux_details = {
29   ".avi parser",
30   "Parser/Video",
31   "Parse a .avi file into audio and video",
32   VERSION,
33   "Erik Walthinsen <omega@cse.ogi.edu>\n"
34   "Wim Taymans <wim.taymans@tvd.be>",
35   "(C) 1999",
36 };
37
38 static GstCaps* avi_typefind (GstBuffer *buf, gpointer private);
39
40 /* typefactory for 'avi' */
41 static GstTypeDefinition avidefinition = {
42   "avidemux_video/avi",
43   "video/avi",
44   ".avi",
45   avi_typefind,
46 };
47
48 /* AviDemux signals and args */
49 enum {
50   /* FILL ME */
51   LAST_SIGNAL
52 };
53
54 enum {
55   ARG_0,
56   ARG_BITRATE,
57   ARG_MEDIA_TIME,
58   ARG_CURRENT_TIME,
59   ARG_FRAME_RATE,
60   /* FILL ME */
61 };
62
63 GST_PADTEMPLATE_FACTORY (sink_templ,
64   "sink",
65   GST_PAD_SINK,
66   GST_PAD_ALWAYS,
67   GST_CAPS_NEW (
68     "avidemux_sink",
69      "video/avi",
70       "format",    GST_PROPS_STRING ("AVI")
71   )
72 )
73
74 GST_PADTEMPLATE_FACTORY (src_video_templ,
75   "video_[00-32]",
76   GST_PAD_SRC,
77   GST_PAD_SOMETIMES,
78   GST_CAPS_NEW (
79     "avidemux_src_video",
80     "video/avi",
81       "format",  GST_PROPS_LIST (
82                    GST_PROPS_STRING ("strf_vids"),
83                    GST_PROPS_STRING ("strf_iavs")
84                  ),
85       "width",   GST_PROPS_INT_RANGE (16, 4096),
86       "height",  GST_PROPS_INT_RANGE (16, 4096)
87
88   ),
89   GST_CAPS_NEW (
90     "avidemux_src_video",
91     "video/raw",
92       "format",  GST_PROPS_LIST (
93                    GST_PROPS_FOURCC (GST_MAKE_FOURCC('Y','U','Y','2')),
94                    GST_PROPS_FOURCC (GST_MAKE_FOURCC('I','4','2','0'))
95                  ),
96       "width",          GST_PROPS_INT_RANGE (16, 4096),
97       "height",         GST_PROPS_INT_RANGE (16, 4096)
98   ),
99   GST_CAPS_NEW (
100     "avidemux_src_video",
101     "video/jpeg",
102       "width",   GST_PROPS_INT_RANGE (16, 4096),
103       "height",  GST_PROPS_INT_RANGE (16, 4096)
104   ),
105   GST_CAPS_NEW (
106     "avidemux_src_video",
107     "video/dv",
108       "format",  GST_PROPS_LIST (
109                    GST_PROPS_STRING ("NTSC"),
110                    GST_PROPS_STRING ("PAL")
111                  ),
112       "width",   GST_PROPS_INT_RANGE (16, 4096),
113       "height",  GST_PROPS_INT_RANGE (16, 4096)
114   )
115 )
116
117 GST_PADTEMPLATE_FACTORY (src_audio_templ,
118   "audio_[00-32]",
119   GST_PAD_SRC,
120   GST_PAD_SOMETIMES,
121   GST_CAPS_NEW (
122     "avidemux_src_audio",
123     "video/avi",
124       "format",  GST_PROPS_STRING ("strf_auds")
125   ),
126   GST_CAPS_NEW (
127     "avidemux_src_audio",
128     "audio/raw",
129       "format",           GST_PROPS_STRING ("int"),
130       "law",              GST_PROPS_INT (0),
131       "endianness",       GST_PROPS_INT (G_BYTE_ORDER),
132       "signed",           GST_PROPS_LIST (
133                             GST_PROPS_BOOLEAN (TRUE),
134                             GST_PROPS_BOOLEAN (FALSE)
135                           ),
136       "width",            GST_PROPS_LIST (
137                             GST_PROPS_INT (8),
138                             GST_PROPS_INT (16)
139                           ),
140       "depth",            GST_PROPS_LIST (
141                             GST_PROPS_INT (8),
142                             GST_PROPS_INT (16)
143                           ),
144       "rate",             GST_PROPS_INT_RANGE (11025, 44100),
145       "channels",         GST_PROPS_INT_RANGE (1, 2)
146   ),
147   GST_CAPS_NEW (
148     "avidemux_src_audio",
149     "audio/mp3",
150       NULL
151   )
152 )
153
154 static void     gst_avi_demux_class_init        (GstAviDemuxClass *klass);
155 static void     gst_avi_demux_init              (GstAviDemux *avi_demux);
156
157 static void     gst_avi_demux_loop              (GstElement *element);
158
159 static GstElementStateReturn
160                 gst_avi_demux_change_state      (GstElement *element);
161
162 static void     gst_avi_demux_get_property      (GObject *object, guint prop_id,        
163                                                  GValue *value, GParamSpec *pspec);
164
165
166 static GstElementClass *parent_class = NULL;
167 /*static guint gst_avi_demux_signals[LAST_SIGNAL] = { 0 }; */
168
169 GType
170 gst_avi_demux_get_type(void) 
171 {
172   static GType avi_demux_type = 0;
173
174   if (!avi_demux_type) {
175     static const GTypeInfo avi_demux_info = {
176       sizeof(GstAviDemuxClass),      
177       NULL,
178       NULL,
179       (GClassInitFunc)gst_avi_demux_class_init,
180       NULL,
181       NULL,
182       sizeof(GstAviDemux),
183       0,
184       (GInstanceInitFunc)gst_avi_demux_init,
185     };
186     avi_demux_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviDemux", &avi_demux_info, 0);
187   }
188   return avi_demux_type;
189 }
190
191 static void
192 gst_avi_demux_class_init (GstAviDemuxClass *klass) 
193 {
194   GObjectClass *gobject_class;
195   GstElementClass *gstelement_class;
196
197   gobject_class = (GObjectClass*)klass;
198   gstelement_class = (GstElementClass*)klass;
199
200   g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_BITRATE,
201     g_param_spec_long ("bitrate","bitrate","bitrate",
202                        G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
203   g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_MEDIA_TIME,
204     g_param_spec_long ("media_time","media_time","media_time",
205                        G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
206   g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_CURRENT_TIME,
207     g_param_spec_long ("current_time","current_time","current_time",
208                        G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
209   g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_FRAME_RATE,
210     g_param_spec_int ("frame-rate","frame rate","Current (non-averaged) frame rate",
211                       0, G_MAXINT, 0, G_PARAM_READABLE));
212
213   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
214   
215   gobject_class->get_property = gst_avi_demux_get_property;
216   
217   gstelement_class->change_state = gst_avi_demux_change_state;
218 }
219
220 static void 
221 gst_avi_demux_init (GstAviDemux *avi_demux) 
222 {
223   guint i;
224
225   GST_FLAG_SET (avi_demux, GST_ELEMENT_EVENT_AWARE);
226                                 
227   avi_demux->sinkpad = gst_pad_new_from_template (
228                   GST_PADTEMPLATE_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   avi_demux->state = GST_AVI_DEMUX_UNKNOWN;
234   avi_demux->num_audio_pads = 0;
235   avi_demux->num_video_pads = 0;
236   /*avi_demux->next_time = 500000; */
237   avi_demux->next_time = 0;
238   avi_demux->init_audio = 0;
239   avi_demux->flags = 0;
240   avi_demux->index_entries = NULL;
241   avi_demux->index_size = 0;
242   avi_demux->resync_offset = 0;
243
244   /*GST_FLAG_SET( GST_OBJECT (avi_demux), GST_ELEMENT_NO_SEEK); */
245
246   for(i=0; i<GST_AVI_DEMUX_MAX_AUDIO_PADS; i++) 
247     avi_demux->audio_pad[i] = NULL;
248
249   for(i=0; i<GST_AVI_DEMUX_MAX_VIDEO_PADS; i++) 
250     avi_demux->video_pad[i] = NULL;
251
252 }
253
254 static GstCaps*
255 avi_typefind (GstBuffer *buf,
256               gpointer private)
257 {
258   gchar *data = GST_BUFFER_DATA (buf);
259   GstCaps *new;
260
261   GST_DEBUG (0,"avi_demux: typefind\n");
262
263   if (GUINT32_FROM_LE (((guint32 *)data)[0]) != GST_RIFF_TAG_RIFF)
264     return NULL;
265   if (GUINT32_FROM_LE (((guint32 *)data)[2]) != GST_RIFF_RIFF_AVI)
266     return NULL;
267
268   new = GST_CAPS_NEW ("avi_typefind",
269                       "video/avi", 
270                         "format", GST_PROPS_STRING ("AVI"));
271
272   return new;
273 }
274
275 static gboolean
276 gst_avi_demux_avih (GstAviDemux *avi_demux)
277 {
278   gst_riff_avih *avih;
279   GstByteStream *bs = avi_demux->bs;
280
281   avih = (gst_riff_avih *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_avih));
282   if (avih) {
283     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: avih tag found");
284     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  us_frame    %d", GUINT32_FROM_LE (avih->us_frame));
285     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  max_bps     %d", GUINT32_FROM_LE (avih->max_bps));
286     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  pad_gran    %d", GUINT32_FROM_LE (avih->pad_gran));
287     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  flags       0x%08x", GUINT32_FROM_LE (avih->flags));
288     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  tot_frames  %d", GUINT32_FROM_LE (avih->tot_frames));
289     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  init_frames %d", GUINT32_FROM_LE (avih->init_frames));
290     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  streams     %d", GUINT32_FROM_LE (avih->streams));
291     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  bufsize     %d", GUINT32_FROM_LE (avih->bufsize));
292     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  width       %d", GUINT32_FROM_LE (avih->width));
293     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  height      %d", GUINT32_FROM_LE (avih->height));
294     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  scale       %d", GUINT32_FROM_LE (avih->scale));
295     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  rate        %d", GUINT32_FROM_LE (avih->rate));
296     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  start       %d", GUINT32_FROM_LE (avih->start));
297     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  length      %d", GUINT32_FROM_LE (avih->length));
298
299     avi_demux->time_interval = GUINT32_FROM_LE (avih->us_frame);
300     avi_demux->tot_frames = GUINT32_FROM_LE (avih->tot_frames);
301     avi_demux->flags = GUINT32_FROM_LE (avih->flags);
302
303     return TRUE;
304   }
305   return FALSE;
306 }
307
308 static gboolean 
309 gst_avi_demux_strh (GstAviDemux *avi_demux)
310 {
311   gst_riff_strh *strh;
312   GstByteStream *bs = avi_demux->bs;
313
314   strh = (gst_riff_strh *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_strh));
315   if (strh) {
316     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strh tag found");
317     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  type        0x%08x (%s)", 
318                   GUINT32_FROM_LE (strh->type), gst_riff_id_to_fourcc (strh->type));
319     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  fcc_handler 0x%08x (%s)", 
320                   GUINT32_FROM_LE (strh->fcc_handler), gst_riff_id_to_fourcc (strh->fcc_handler));
321     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  flags       0x%08x", GUINT32_FROM_LE (strh->flags));
322     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  priority    %d", GUINT32_FROM_LE (strh->priority));
323     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  init_frames %d", GUINT32_FROM_LE (strh->init_frames));
324     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  scale       %d", GUINT32_FROM_LE (strh->scale));
325     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  rate        %d", GUINT32_FROM_LE (strh->rate));
326     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  start       %d", GUINT32_FROM_LE (strh->start));
327     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  length      %d", GUINT32_FROM_LE (strh->length));
328     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  bufsize     %d", GUINT32_FROM_LE (strh->bufsize));
329     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  quality     %d", GUINT32_FROM_LE (strh->quality));
330     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  samplesize  %d", GUINT32_FROM_LE (strh->samplesize));
331
332     avi_demux->fcc_type = GUINT32_FROM_LE (strh->type);
333     if (strh->type == GST_RIFF_FCC_auds) {
334       guint32 scale;
335       
336       scale = GUINT32_FROM_LE (strh->scale);
337       avi_demux->init_audio = GUINT32_FROM_LE (strh->init_frames);
338       if (!scale)
339         scale = 1;
340       avi_demux->audio_rate = GUINT32_FROM_LE (strh->rate) / scale;
341     }
342     else if (strh->type == GST_RIFF_FCC_vids) {
343       guint32 scale;
344       
345       scale = GUINT32_FROM_LE (strh->scale);
346       if (!scale)
347         scale = 1;
348       avi_demux->frame_rate = (gint) GUINT32_FROM_LE (strh->rate) / scale;
349       g_object_notify (G_OBJECT (avi_demux), "frame-rate");
350     }
351
352     return TRUE;
353   }
354   return FALSE;
355 }
356
357 static void 
358 gst_avi_demux_strf_vids (GstAviDemux *avi_demux)
359 {
360   gst_riff_strf_vids *strf;
361   GstPad *srcpad;
362   GstByteStream *bs = avi_demux->bs;
363   GstCaps *newcaps = NULL, *capslist = NULL;
364
365   strf = (gst_riff_strf_vids *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_strf_vids));
366
367   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context vids");
368   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  size        %d", GUINT32_FROM_LE (strf->size));
369   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  width       %d", GUINT32_FROM_LE (strf->width));
370   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  height      %d", GUINT32_FROM_LE (strf->height));
371   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  planes      %d", GUINT16_FROM_LE (strf->planes));
372   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  bit_cnt     %d", GUINT16_FROM_LE (strf->bit_cnt));
373   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  compression 0x%08x (%s)", 
374                   GUINT32_FROM_LE (strf->compression), gst_riff_id_to_fourcc (strf->compression));
375   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  image_size  %d", GUINT32_FROM_LE (strf->image_size));
376   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  xpels_meter %d", GUINT32_FROM_LE (strf->xpels_meter));
377   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  ypels_meter %d", GUINT32_FROM_LE (strf->ypels_meter));
378   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  num_colors  %d", GUINT32_FROM_LE (strf->num_colors));
379   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  imp_colors  %d", GUINT32_FROM_LE (strf->imp_colors));
380
381   srcpad =  gst_pad_new_from_template (
382                   GST_PADTEMPLATE_GET (src_video_templ), g_strdup_printf ("video_%02d", 
383                           avi_demux->num_video_pads));
384
385   capslist = gst_caps_append(NULL, GST_CAPS_NEW (
386                           "avidemux_video_src",
387                           "video/avi",
388                             "format",           GST_PROPS_STRING ("strf_vids"),
389                               "size",           GST_PROPS_INT (GUINT32_FROM_LE (strf->size)),
390                               "width",          GST_PROPS_INT (GUINT32_FROM_LE (strf->width)),
391                               "height",         GST_PROPS_INT (GUINT32_FROM_LE (strf->height)),
392                               "planes",         GST_PROPS_INT (GUINT16_FROM_LE (strf->planes)),
393                               "bit_cnt",        GST_PROPS_INT (GUINT16_FROM_LE (strf->bit_cnt)),
394                               "compression",    GST_PROPS_FOURCC (GUINT32_FROM_LE (strf->compression)),
395                               "image_size",     GST_PROPS_INT (GUINT32_FROM_LE (strf->image_size)),
396                               "xpels_meter",    GST_PROPS_INT (GUINT32_FROM_LE (strf->xpels_meter)),
397                               "ypels_meter",    GST_PROPS_INT (GUINT32_FROM_LE (strf->ypels_meter)),
398                               "num_colors",     GST_PROPS_INT (GUINT32_FROM_LE (strf->num_colors)),
399                               "imp_colors",     GST_PROPS_INT (GUINT32_FROM_LE (strf->imp_colors))
400                               ));
401
402   /* let's try some gstreamer-like mime-type caps */
403   switch (GUINT32_FROM_LE(strf->compression))
404   {
405     case GST_MAKE_FOURCC('I','4','2','0'):
406     case GST_MAKE_FOURCC('Y','U','Y','2'):
407       newcaps = GST_CAPS_NEW (
408                   "avidemux_video_src",
409                   "video/raw",
410                     "format",  GST_PROPS_FOURCC(GUINT32_FROM_LE(strf->compression)),
411                     "width",   GST_PROPS_INT(strf->width),
412                     "height",  GST_PROPS_INT(strf->height)
413                 );
414       break;
415     case GST_MAKE_FOURCC('M','J','P','G'):
416       newcaps = GST_CAPS_NEW (
417                   "avidemux_video_src",
418                   "video/jpeg",
419                     "width",   GST_PROPS_INT(strf->width),
420                     "height",  GST_PROPS_INT(strf->height)
421                 );
422       break;
423     case GST_MAKE_FOURCC('d','v','s','d'):
424       newcaps = GST_CAPS_NEW (
425                   "avidemux_video_src",
426                   "video/dv",
427                     "format",  GST_PROPS_STRING("NTSC"), /* FIXME??? */
428                     "width",   GST_PROPS_INT(strf->width),
429                     "height",  GST_PROPS_INT(strf->height)
430                 );
431       break;
432   }
433
434   if (newcaps) capslist = gst_caps_append(capslist, newcaps);
435
436   gst_pad_try_set_caps(srcpad, capslist);
437
438   avi_demux->video_pad[avi_demux->num_video_pads++] = srcpad;
439   gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
440 }
441
442 static void 
443 gst_avi_demux_strf_auds (GstAviDemux *avi_demux)
444 {
445   gst_riff_strf_auds *strf;
446   GstPad *srcpad;
447   GstByteStream *bs = avi_demux->bs;
448   GstCaps *newcaps = NULL, *capslist = NULL;
449
450   strf = (gst_riff_strf_auds *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_strf_auds));
451
452   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context auds");
453   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  format      %d", GUINT16_FROM_LE (strf->format));
454   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  channels    %d", GUINT16_FROM_LE (strf->channels));
455   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  rate        %d", GUINT32_FROM_LE (strf->rate));
456   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  av_bps      %d", GUINT32_FROM_LE (strf->av_bps));
457   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  blockalign  %d", GUINT16_FROM_LE (strf->blockalign));
458   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  size        %d", GUINT16_FROM_LE (strf->size));
459
460   srcpad =  gst_pad_new_from_template (
461                   GST_PADTEMPLATE_GET (src_audio_templ), g_strdup_printf ("audio_%02d", 
462                           avi_demux->num_audio_pads));
463
464   capslist = gst_caps_append(NULL, GST_CAPS_NEW (
465                           "avidemux_audio_src",
466                           "video/avi",
467                             "format",           GST_PROPS_STRING ("strf_auds"),
468                               "fmt",            GST_PROPS_INT (GUINT16_FROM_LE (strf->format)),
469                               "channels",       GST_PROPS_INT (GUINT16_FROM_LE (strf->channels)),
470                               "rate",           GST_PROPS_INT (GUINT32_FROM_LE (strf->rate)),
471                               "av_bps",         GST_PROPS_INT (GUINT32_FROM_LE (strf->av_bps)),
472                               "blockalign",     GST_PROPS_INT (GUINT16_FROM_LE (strf->blockalign)),
473                               "size",           GST_PROPS_INT (GUINT16_FROM_LE (strf->size))
474                           ));
475
476   /* let's try some gstreamer-formatted mime types */
477   switch (GUINT16_FROM_LE(strf->format))
478   {
479     case 0x0050:
480     case 0x0055: /* mp3 */
481       newcaps = gst_caps_new ("avidemux_audio_src",
482                               "audio/mp3",
483                                 NULL);
484       break;
485     case 0x0001: /* PCM/wav */
486       newcaps = gst_caps_new ("avidemux_audio_src",
487                               "audio/raw",
488                               gst_props_new (
489                                 "format",     GST_PROPS_STRING ("int"),
490                                 "law",        GST_PROPS_INT (0),
491                                 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
492                                 "signed",     GST_PROPS_BOOLEAN ((GUINT16_FROM_LE (strf->size) != 8)),
493                                 "width",      GST_PROPS_INT ((GUINT16_FROM_LE (strf->blockalign)*8) /
494                                                                 GUINT16_FROM_LE (strf->channels)),
495                                 "depth",      GST_PROPS_INT (GUINT16_FROM_LE (strf->size)),
496                                 "rate",       GST_PROPS_INT (GUINT32_FROM_LE (strf->rate)),
497                                 "channels",   GST_PROPS_INT (GUINT16_FROM_LE (strf->channels)),
498                                 NULL
499                               ));
500       break;
501   }
502
503   if (newcaps) capslist = gst_caps_append(capslist, newcaps);
504
505   gst_pad_try_set_caps(srcpad, capslist);
506
507   avi_demux->audio_pad[avi_demux->num_audio_pads++] = srcpad;
508   gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
509 }
510
511 static void 
512 gst_avi_demux_strf_iavs (GstAviDemux *avi_demux)
513 {
514   gst_riff_strf_iavs *strf;
515   GstPad *srcpad;
516   GstByteStream *bs = avi_demux->bs;
517   GstCaps *newcaps = NULL, *capslist = NULL;
518
519   strf = (gst_riff_strf_iavs *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_strf_iavs));
520
521   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context iavs");
522   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxSrc   %08x", GUINT32_FROM_LE (strf->DVAAuxSrc));
523   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxCtl   %08x", GUINT32_FROM_LE (strf->DVAAuxCtl));
524   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxSrc1  %08x", GUINT32_FROM_LE (strf->DVAAuxSrc1));
525   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxCtl1  %08x", GUINT32_FROM_LE (strf->DVAAuxCtl1));
526   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVVAuxSrc   %08x", GUINT32_FROM_LE (strf->DVVAuxSrc));
527   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVVAuxCtl   %08x", GUINT32_FROM_LE (strf->DVVAuxCtl));
528   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVReserved1 %08x", GUINT32_FROM_LE (strf->DVReserved1));
529   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVReserved2 %08x", GUINT32_FROM_LE (strf->DVReserved2));
530
531   srcpad =  gst_pad_new_from_template (
532                   GST_PADTEMPLATE_GET (src_video_templ), g_strdup_printf ("video_%02d", 
533                           avi_demux->num_video_pads));
534
535   capslist = gst_caps_append(NULL, GST_CAPS_NEW (
536                           "avidemux_video_src",
537                           "video/avi",
538                             "format",           GST_PROPS_STRING ("strf_iavs"),
539                               "DVAAuxSrc",      GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxSrc)),
540                               "DVAAuxCtl",      GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxCtl)),
541                               "DVAAuxSrc1",     GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxSrc1)),
542                               "DVAAuxCtl1",     GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxCtl1)),
543                               "DVVAuxSrc",      GST_PROPS_INT (GUINT32_FROM_LE (strf->DVVAuxSrc)),
544                               "DVVAuxCtl",      GST_PROPS_INT (GUINT32_FROM_LE (strf->DVVAuxCtl)),
545                               "DVReserved1",    GST_PROPS_INT (GUINT32_FROM_LE (strf->DVReserved1)),
546                               "DVReserved2",    GST_PROPS_INT (GUINT32_FROM_LE (strf->DVReserved2))
547                          ));
548
549   newcaps = gst_caps_new ("avi_type_dv", 
550                           "video/dv", 
551                           gst_props_new (
552                             "format",           GST_PROPS_STRING ("NTSC"), /* FIXME??? */
553                             NULL));
554
555   if (newcaps) capslist = gst_caps_append(capslist, newcaps);
556
557   gst_pad_try_set_caps(srcpad, capslist);
558
559   avi_demux->video_pad[avi_demux->num_video_pads++] = srcpad;
560   gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
561 }
562
563 static void
564 gst_avidemux_parse_index (GstAviDemux *avi_demux,
565                           gulong filepos, gulong offset)
566 {
567   GstBuffer *buf;
568   gulong index_size;
569
570   if (!gst_bytestream_seek (avi_demux->bs, GST_SEEK_BYTEOFFSET_SET, filepos + offset)) {
571     GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek to index");
572     return;
573   }
574   buf = gst_bytestream_read (avi_demux->bs, 8);
575   while (!buf) {
576     guint32 remaining;
577     GstEvent *event;
578   
579     gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
580
581     buf = gst_bytestream_read (avi_demux->bs, 8);
582   }
583                   
584   if (GST_BUFFER_OFFSET (buf) != filepos + offset || GST_BUFFER_SIZE (buf) != 8) {
585     GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not get index");
586     return;
587   }
588
589   if (gst_riff_fourcc_to_id (GST_BUFFER_DATA (buf)) != GST_RIFF_TAG_idx1) {
590     GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: no index found");
591     return;
592   }
593
594   index_size = GUINT32_FROM_LE(*(guint32 *)(GST_BUFFER_DATA (buf) + 4));
595   gst_buffer_unref (buf);
596
597   buf = gst_bytestream_read (avi_demux->bs, index_size);
598
599   avi_demux->index_size = index_size/sizeof(gst_riff_index_entry);
600
601   GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: index size %lu", avi_demux->index_size);
602
603   avi_demux->index_entries = g_malloc (GST_BUFFER_SIZE (buf));
604   memcpy (avi_demux->index_entries, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
605   gst_buffer_unref (buf);
606
607   if (!gst_bytestream_seek (avi_demux->bs, GST_SEEK_BYTEOFFSET_SET, filepos)) {
608     GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek back to movi");
609     return;
610   }
611 }
612
613 static gboolean
614 gst_avidemux_handle_event (GstAviDemux *avi_demux)
615 {
616   guint32 remaining;
617   GstEvent *event;
618   GstEventType type;
619   
620   gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
621
622   type = event? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
623
624   switch (type) {
625     case GST_EVENT_EOS:
626       gst_pad_event_default (avi_demux->sinkpad, event);
627       break;
628     case GST_EVENT_SEEK:
629       g_warning ("seek event\n");
630       break;
631     case GST_EVENT_FLUSH:
632       g_warning ("flush event\n");
633       break;
634     case GST_EVENT_DISCONTINUOUS:
635       g_warning ("discont event\n");
636       break;
637     default:
638       g_warning ("unhandled event %d\n", type);
639       break;
640   }
641
642   return TRUE;
643 }
644
645 static inline gboolean 
646 gst_avidemux_read_chunk (GstAviDemux *avi_demux, guint32 *id, guint32 *size)
647 {
648   gst_riff_chunk *chunk;
649   GstByteStream *bs = avi_demux->bs;
650
651   do {
652     chunk = (gst_riff_chunk *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_chunk));
653     if (chunk) {
654       *id =   GUINT32_FROM_LE (chunk->id);
655       *size = GUINT32_FROM_LE (chunk->size);
656
657       gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
658
659       return TRUE;
660     }
661   } while (gst_avidemux_handle_event (avi_demux));
662
663   return TRUE;
664 }
665
666 static gboolean
667 gst_avidemux_process_chunk (GstAviDemux *avi_demux, guint64 *filepos,
668                              guint32 desired_tag,
669                              gint rec_depth, guint32 *chunksize)
670 {
671   guint32 chunkid;      
672   GstByteStream *bs = avi_demux->bs;
673
674   if (!gst_avidemux_read_chunk (avi_demux, &chunkid, chunksize)) {
675     g_print ("  *****  Error reading chunk at filepos 0x%08llx\n", *filepos);
676     return FALSE;
677   }
678   if (desired_tag) {            /* do we have to test identity? */
679     if (desired_tag != chunkid) {
680       g_print ("\n\n *** Error: Expected chunk '%s', found '%s'\n",
681               gst_riff_id_to_fourcc (desired_tag),
682               gst_riff_id_to_fourcc (chunkid));
683       return FALSE;
684     }
685   }
686
687   GST_INFO (GST_CAT_PLUGIN_INFO, "chunkid %s, size %08x, filepos %08llx", 
688                   gst_riff_id_to_fourcc (chunkid), *chunksize, *filepos);
689
690   *filepos += (sizeof (guint32) + sizeof (guint32));
691
692   switch (chunkid) {
693     case GST_RIFF_TAG_RIFF:
694     case GST_RIFF_TAG_LIST:
695     {
696       guint32 datashowed;
697       guint32 subchunksize = 0; /* size of a read subchunk             */
698       gchar *formtype;
699
700       formtype = gst_bytestream_peek_bytes (bs, sizeof (guint32));
701       if (!formtype)
702         return FALSE;
703
704       switch (GUINT32_FROM_LE (*((guint32*)formtype))) {
705         case GST_RIFF_LIST_movi:
706           gst_avidemux_parse_index (avi_demux, *filepos, *chunksize);
707           while (!gst_bytestream_flush (bs, sizeof (guint32))) {
708             guint32 remaining;
709             GstEvent *event;
710
711             gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
712           }
713           break;
714         default:
715           /* flush the form type */
716           gst_bytestream_flush_fast (bs, sizeof (guint32));
717           break;
718       }
719
720       datashowed = sizeof (guint32);    /* we showed the form type      */
721       *filepos += datashowed;   /* for the rest of the routine  */
722
723       while (datashowed < *chunksize) { /* while not showed all: */
724
725         GST_INFO (GST_CAT_PLUGIN_INFO, "process chunk filepos %08llx", *filepos);
726         /* recurse for subchunks of RIFF and LIST chunks: */
727         if (!gst_avidemux_process_chunk (avi_demux, filepos, 0,
728                            rec_depth + 1, &subchunksize))
729           return FALSE;
730
731         subchunksize = ((subchunksize + 1) & ~1);
732
733         datashowed += (sizeof (guint32) + sizeof (guint32) + subchunksize);
734         GST_INFO (GST_CAT_PLUGIN_INFO, "process chunk done filepos %08llx, subchunksize %08x", 
735                         *filepos, subchunksize);
736       }
737       if (datashowed != *chunksize) {
738         g_warning ("error parsing AVI");
739       }
740       goto done;
741     }
742     case GST_RIFF_TAG_avih:
743       gst_avi_demux_avih (avi_demux);
744       break;
745     case GST_RIFF_TAG_strh:
746     {
747       gst_avi_demux_strh (avi_demux);
748       break;
749     }
750     case GST_RIFF_TAG_strf:
751       switch (avi_demux->fcc_type) {
752         case GST_RIFF_FCC_vids:
753           gst_avi_demux_strf_vids (avi_demux);
754           break;
755         case GST_RIFF_FCC_auds:
756           gst_avi_demux_strf_auds (avi_demux);
757           break;
758         case GST_RIFF_FCC_iavs:
759           gst_avi_demux_strf_iavs (avi_demux);
760           break;
761         case GST_RIFF_FCC_pads:
762         case GST_RIFF_FCC_txts:
763         default:
764           GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux_chain: strh type %s not supported", gst_riff_id_to_fourcc (avi_demux->fcc_type));
765           break;
766       }
767       break;
768     case GST_RIFF_00dc:
769     case GST_RIFF_00db:
770     case GST_RIFF_00__:
771     {
772       GST_DEBUG (0,"gst_avi_demux_chain: tag found %08x size %08x\n",
773                     chunkid, *chunksize);
774
775       if (GST_PAD_IS_CONNECTED (avi_demux->video_pad[0])) {
776         GstBuffer *buf;
777
778         if (*chunksize) {
779           buf = gst_bytestream_peek (bs, *chunksize);
780
781           GST_BUFFER_TIMESTAMP (buf) = avi_demux->next_time;
782
783           avi_demux->next_time += avi_demux->time_interval;
784
785           if (avi_demux->video_need_flush[0]) {
786              /* FIXME, do some flush event here */
787             avi_demux->video_need_flush[0] = FALSE;
788           }
789
790           GST_DEBUG (0,"gst_avi_demux_chain: send video buffer %08x\n", *chunksize);
791           gst_pad_push(avi_demux->video_pad[0], buf);
792           GST_DEBUG (0,"gst_avi_demux_chain: sent video buffer %08x %p\n",
793                       *chunksize, &avi_demux->video_pad[0]);
794           avi_demux->current_frame++;
795         }
796       }
797       *chunksize = (*chunksize + 1) & ~1;
798       break;
799     }
800     case GST_RIFF_01wb:
801     {
802       GST_DEBUG (0,"gst_avi_demux_chain: tag found %08x size %08x\n",
803                     chunkid, *chunksize);
804
805       if (avi_demux->init_audio) {
806         /*avi_demux->next_time += (*chunksize) * 1000000LL / avi_demux->audio_rate; */
807         avi_demux->init_audio--;
808       }
809
810       if (GST_PAD_IS_CONNECTED (avi_demux->audio_pad[0])) {
811         GstBuffer *buf;
812
813         if (*chunksize) {
814           buf = gst_bytestream_peek (bs, *chunksize);
815
816           GST_BUFFER_TIMESTAMP (buf) = -1LL;
817
818           if (avi_demux->audio_need_flush[0]) {
819             GST_DEBUG (0,"audio flush\n");
820             avi_demux->audio_need_flush[0] = FALSE;
821             /* FIXME, do some flush event here */
822           }
823
824           GST_DEBUG (0,"gst_avi_demux_chain: send audio buffer %08x\n", *chunksize);
825           gst_pad_push (avi_demux->audio_pad[0], buf);
826           GST_DEBUG (0,"gst_avi_demux_chain: sent audio buffer %08x\n", *chunksize);
827         }
828       }
829       *chunksize = (*chunksize + 1) & ~1;
830       break;
831     }
832     default:
833       GST_DEBUG (0, "  *****  unknown chunkid %08x (%s)\n", chunkid, gst_riff_id_to_fourcc (chunkid));
834       *chunksize = (*chunksize + 1) & ~1;
835       break;
836   }
837   GST_INFO (GST_CAT_PLUGIN_INFO, "chunkid %s, flush %08x, filepos %08llx", 
838                   gst_riff_id_to_fourcc (chunkid), *chunksize, *filepos);
839
840   *filepos += *chunksize;
841   if (!gst_bytestream_flush (bs, *chunksize)) {
842     return gst_avidemux_handle_event (avi_demux);
843   }
844
845 done:
846   /* we are running in an infinite loop, we need to _yield 
847    * from time to time */
848   gst_element_yield (GST_ELEMENT (avi_demux));
849
850   return TRUE;
851 }
852
853 static void
854 gst_avi_demux_loop (GstElement *element)
855 {
856   GstAviDemux *avi_demux;
857   guint32 chunksize;
858   guint64 filepos = 0;
859
860   g_return_if_fail (element != NULL);
861   g_return_if_fail (GST_IS_AVI_DEMUX (element));
862
863   avi_demux = GST_AVI_DEMUX (element);
864
865   /* this is basically an infinite loop */
866   if (!gst_avidemux_process_chunk (avi_demux, &filepos, GST_RIFF_TAG_RIFF, 0, &chunksize)) {
867     gst_element_error (element, "This doesn't appear to be an AVI file");
868     return;
869   }
870   /* if we exit the loop we are EOS */
871   gst_pad_event_default (avi_demux->sinkpad, gst_event_new (GST_EVENT_EOS));
872 }
873
874 static GstElementStateReturn
875 gst_avi_demux_change_state (GstElement *element)
876 {
877   GstAviDemux *avi_demux = GST_AVI_DEMUX (element);
878
879   switch (GST_STATE_TRANSITION (element)) {
880     case GST_STATE_NULL_TO_READY:
881       break;
882     case GST_STATE_READY_TO_PAUSED:
883       avi_demux->bs = gst_bytestream_new (avi_demux->sinkpad);
884       break;
885     case GST_STATE_PAUSED_TO_PLAYING:
886       break;
887     case GST_STATE_PLAYING_TO_PAUSED:
888       break;
889     case GST_STATE_PAUSED_TO_READY:
890       gst_bytestream_destroy (avi_demux->bs);
891       break;
892     case GST_STATE_READY_TO_NULL:
893       break;
894     default:
895       break;
896   }
897
898   parent_class->change_state (element);
899
900   return GST_STATE_SUCCESS;
901 }
902
903 static void
904 gst_avi_demux_get_property (GObject *object, guint prop_id, GValue *value,
905                             GParamSpec *pspec)
906 {
907   GstAviDemux *src;
908
909   g_return_if_fail (GST_IS_AVI_DEMUX (object));
910
911   src = GST_AVI_DEMUX (object);
912
913   switch (prop_id) {
914     case ARG_BITRATE:
915       break;
916     case ARG_MEDIA_TIME:
917       g_value_set_long (value, (src->tot_frames * src->time_interval) / 1000000);
918       break;
919     case ARG_CURRENT_TIME:
920       g_value_set_long (value, (src->current_frame * src->time_interval) / 1000000);
921       break;
922     case ARG_FRAME_RATE:
923       g_value_set_int (value, (src->frame_rate));
924       break;
925     default:
926       break;
927   }
928 }
929
930 static gboolean
931 plugin_init (GModule *module, GstPlugin *plugin)
932 {
933   GstElementFactory *factory;
934   GstTypeFactory *type;
935
936   /* this filter needs the riff parser */
937   if (!gst_library_load ("gstbytestream")) {
938     gst_info("avidemux: could not load support library: 'gstbytestream'\n");
939     return FALSE;
940   }
941   if (!gst_library_load ("gstriff")) {
942     gst_info("avidemux: could not load support library: 'gstriff'\n");
943     return FALSE;
944   }
945
946   /* create an elementfactory for the avi_demux element */
947   factory = gst_elementfactory_new ("avidemux",GST_TYPE_AVI_DEMUX,
948                                     &gst_avi_demux_details);
949   g_return_val_if_fail (factory != NULL, FALSE);
950
951   gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_audio_templ));
952   gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_video_templ));
953   gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sink_templ));
954
955   type = gst_typefactory_new (&avidefinition);
956   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type));
957
958   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
959
960   return TRUE;
961 }
962
963 GstPluginDesc plugin_desc = {
964   GST_VERSION_MAJOR,
965   GST_VERSION_MINOR,
966   "avidemux",
967   plugin_init
968 };
969