Replace audio/mp3 with audio/x-mp3 and audio/x-flac with application/x-flac
[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 #include <string.h>
23
24 #include "gstavidemux.h"
25
26
27 /* elementfactory information */
28 static GstElementDetails gst_avi_demux_details = {
29   "Avi demuxer",
30   "Codec/Demuxer",
31   "LGPL",
32   "Demultiplex an avi file into audio and video",
33   VERSION,
34   "Erik Walthinsen <omega@cse.ogi.edu>\n"
35   "Wim Taymans <wim.taymans@tvd.be>",
36   "(C) 1999",
37 };
38
39 static GstCaps* avi_type_find (GstBuffer *buf, gpointer private);
40
41 /* typefactory for 'avi' */
42 static GstTypeDefinition avidefinition = {
43   "avidemux_video/avi",
44   "video/avi",
45   ".avi",
46   avi_type_find,
47 };
48
49 /* AviDemux signals and args */
50 enum {
51   /* FILL ME */
52   LAST_SIGNAL
53 };
54
55 enum {
56   ARG_0,
57   ARG_BITRATE,
58   /* FILL ME */
59 };
60
61 GST_PAD_TEMPLATE_FACTORY (sink_templ,
62   "sink",
63   GST_PAD_SINK,
64   GST_PAD_ALWAYS,
65   GST_CAPS_NEW (
66     "avidemux_sink",
67      "video/avi",
68       "format",    GST_PROPS_STRING ("AVI")
69   )
70 )
71
72 GST_PAD_TEMPLATE_FACTORY (src_video_templ,
73   "video_%02d",
74   GST_PAD_SRC,
75   GST_PAD_SOMETIMES,
76   GST_CAPS_NEW (
77     "avidemux_src_video",
78     "video/avi",
79       "format",  GST_PROPS_LIST (
80                    GST_PROPS_STRING ("strf_vids"),
81                    GST_PROPS_STRING ("strf_iavs")
82                  ),
83       "width",   GST_PROPS_INT_RANGE (16, 4096),
84       "height",  GST_PROPS_INT_RANGE (16, 4096)
85
86   ),
87   GST_CAPS_NEW (
88     "avidemux_src_video",
89     "video/raw",
90       "format",  GST_PROPS_LIST (
91                    GST_PROPS_FOURCC (GST_MAKE_FOURCC('Y','U','Y','2')),
92                    GST_PROPS_FOURCC (GST_MAKE_FOURCC('I','4','2','0'))
93                  ),
94       "width",          GST_PROPS_INT_RANGE (16, 4096),
95       "height",         GST_PROPS_INT_RANGE (16, 4096)
96   ),
97   GST_CAPS_NEW (
98     "avidemux_src_video",
99     "video/jpeg",
100       "width",   GST_PROPS_INT_RANGE (16, 4096),
101       "height",  GST_PROPS_INT_RANGE (16, 4096)
102   ),
103   GST_CAPS_NEW (
104     "avidemux_src_video",
105     "video/dv",
106       "format",  GST_PROPS_LIST (
107                    GST_PROPS_STRING ("NTSC"),
108                    GST_PROPS_STRING ("PAL")
109                  ),
110       "width",   GST_PROPS_INT_RANGE (16, 4096),
111       "height",  GST_PROPS_INT_RANGE (16, 4096)
112   )
113 )
114
115 GST_PAD_TEMPLATE_FACTORY (src_audio_templ,
116   "audio_%02d",
117   GST_PAD_SRC,
118   GST_PAD_SOMETIMES,
119   GST_CAPS_NEW (
120     "avidemux_src_audio",
121     "video/avi",
122       "format",  GST_PROPS_STRING ("strf_auds")
123   ),
124   GST_CAPS_NEW (
125     "avidemux_src_audio",
126     "audio/raw",
127       "format",           GST_PROPS_STRING ("int"),
128       "law",              GST_PROPS_INT (0),
129       "endianness",       GST_PROPS_INT (G_BYTE_ORDER),
130       "signed",           GST_PROPS_LIST (
131                             GST_PROPS_BOOLEAN (TRUE),
132                             GST_PROPS_BOOLEAN (FALSE)
133                           ),
134       "width",            GST_PROPS_LIST (
135                             GST_PROPS_INT (8),
136                             GST_PROPS_INT (16)
137                           ),
138       "depth",            GST_PROPS_LIST (
139                             GST_PROPS_INT (8),
140                             GST_PROPS_INT (16)
141                           ),
142       "rate",             GST_PROPS_INT_RANGE (11025, 44100),
143       "channels",         GST_PROPS_INT_RANGE (1, 2)
144   ),
145   GST_CAPS_NEW (
146     "avidemux_src_audio",
147     "audio/x-mp3",
148       NULL
149   ),
150   GST_CAPS_NEW (
151     "avidemux_src_audio",
152     "application/x-ogg",
153     NULL
154   )
155 )
156
157 static void             gst_avi_demux_class_init                (GstAviDemuxClass *klass);
158 static void             gst_avi_demux_init                      (GstAviDemux *avi_demux);
159
160 static void             gst_avi_demux_loop                      (GstElement *element);
161
162 static gboolean         gst_avi_demux_process_chunk             (GstAviDemux *avi_demux, guint64 *filepos,
163                                                                  guint32 desired_tag,
164                                                                  gint rec_depth, guint32 *chunksize);
165
166 static gboolean         gst_avi_demux_send_event                (GstElement *element, GstEvent *event);
167
168 static const GstEventMask*
169                         gst_avi_demux_get_event_mask            (GstPad *pad);
170 static gboolean         gst_avi_demux_handle_src_event          (GstPad *pad, GstEvent *event);
171 static const GstFormat* gst_avi_demux_get_src_formats           (GstPad *pad); 
172 static const GstPadQueryType*
173                         gst_avi_demux_get_src_query_types       (GstPad *pad);
174 static gboolean         gst_avi_demux_handle_src_query          (GstPad *pad, GstPadQueryType type, 
175                                                                  GstFormat *format, gint64 *value);
176 static gboolean         gst_avi_demux_src_convert               (GstPad *pad, GstFormat src_format, gint64 src_value,
177                                                                  GstFormat *dest_format, gint64 *dest_value);
178
179 static GstElementStateReturn
180                         gst_avi_demux_change_state              (GstElement *element);
181
182 static void             gst_avi_demux_get_property              (GObject *object, guint prop_id,        
183                                                                  GValue *value, GParamSpec *pspec);
184
185
186 static GstElementClass *parent_class = NULL;
187 /*static guint gst_avi_demux_signals[LAST_SIGNAL] = { 0 }; */
188
189 GType
190 gst_avi_demux_get_type(void) 
191 {
192   static GType avi_demux_type = 0;
193
194   if (!avi_demux_type) {
195     static const GTypeInfo avi_demux_info = {
196       sizeof(GstAviDemuxClass),      
197       NULL,
198       NULL,
199       (GClassInitFunc)gst_avi_demux_class_init,
200       NULL,
201       NULL,
202       sizeof(GstAviDemux),
203       0,
204       (GInstanceInitFunc)gst_avi_demux_init,
205     };
206     avi_demux_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviDemux", &avi_demux_info, 0);
207   }
208   return avi_demux_type;
209 }
210
211 static void
212 gst_avi_demux_class_init (GstAviDemuxClass *klass) 
213 {
214   GObjectClass *gobject_class;
215   GstElementClass *gstelement_class;
216
217   gobject_class = (GObjectClass*)klass;
218   gstelement_class = (GstElementClass*)klass;
219
220   g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_BITRATE,
221     g_param_spec_long ("bitrate","bitrate","bitrate",
222                        G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
223
224   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
225   
226   gobject_class->get_property = gst_avi_demux_get_property;
227   
228   gstelement_class->change_state = gst_avi_demux_change_state;
229   gstelement_class->send_event = gst_avi_demux_send_event;
230 }
231
232 static void 
233 gst_avi_demux_init (GstAviDemux *avi_demux) 
234 {
235   GST_FLAG_SET (avi_demux, GST_ELEMENT_EVENT_AWARE);
236                                 
237   avi_demux->sinkpad = gst_pad_new_from_template (
238                   GST_PAD_TEMPLATE_GET (sink_templ), "sink");
239   gst_element_add_pad (GST_ELEMENT (avi_demux), avi_demux->sinkpad);
240
241   gst_element_set_loop_function (GST_ELEMENT (avi_demux), gst_avi_demux_loop);
242
243   avi_demux->num_streams = 0;
244   avi_demux->num_v_streams = 0;
245   avi_demux->num_a_streams = 0;
246   avi_demux->index_entries = NULL;
247   avi_demux->index_size = 0;
248   avi_demux->seek_pending = 0;
249   avi_demux->restart = FALSE;
250
251 }
252
253 static GstCaps*
254 avi_type_find (GstBuffer *buf,
255               gpointer private)
256 {
257   gchar *data = GST_BUFFER_DATA (buf);
258   GstCaps *new;
259
260   GST_DEBUG (0,"avi_demux: typefind");
261
262   if (GUINT32_FROM_LE (((guint32 *)data)[0]) != GST_RIFF_TAG_RIFF)
263     return NULL;
264   if (GUINT32_FROM_LE (((guint32 *)data)[2]) != GST_RIFF_RIFF_AVI)
265     return NULL;
266
267   new = GST_CAPS_NEW ("avi_type_find",
268                       "video/avi", 
269                         "format", GST_PROPS_STRING ("AVI"));
270   return new;
271 }
272
273 static gboolean
274 gst_avi_demux_avih (GstAviDemux *avi_demux)
275 {
276   gst_riff_avih *avih;
277   guint32       got_bytes;
278   GstByteStream *bs = avi_demux->bs;
279
280   got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&avih, sizeof (gst_riff_avih));
281   if (got_bytes == sizeof (gst_riff_avih)) {
282     avi_demux->avih.us_frame    = GUINT32_FROM_LE (avih->us_frame);
283     avi_demux->avih.max_bps     = GUINT32_FROM_LE (avih->max_bps);
284     avi_demux->avih.pad_gran    = GUINT32_FROM_LE (avih->pad_gran);
285     avi_demux->avih.flags       = GUINT32_FROM_LE (avih->flags);
286     avi_demux->avih.tot_frames  = GUINT32_FROM_LE (avih->tot_frames);
287     avi_demux->avih.init_frames = GUINT32_FROM_LE (avih->init_frames);
288     avi_demux->avih.streams     = GUINT32_FROM_LE (avih->streams);
289     avi_demux->avih.bufsize     = GUINT32_FROM_LE (avih->bufsize);
290     avi_demux->avih.width       = GUINT32_FROM_LE (avih->width);
291     avi_demux->avih.height      = GUINT32_FROM_LE (avih->height);
292     avi_demux->avih.scale       = GUINT32_FROM_LE (avih->scale);
293     avi_demux->avih.rate        = GUINT32_FROM_LE (avih->rate);
294     avi_demux->avih.start       = GUINT32_FROM_LE (avih->start);
295     avi_demux->avih.length      = GUINT32_FROM_LE (avih->length);
296
297     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: avih tag found");
298     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  us_frame    %d", avi_demux->avih.us_frame);
299     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  max_bps     %d", avi_demux->avih.max_bps);
300     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  pad_gran    %d", avi_demux->avih.pad_gran);
301     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  flags       0x%08x", avi_demux->avih.flags);
302     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  tot_frames  %d", avi_demux->avih.tot_frames);
303     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  init_frames %d", avi_demux->avih.init_frames);
304     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  streams     %d", avi_demux->avih.streams);
305     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  bufsize     %d", avi_demux->avih.bufsize);
306     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  width       %d", avi_demux->avih.width);
307     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  height      %d", avi_demux->avih.height);
308     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  scale       %d", avi_demux->avih.scale);
309     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  rate        %d", avi_demux->avih.rate);
310     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  start       %d", avi_demux->avih.start);
311     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  length      %d", avi_demux->avih.length);
312
313     return TRUE;
314   }
315   return FALSE;
316 }
317
318 static gboolean 
319 gst_avi_demux_strh (GstAviDemux *avi_demux)
320 {
321   gst_riff_strh *strh;
322   GstByteStream *bs = avi_demux->bs;
323   guint32       got_bytes;
324
325   got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&strh, sizeof (gst_riff_strh));
326   if (got_bytes == sizeof (gst_riff_strh)) {
327     avi_stream_context *target;
328
329     avi_demux->fcc_type = GUINT32_FROM_LE (strh->type);
330
331     target = &avi_demux->stream[avi_demux->num_streams];
332
333     target->num = avi_demux->num_streams;
334
335     target->strh.type           = avi_demux->fcc_type;
336     target->strh.fcc_handler    = GUINT32_FROM_LE (strh->fcc_handler);
337     target->strh.flags          = GUINT32_FROM_LE (strh->flags);
338     target->strh.priority       = GUINT32_FROM_LE (strh->priority);
339     target->strh.init_frames    = GUINT32_FROM_LE (strh->init_frames);
340     target->strh.scale          = GUINT32_FROM_LE (strh->scale);
341     target->strh.rate           = GUINT32_FROM_LE (strh->rate);
342     target->strh.start          = GUINT32_FROM_LE (strh->start);
343     target->strh.length         = GUINT32_FROM_LE (strh->length);
344     target->strh.bufsize        = GUINT32_FROM_LE (strh->bufsize);
345     target->strh.quality        = GUINT32_FROM_LE (strh->quality);
346     target->strh.samplesize     = GUINT32_FROM_LE (strh->samplesize);
347
348     if (!target->strh.scale)
349       target->strh.scale = 1; /* avoid division by zero */
350     if (!target->strh.rate)
351       target->strh.rate = 1; /* avoid division by zero */
352
353     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strh tag found");
354     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  type        0x%08x (%s)", 
355                   target->strh.type, gst_riff_id_to_fourcc (strh->type));
356     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  fcc_handler 0x%08x (%s)", 
357                   target->strh.fcc_handler, gst_riff_id_to_fourcc (strh->fcc_handler));
358     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  flags       0x%08x", strh->flags);
359     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  priority    %d", target->strh.priority);
360     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  init_frames %d", target->strh.init_frames);
361     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  scale       %d", target->strh.scale);
362     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  rate        %d", target->strh.rate);
363     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  start       %d", target->strh.start);
364     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  length      %d", target->strh.length);
365     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  bufsize     %d", target->strh.bufsize);
366     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  quality     %d", target->strh.quality);
367     GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  samplesize  %d", target->strh.samplesize);
368
369     target->delay = 0LL;
370     target->total_bytes = 0LL;
371     target->total_frames = 0;
372     target->end_pos = -1;
373
374     target->skip = 0;
375
376     avi_demux->avih.bufsize = MAX (avi_demux->avih.bufsize, target->strh.bufsize);
377
378     return TRUE;
379   }
380   return FALSE;
381 }
382
383 static void 
384 gst_avi_demux_strf_vids (GstAviDemux *avi_demux)
385 {
386   gst_riff_strf_vids *strf;
387   GstPad *srcpad;
388   GstByteStream *bs = avi_demux->bs;
389   GstCaps *newcaps = NULL, *capslist = NULL;
390   avi_stream_context *stream;
391   guint32       got_bytes;
392
393   got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&strf, sizeof (gst_riff_strf_vids));
394
395   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context vids");
396   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  size        %d", GUINT32_FROM_LE (strf->size));
397   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  width       %d", GUINT32_FROM_LE (strf->width));
398   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  height      %d", GUINT32_FROM_LE (strf->height));
399   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  planes      %d", GUINT16_FROM_LE (strf->planes));
400   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  bit_cnt     %d", GUINT16_FROM_LE (strf->bit_cnt));
401   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  compression 0x%08x (%s)", 
402                   GUINT32_FROM_LE (strf->compression), gst_riff_id_to_fourcc (strf->compression));
403   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  image_size  %d", GUINT32_FROM_LE (strf->image_size));
404   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  xpels_meter %d", GUINT32_FROM_LE (strf->xpels_meter));
405   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  ypels_meter %d", GUINT32_FROM_LE (strf->ypels_meter));
406   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  num_colors  %d", GUINT32_FROM_LE (strf->num_colors));
407   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  imp_colors  %d", GUINT32_FROM_LE (strf->imp_colors));
408
409   srcpad =  gst_pad_new_from_template (
410                   GST_PAD_TEMPLATE_GET (src_video_templ), g_strdup_printf ("video_%02d", 
411                           avi_demux->num_v_streams));
412
413   capslist = gst_caps_append(NULL, GST_CAPS_NEW (
414                           "avidemux_video_src",
415                           "video/avi",
416                             "format",           GST_PROPS_STRING ("strf_vids"),
417                               "size",           GST_PROPS_INT (GUINT32_FROM_LE (strf->size)),
418                               "width",          GST_PROPS_INT (GUINT32_FROM_LE (strf->width)),
419                               "height",         GST_PROPS_INT (GUINT32_FROM_LE (strf->height)),
420                               "planes",         GST_PROPS_INT (GUINT16_FROM_LE (strf->planes)),
421                               "bit_cnt",        GST_PROPS_INT (GUINT16_FROM_LE (strf->bit_cnt)),
422                               "compression",    GST_PROPS_FOURCC (GUINT32_FROM_LE (strf->compression)),
423                               "image_size",     GST_PROPS_INT (GUINT32_FROM_LE (strf->image_size)),
424                               "xpels_meter",    GST_PROPS_INT (GUINT32_FROM_LE (strf->xpels_meter)),
425                               "ypels_meter",    GST_PROPS_INT (GUINT32_FROM_LE (strf->ypels_meter)),
426                               "num_colors",     GST_PROPS_INT (GUINT32_FROM_LE (strf->num_colors)),
427                               "imp_colors",     GST_PROPS_INT (GUINT32_FROM_LE (strf->imp_colors))
428                               ));
429
430   /* let's try some gstreamer-like mime-type caps */
431   switch (GUINT32_FROM_LE(strf->compression))
432   {
433     case GST_MAKE_FOURCC('I','4','2','0'):
434     case GST_MAKE_FOURCC('Y','U','Y','2'):
435       newcaps = GST_CAPS_NEW (
436                   "avidemux_video_src",
437                   "video/raw",
438                     "format",  GST_PROPS_FOURCC(GUINT32_FROM_LE(strf->compression)),
439                     "width",   GST_PROPS_INT(strf->width),
440                     "height",  GST_PROPS_INT(strf->height)
441                 );
442       break;
443     case GST_MAKE_FOURCC('M','J','P','G'):
444       newcaps = GST_CAPS_NEW (
445                   "avidemux_video_src",
446                   "video/jpeg",
447                     "width",   GST_PROPS_INT(strf->width),
448                     "height",  GST_PROPS_INT(strf->height)
449                 );
450       break;
451     case GST_MAKE_FOURCC('d','v','s','d'):
452       newcaps = GST_CAPS_NEW (
453                   "avidemux_video_src",
454                   "video/dv",
455                     "format",  GST_PROPS_STRING("NTSC"), /* FIXME??? */
456                     "width",   GST_PROPS_INT(strf->width),
457                     "height",  GST_PROPS_INT(strf->height)
458                 );
459       break;
460   }
461
462   if (newcaps) capslist = gst_caps_append (capslist, newcaps);
463
464   gst_pad_try_set_caps (srcpad, capslist);
465   gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
466   gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
467   gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
468   gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
469   gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
470   gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
471
472   stream = &avi_demux->stream[avi_demux->num_streams];
473   stream->pad = srcpad;
474   gst_pad_set_element_private (srcpad, stream);
475   avi_demux->num_streams++;
476   avi_demux->num_v_streams++;
477
478   gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
479 }
480
481 static void 
482 gst_avi_demux_strf_auds (GstAviDemux *avi_demux)
483 {
484   gst_riff_strf_auds *strf;
485   GstPad *srcpad;
486   GstByteStream *bs = avi_demux->bs;
487   GstCaps *newcaps = NULL, *capslist = NULL;
488   avi_stream_context *stream;
489   guint32       got_bytes;
490
491   got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&strf, sizeof (gst_riff_strf_auds));
492
493   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context auds");
494   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  format      %d", GUINT16_FROM_LE (strf->format));
495   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  channels    %d", GUINT16_FROM_LE (strf->channels));
496   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  rate        %d", GUINT32_FROM_LE (strf->rate));
497   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  av_bps      %d", GUINT32_FROM_LE (strf->av_bps));
498   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  blockalign  %d", GUINT16_FROM_LE (strf->blockalign));
499   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  size        %d", GUINT16_FROM_LE (strf->size));
500
501   srcpad =  gst_pad_new_from_template (
502                   GST_PAD_TEMPLATE_GET (src_audio_templ), g_strdup_printf ("audio_%02d", 
503                           avi_demux->num_a_streams));
504
505   capslist = gst_caps_append(NULL, GST_CAPS_NEW (
506                           "avidemux_audio_src",
507                           "video/avi",
508                             "format",           GST_PROPS_STRING ("strf_auds"),
509                               "fmt",            GST_PROPS_INT (GUINT16_FROM_LE (strf->format)),
510                               "channels",       GST_PROPS_INT (GUINT16_FROM_LE (strf->channels)),
511                               "rate",           GST_PROPS_INT (GUINT32_FROM_LE (strf->rate)),
512                               "av_bps",         GST_PROPS_INT (GUINT32_FROM_LE (strf->av_bps)),
513                               "blockalign",     GST_PROPS_INT (GUINT16_FROM_LE (strf->blockalign)),
514                               "size",           GST_PROPS_INT (GUINT16_FROM_LE (strf->size))
515                           ));
516
517   /* let's try some gstreamer-formatted mime types */
518   switch (GUINT16_FROM_LE(strf->format))
519   {
520     case GST_RIFF_WAVE_FORMAT_MPEGL3:
521     case GST_RIFF_WAVE_FORMAT_MPEGL12: /* mp3 */
522       newcaps = gst_caps_new ("avidemux_audio_src",
523                               "audio/x-mp3",
524                                 NULL);
525       break;
526     case GST_RIFF_WAVE_FORMAT_PCM: /* PCM/wav */
527       newcaps = gst_caps_new ("avidemux_audio_src",
528                               "audio/raw",
529                               gst_props_new (
530                                 "format",     GST_PROPS_STRING ("int"),
531                                 "law",        GST_PROPS_INT (0),
532                                 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
533                                 "signed",     GST_PROPS_BOOLEAN ((GUINT16_FROM_LE (strf->size) != 8)),
534                                 "width",      GST_PROPS_INT ((GUINT16_FROM_LE (strf->blockalign)*8) /
535                                                               GUINT16_FROM_LE (strf->channels)),
536                                 "depth",      GST_PROPS_INT (GUINT16_FROM_LE (strf->size)),
537                                 "rate",       GST_PROPS_INT (GUINT32_FROM_LE (strf->rate)),
538                                 "channels",   GST_PROPS_INT (GUINT16_FROM_LE (strf->channels)),
539                                 NULL
540                               ));
541       break;
542     case GST_RIFF_WAVE_FORMAT_VORBIS1: /* ogg/vorbis mode 1 */
543     case GST_RIFF_WAVE_FORMAT_VORBIS2: /* ogg/vorbis mode 2 */
544     case GST_RIFF_WAVE_FORMAT_VORBIS3: /* ogg/vorbis mode 3 */
545     case GST_RIFF_WAVE_FORMAT_VORBIS1PLUS: /* ogg/vorbis mode 1+ */
546     case GST_RIFF_WAVE_FORMAT_VORBIS2PLUS: /* ogg/vorbis mode 2+ */
547     case GST_RIFF_WAVE_FORMAT_VORBIS3PLUS: /* ogg/vorbis mode 3+ */
548       newcaps = gst_caps_new ("avidemux_audio_src",
549                               "application/x-ogg",
550                               NULL);
551       break;
552   }
553
554   if (newcaps) capslist = gst_caps_append(capslist, newcaps);
555
556
557   gst_pad_try_set_caps(srcpad, capslist);
558   gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
559   gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
560   gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
561   gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
562   gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
563   gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
564
565   stream = &avi_demux->stream[avi_demux->num_streams];
566   stream->pad = srcpad;
567   gst_pad_set_element_private (srcpad, stream);
568   avi_demux->num_streams++;
569   avi_demux->num_a_streams++;
570
571   gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
572 }
573
574 static void 
575 gst_avi_demux_strf_iavs (GstAviDemux *avi_demux)
576 {
577   gst_riff_strf_iavs *strf;
578   GstPad *srcpad;
579   GstByteStream *bs = avi_demux->bs;
580   GstCaps *newcaps = NULL, *capslist = NULL;
581   avi_stream_context *stream;
582   guint32       got_bytes;
583
584   got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&strf, sizeof (gst_riff_strf_iavs));
585
586   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context iavs");
587   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxSrc   %08x", GUINT32_FROM_LE (strf->DVAAuxSrc));
588   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxCtl   %08x", GUINT32_FROM_LE (strf->DVAAuxCtl));
589   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxSrc1  %08x", GUINT32_FROM_LE (strf->DVAAuxSrc1));
590   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxCtl1  %08x", GUINT32_FROM_LE (strf->DVAAuxCtl1));
591   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVVAuxSrc   %08x", GUINT32_FROM_LE (strf->DVVAuxSrc));
592   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVVAuxCtl   %08x", GUINT32_FROM_LE (strf->DVVAuxCtl));
593   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVReserved1 %08x", GUINT32_FROM_LE (strf->DVReserved1));
594   GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVReserved2 %08x", GUINT32_FROM_LE (strf->DVReserved2));
595
596   srcpad =  gst_pad_new_from_template (
597                   GST_PAD_TEMPLATE_GET (src_video_templ), g_strdup_printf ("video_%02d", 
598                           avi_demux->num_v_streams));
599
600   capslist = gst_caps_append(NULL, GST_CAPS_NEW (
601                           "avidemux_video_src",
602                           "video/avi",
603                             "format",           GST_PROPS_STRING ("strf_iavs"),
604                               "DVAAuxSrc",      GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxSrc)),
605                               "DVAAuxCtl",      GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxCtl)),
606                               "DVAAuxSrc1",     GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxSrc1)),
607                               "DVAAuxCtl1",     GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxCtl1)),
608                               "DVVAuxSrc",      GST_PROPS_INT (GUINT32_FROM_LE (strf->DVVAuxSrc)),
609                               "DVVAuxCtl",      GST_PROPS_INT (GUINT32_FROM_LE (strf->DVVAuxCtl)),
610                               "DVReserved1",    GST_PROPS_INT (GUINT32_FROM_LE (strf->DVReserved1)),
611                               "DVReserved2",    GST_PROPS_INT (GUINT32_FROM_LE (strf->DVReserved2))
612                          ));
613
614   newcaps = gst_caps_new ("avi_type_dv", 
615                           "video/dv", 
616                           gst_props_new (
617                             "format",           GST_PROPS_STRING ("NTSC"), /* FIXME??? */
618                             NULL));
619
620   if (newcaps) capslist = gst_caps_append(capslist, newcaps);
621
622   gst_pad_try_set_caps(srcpad, capslist);
623   gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
624   gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
625   gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
626   gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
627   gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
628   gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
629
630   stream = &avi_demux->stream[avi_demux->num_streams];
631   stream->pad = srcpad;
632   gst_pad_set_element_private (srcpad, stream);
633   avi_demux->num_streams++;
634   avi_demux->num_v_streams++;
635
636   gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
637 }
638
639 static void
640 gst_avi_debug_entry (const gchar *prefix, gst_avi_index_entry *entry)
641 {
642   GST_DEBUG (0, "%s: %05d %d %08llx %05d %14lld %08x %08x (%d) %08x", prefix, entry->index_nr, entry->stream_nr, 
643                   entry->bytes_before, entry->frames_before, entry->ts, entry->flags, entry->offset, 
644                   entry->offset, entry->size);
645 }
646
647 static void
648 gst_avi_demux_parse_index (GstAviDemux *avi_demux,
649                           gulong filepos, gulong offset)
650 {
651   GstBuffer *buf;
652   gulong index_size;
653   guint32 got_bytes;
654   gint i;
655   gst_riff_index_entry *entry;
656
657   if (!gst_bytestream_seek (avi_demux->bs, filepos + offset, GST_SEEK_METHOD_SET)) {
658     GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek to index");
659     return;
660   }
661   got_bytes = gst_bytestream_read (avi_demux->bs, &buf, 8);
662   while (got_bytes < 8) {
663     guint32 remaining;
664     GstEvent *event;
665   
666     gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
667     gst_event_unref (event);
668
669     got_bytes = gst_bytestream_read (avi_demux->bs, &buf, 8);
670   }
671                   
672   if (GST_BUFFER_OFFSET (buf) != filepos + offset || GST_BUFFER_SIZE (buf) != 8) {
673     GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not get index, got %lld %d, expected %ld", 
674                     GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf), filepos + offset);
675     goto end;
676   }
677
678   if (gst_riff_fourcc_to_id (GST_BUFFER_DATA (buf)) != GST_RIFF_TAG_idx1) {
679     GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: no index found");
680     goto end;
681   }
682
683   index_size = GUINT32_FROM_LE(*(guint32 *)(GST_BUFFER_DATA (buf) + 4));
684   gst_buffer_unref (buf);
685
686   gst_bytestream_size_hint (avi_demux->bs, index_size);
687
688   got_bytes = gst_bytestream_read (avi_demux->bs, &buf, index_size);
689   if (got_bytes < index_size) {
690     GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: error reading index");
691     goto end;
692   }
693
694   avi_demux->index_size = index_size/sizeof(gst_riff_index_entry);
695   GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: index size %lu", avi_demux->index_size);
696
697   avi_demux->index_entries = g_malloc (avi_demux->index_size * sizeof (gst_avi_index_entry));
698
699   entry = (gst_riff_index_entry *) GST_BUFFER_DATA (buf);
700
701   for (i = 0; i < avi_demux->index_size; i++) {
702     avi_stream_context *stream;
703     gint stream_nr;
704     gst_avi_index_entry *target = &avi_demux->index_entries[i];
705     GstFormat format;
706
707     stream_nr = CHUNKID_TO_STREAMNR (entry[i].id);
708     if (stream_nr > avi_demux->num_streams || stream_nr < 0) {
709       avi_demux->index_entries[i].stream_nr = -1;
710       continue;
711     }
712
713     target->stream_nr = stream_nr;
714     stream = &avi_demux->stream[stream_nr];
715
716     target->index_nr = i;
717     target->flags    = entry[i].flags;
718     target->size     = entry[i].size;
719     target->offset   = entry[i].offset;
720
721     /* figure out if the index is 0 based or relative to the MOVI start */
722     if (i == 0) {
723       if (target->offset < filepos)
724         avi_demux->index_offset = filepos;
725       else
726         avi_demux->index_offset = 0;
727     }
728
729     target->bytes_before = stream->total_bytes;
730     target->frames_before = stream->total_frames;
731
732     format = GST_FORMAT_TIME;
733     if (stream->strh.type == GST_RIFF_FCC_auds) {
734       /* all audio frames are keyframes */
735       target->flags |= GST_RIFF_IF_KEYFRAME;
736     }
737       
738     /* constant rate stream */
739     if (stream->strh.samplesize) {
740       gst_pad_convert (stream->pad, GST_FORMAT_BYTES, stream->total_bytes,
741                                  &format, &target->ts);
742     }
743     /* VBR stream */
744     else {
745       gst_pad_convert (stream->pad, GST_FORMAT_UNITS, stream->total_frames,
746                                  &format, &target->ts);
747     }
748     gst_avi_debug_entry ("index", target);
749
750     stream->total_bytes += target->size;
751     stream->total_frames++;
752   }
753   for (i = 0; i < avi_demux->num_streams; i++) {
754     avi_stream_context *stream;
755
756     stream = &avi_demux->stream[i];
757     GST_DEBUG (GST_CAT_PLUGIN_INFO, "stream %i: %d frames, %lld bytes", i, stream->total_frames, stream->total_bytes);
758   }
759   gst_buffer_unref (buf);
760
761 end:
762   GST_DEBUG (GST_CAT_PLUGIN_INFO, "index offset at %08lx", filepos);
763
764   if (!gst_bytestream_seek (avi_demux->bs, filepos, GST_SEEK_METHOD_SET)) {
765     GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek back to movi");
766     return;
767   }
768 }
769
770 static gst_avi_index_entry*
771 gst_avi_demux_index_next (GstAviDemux *avi_demux, gint stream_nr, gint start, guint32 flags)
772 {
773   gint i;
774   gst_avi_index_entry *entry = NULL;
775
776   for (i = start; i < avi_demux->index_size; i++) {
777     entry = &avi_demux->index_entries[i];
778
779     if (entry->stream_nr == stream_nr && (entry->flags & flags) == flags) {
780       break;
781     }
782   }
783
784   return entry;
785 }
786
787 static gst_avi_index_entry*
788 gst_avi_demux_index_entry_for_time (GstAviDemux *avi_demux, gint stream_nr, guint64 time, guint32 flags)
789 {
790   gst_avi_index_entry *entry = NULL, *last_entry = NULL;
791   gint i;
792
793   i = -1;
794   do {
795     entry = gst_avi_demux_index_next (avi_demux, stream_nr, i + 1, flags);
796     if (!entry)
797       return NULL;
798
799     i = entry->index_nr;
800
801     if (entry->ts <= time) {
802       last_entry = entry;
803     }
804   }
805   while (entry->ts <= time);
806
807   return last_entry;
808 }
809
810 static const GstFormat*
811 gst_avi_demux_get_src_formats (GstPad *pad) 
812 {
813   avi_stream_context *stream = gst_pad_get_element_private (pad);
814
815   static const GstFormat src_a_formats[] = {
816     GST_FORMAT_TIME,
817     GST_FORMAT_BYTES,
818     GST_FORMAT_UNITS,
819     0
820   };
821   static const GstFormat src_v_formats[] = {
822     GST_FORMAT_TIME,
823     GST_FORMAT_UNITS,
824     0
825   };
826
827   return (stream->strh.type == GST_RIFF_FCC_auds ? src_a_formats : src_v_formats);
828 }
829
830 static gboolean
831 gst_avi_demux_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
832                            GstFormat *dest_format, gint64 *dest_value)
833 {
834   gboolean res = TRUE;
835   avi_stream_context *stream = gst_pad_get_element_private (pad);
836
837   if (stream->strh.type != GST_RIFF_FCC_auds && 
838                   (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
839     return FALSE;
840
841   switch (src_format) {
842     case GST_FORMAT_TIME:
843       switch (*dest_format) {
844         case GST_FORMAT_BYTES:
845           *dest_value = src_value * stream->strh.rate / (stream->strh.scale * GST_SECOND);
846           break;
847         case GST_FORMAT_DEFAULT:
848           *dest_format = GST_FORMAT_UNITS;
849         case GST_FORMAT_UNITS:
850           *dest_value = src_value * stream->strh.rate / (stream->strh.scale * GST_SECOND);
851           break;
852         default:
853           res = FALSE;
854           break;
855       }
856       break;
857     case GST_FORMAT_BYTES:
858     case GST_FORMAT_UNITS:
859       switch (*dest_format) {
860         case GST_FORMAT_TIME:
861           *dest_value = ((((gfloat)src_value) * stream->strh.scale)  / stream->strh.rate) * GST_SECOND;
862           break;
863         default:
864           res = FALSE;
865           break;
866       }
867       break;
868     default:
869       res = FALSE;
870   }
871
872   return res;
873 }
874
875 static const GstPadQueryType*
876 gst_avi_demux_get_src_query_types (GstPad *pad) 
877 {
878   static const GstPadQueryType src_types[] = {
879     GST_PAD_QUERY_TOTAL,
880     GST_PAD_QUERY_POSITION,
881     0
882   };
883
884   return src_types;
885 }
886
887 static gboolean
888 gst_avi_demux_handle_src_query (GstPad *pad, GstPadQueryType type, 
889                                 GstFormat *format, gint64 *value)
890 {
891   gboolean res = TRUE;
892   //GstAviDemux *avi_demux = GST_AVI_DEMUX (gst_pad_get_parent (pad));
893   avi_stream_context *stream = gst_pad_get_element_private (pad);
894
895   switch (type) {
896     case GST_PAD_QUERY_TOTAL:
897       switch (*format) {
898         case GST_FORMAT_DEFAULT:
899           *format = GST_FORMAT_TIME;
900           /* fall through */
901         case GST_FORMAT_TIME:
902           *value = (((gfloat)stream->strh.scale) * stream->strh.length / stream->strh.rate) * GST_SECOND;
903           break;
904         case GST_FORMAT_BYTES:
905           if (stream->strh.type == GST_RIFF_FCC_auds) {
906             *value = stream->total_bytes;
907           }
908           else
909             res = FALSE;
910           break;
911         case GST_FORMAT_UNITS:
912           if (stream->strh.type == GST_RIFF_FCC_auds)
913             *value = stream->strh.length * stream->strh.samplesize;
914           else if (stream->strh.type == GST_RIFF_FCC_vids)
915             *value = stream->strh.length;
916           else
917             res = FALSE;
918           break;
919         default:
920           res = FALSE;
921           break;
922       }
923       break;
924     case GST_PAD_QUERY_POSITION:
925       switch (*format) {
926         case GST_FORMAT_DEFAULT:
927           *format = GST_FORMAT_TIME;
928           /* fall through */
929         case GST_FORMAT_TIME:
930           if (stream->strh.samplesize) {
931             *value = (((gfloat)stream->current_byte) * stream->strh.scale / stream->strh.rate) * GST_SECOND;
932           }
933           else {
934             *value = (((gfloat)stream->current_frame) * stream->strh.scale / stream->strh.rate) * GST_SECOND;
935           }
936           break;
937         case GST_FORMAT_BYTES:
938           *value = stream->current_byte;
939           break;
940         case GST_FORMAT_UNITS:
941           if (stream->strh.samplesize) 
942             *value = stream->current_byte * stream->strh.samplesize;
943           else 
944             *value = stream->current_frame;
945           break;
946         default:
947           res = FALSE;
948           break;
949       }
950       break;
951     default:
952       res = FALSE;
953       break;
954   }
955
956   return res;
957 }
958
959 static gint32
960 gst_avi_demux_sync_streams (GstAviDemux *avi_demux, guint64 time)
961 {
962   gint i;
963   guint32 min_index = G_MAXUINT;
964   avi_stream_context *stream;
965   gst_avi_index_entry *entry;
966
967   for (i = 0; i < avi_demux->num_streams; i++) {
968     stream = &avi_demux->stream[i];
969
970     GST_DEBUG (0, "finding %d for time %lld", i, time);
971
972     entry = gst_avi_demux_index_entry_for_time (avi_demux, stream->num, time, GST_RIFF_IF_KEYFRAME);
973     if (entry) {
974       gst_avi_debug_entry ("sync entry", entry);
975
976       min_index = MIN (entry->index_nr, min_index);
977     }
978   }
979   GST_DEBUG (0, "first index at %d", min_index);
980   
981   /* now we know the entry we need to sync on. calculate number of frames to
982    * skip fro there on and the stream stats */
983   for (i = 0; i < avi_demux->num_streams; i++) {
984     gst_avi_index_entry *next_entry;
985     stream = &avi_demux->stream[i];
986
987     /* next entry */
988     next_entry = gst_avi_demux_index_next (avi_demux, stream->num, min_index, 0);
989     /* next entry with keyframe */
990     entry = gst_avi_demux_index_next (avi_demux, stream->num, min_index, GST_RIFF_IF_KEYFRAME);
991     gst_avi_debug_entry ("final sync", entry);
992
993     stream->current_byte = next_entry->bytes_before;
994     stream->current_frame = next_entry->frames_before;
995     stream->skip = entry->frames_before - next_entry->frames_before;
996
997     GST_DEBUG (0, "%d skip %d", stream->num, stream->skip);
998   }
999   GST_DEBUG (0, "final index at %d", min_index);
1000
1001   return min_index;
1002 }
1003
1004 static gboolean
1005 gst_avi_demux_send_event (GstElement *element, GstEvent *event)
1006 {
1007   const GList *pads;
1008
1009   pads = gst_element_get_pad_list (element);
1010
1011   while (pads) { 
1012     GstPad *pad = GST_PAD (pads->data);
1013
1014     if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
1015       /* we ref the event here as we might have to try again if the event
1016        * failed on this pad */
1017       gst_event_ref (event);
1018       if (gst_avi_demux_handle_src_event (pad, event)) {
1019         gst_event_unref (event);
1020         return TRUE;
1021       }
1022     }
1023     
1024     pads = g_list_next (pads);
1025   }
1026   
1027   gst_event_unref (event);
1028   return FALSE;
1029 }
1030
1031 static const GstEventMask*
1032 gst_avi_demux_get_event_mask (GstPad *pad)
1033 {
1034   static const GstEventMask masks[] = {
1035     { GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
1036     { GST_EVENT_SEEK_SEGMENT, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
1037     { 0, }
1038   };
1039
1040   return masks;
1041 }
1042         
1043 static gboolean
1044 gst_avi_demux_handle_src_event (GstPad *pad, GstEvent *event)
1045 {
1046   gboolean res = TRUE;
1047   GstAviDemux *avi_demux = GST_AVI_DEMUX (gst_pad_get_parent (pad));
1048   avi_stream_context *stream;
1049   
1050   stream = gst_pad_get_element_private (pad);
1051
1052   switch (GST_EVENT_TYPE (event)) {
1053     case GST_EVENT_SEEK_SEGMENT:
1054       stream->end_pos = GST_EVENT_SEEK_ENDOFFSET (event);
1055     case GST_EVENT_SEEK:
1056       GST_DEBUG (0, "seek format %d, %08x", GST_EVENT_SEEK_FORMAT (event), stream->strh.type);
1057       switch (GST_EVENT_SEEK_FORMAT (event)) {
1058         case GST_FORMAT_BYTES:
1059         case GST_FORMAT_UNITS:
1060           break;
1061         case GST_FORMAT_TIME:
1062         {
1063           gst_avi_index_entry *seek_entry, *entry;
1064           gint64 desired_offset = GST_EVENT_SEEK_OFFSET (event);
1065           guint32 flags;
1066           guint64 min_index;
1067           
1068
1069           /* no seek on audio yet */
1070           if (stream->strh.type == GST_RIFF_FCC_auds) {
1071             res = FALSE;
1072             goto done;
1073           }
1074           GST_DEBUG (0, "seeking to %lld", desired_offset);
1075
1076           flags = GST_RIFF_IF_KEYFRAME;
1077
1078           entry = gst_avi_demux_index_entry_for_time (avi_demux, stream->num, desired_offset, GST_RIFF_IF_KEYFRAME);
1079           if (entry) {
1080             desired_offset = entry->ts;
1081             min_index = gst_avi_demux_sync_streams (avi_demux, desired_offset);
1082             seek_entry = &avi_demux->index_entries[min_index];
1083             
1084             gst_avi_debug_entry ("syncing to entry", seek_entry);
1085             
1086             avi_demux->seek_offset = seek_entry->offset + avi_demux->index_offset;
1087             avi_demux->seek_pending = TRUE;
1088             avi_demux->last_seek = seek_entry->ts;
1089           }
1090           else {
1091             GST_DEBUG (0, "no index entry found for time %lld", desired_offset);
1092             res = FALSE;
1093           }
1094           break;
1095         }
1096         default:
1097           res = FALSE;
1098           break;
1099       }
1100       break;
1101     default:
1102       res = FALSE;
1103       break;
1104   }
1105
1106 done:
1107   gst_event_unref (event);
1108
1109   return res;
1110 }
1111
1112 static gboolean
1113 gst_avi_demux_handle_sink_event (GstAviDemux *avi_demux)
1114 {
1115   guint32 remaining;
1116   GstEvent *event;
1117   GstEventType type;
1118   
1119   gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
1120
1121   type = event? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
1122
1123   switch (type) {
1124     case GST_EVENT_EOS:
1125       gst_bytestream_flush (avi_demux->bs, remaining);
1126       gst_pad_event_default (avi_demux->sinkpad, event);
1127       break;
1128     case GST_EVENT_FLUSH:
1129       g_warning ("flush event");
1130       break;
1131     case GST_EVENT_DISCONTINUOUS:
1132     {
1133       gint i;
1134       GstEvent *discont;
1135
1136       for (i = 0; i < avi_demux->num_streams; i++) {
1137         avi_stream_context *stream = &avi_demux->stream[i];
1138
1139         if (GST_PAD_IS_USABLE (stream->pad)) {
1140           GST_DEBUG (GST_CAT_EVENT, "sending discont on %d %lld + %lld = %lld", i, 
1141                         avi_demux->last_seek, stream->delay, avi_demux->last_seek + stream->delay);
1142          discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, 
1143                         avi_demux->last_seek + stream->delay , NULL);
1144           gst_pad_push (stream->pad, GST_BUFFER (discont));
1145         }
1146       }
1147       break;
1148     }
1149     default:
1150       g_warning ("unhandled event %d", type);
1151       break;
1152   }
1153
1154   gst_event_unref (event);
1155
1156   return TRUE;
1157 }
1158
1159 static inline gboolean 
1160 gst_avi_demux_read_chunk (GstAviDemux *avi_demux, guint32 *id, guint32 *size)
1161 {
1162   gst_riff_chunk *chunk;
1163   GstByteStream *bs = avi_demux->bs;
1164   guint32       got_bytes;
1165
1166   do {
1167     got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&chunk, sizeof (gst_riff_chunk));
1168     if (got_bytes == sizeof (gst_riff_chunk)) {
1169       *id =   GUINT32_FROM_LE (chunk->id);
1170       *size = GUINT32_FROM_LE (chunk->size);
1171
1172       gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
1173
1174       return TRUE;
1175     }
1176   } while (gst_avi_demux_handle_sink_event (avi_demux));
1177
1178   return TRUE;
1179 }
1180
1181 static gboolean
1182 gst_avi_demux_process_movi (GstAviDemux *avi_demux, gint rec_depth, guint64 *filepos)
1183 {
1184   guint32 subchunksize = 0;
1185
1186   while (!avi_demux->restart) { /* while not showed all: */
1187     if (avi_demux->seek_pending) {
1188       GST_DEBUG (0, "avidemux: seek pending to %lld %08llx", avi_demux->seek_offset, avi_demux->seek_offset);
1189       if (!gst_bytestream_seek (avi_demux->bs, avi_demux->seek_offset, GST_SEEK_METHOD_SET)) {
1190         GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek");
1191       }
1192       else {
1193         *filepos = avi_demux->seek_offset;
1194       }
1195       avi_demux->seek_pending = FALSE;
1196     }
1197
1198     GST_INFO (GST_CAT_PLUGIN_INFO, "process chunk filepos %08llx", *filepos);
1199     /* recurse for subchunks of RIFF and LIST chunks: */
1200     if (!gst_avi_demux_process_chunk (avi_demux, filepos, 0,
1201                            rec_depth + 1, &subchunksize)) {
1202       return FALSE;
1203     }
1204     /* we are running in an infinite loop, we need to _yield 
1205      * from time to time */
1206     gst_element_yield (GST_ELEMENT (avi_demux));
1207   }
1208   return TRUE;
1209 }
1210
1211 static gboolean
1212 gst_avi_demux_process_chunk (GstAviDemux *avi_demux, guint64 *filepos,
1213                              guint32 desired_tag,
1214                              gint rec_depth, guint32 *chunksize)
1215 {
1216   guint32 chunkid;      
1217   GstByteStream *bs = avi_demux->bs;
1218
1219   if (!gst_avi_demux_read_chunk (avi_demux, &chunkid, chunksize)) {
1220     g_print ("  *****  Error reading chunk at filepos 0x%08llx\n", *filepos);
1221     return FALSE;
1222   }
1223   if (desired_tag) {            /* do we have to test identity? */
1224     if (desired_tag != chunkid) {
1225       g_print ("\n\n *** Error: Expected chunk '%s', found '%s'\n",
1226               gst_riff_id_to_fourcc (desired_tag),
1227               gst_riff_id_to_fourcc (chunkid));
1228       return FALSE;
1229     }
1230   }
1231
1232   GST_INFO (GST_CAT_PLUGIN_INFO, "chunkid %s, size %08x, filepos %08llx", 
1233                   gst_riff_id_to_fourcc (chunkid), *chunksize, *filepos);
1234
1235   *filepos += (sizeof (guint32) + sizeof (guint32));
1236
1237   switch (chunkid) {
1238     case GST_RIFF_TAG_RIFF:
1239     case GST_RIFF_TAG_LIST:
1240     {
1241       guint32 datashowed;
1242       guint32 subchunksize = 0; /* size of a read subchunk             */
1243       gchar *formtype;
1244       guint32       got_bytes;
1245
1246       got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&formtype, sizeof (guint32));
1247       if (got_bytes < sizeof(guint32))
1248         return FALSE;
1249
1250       switch (GUINT32_FROM_LE (*((guint32*)formtype))) {
1251         case GST_RIFF_LIST_movi:
1252           gst_avi_demux_parse_index (avi_demux, *filepos, *chunksize);
1253           while (!gst_bytestream_flush (bs, sizeof (guint32))) {
1254             guint32 remaining;
1255             GstEvent *event;
1256
1257             gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
1258             gst_event_unref (event);
1259           }
1260           if  (avi_demux->avih.bufsize)
1261             gst_bytestream_size_hint (avi_demux->bs, avi_demux->avih.bufsize);
1262
1263           gst_avi_demux_process_movi (avi_demux, rec_depth, filepos);
1264           goto done;
1265         default:
1266           /* flush the form type */
1267           gst_bytestream_flush_fast (bs, sizeof (guint32));
1268           break;
1269       }
1270
1271       datashowed = sizeof (guint32);    /* we showed the form type      */
1272       *filepos += datashowed;   /* for the rest of the routine  */
1273
1274       while (datashowed < *chunksize) { /* while not showed all: */
1275
1276         GST_INFO (GST_CAT_PLUGIN_INFO, "process chunk filepos %08llx", *filepos);
1277         /* recurse for subchunks of RIFF and LIST chunks: */
1278         if (!gst_avi_demux_process_chunk (avi_demux, filepos, 0,
1279                            rec_depth + 1, &subchunksize)) {
1280
1281           g_print ("  *****  Error processing chunk at filepos 0x%08llxi %u %u\n",
1282                    *filepos, *chunksize, datashowed);
1283           return FALSE;
1284         }
1285         if (avi_demux->restart)
1286           goto done;
1287
1288         subchunksize = ((subchunksize + 1) & ~1);
1289
1290         datashowed += (sizeof (guint32) + sizeof (guint32) + subchunksize);
1291         GST_INFO (GST_CAT_PLUGIN_INFO, "process chunk done filepos %08llx, subchunksize %08x", 
1292                         *filepos, subchunksize);
1293       }
1294       if (datashowed != *chunksize) {
1295         g_warning ("error parsing AVI %u %u", datashowed, *chunksize);
1296       }
1297       goto done;
1298     }
1299     case GST_RIFF_TAG_avih:
1300       gst_avi_demux_avih (avi_demux);
1301       break;
1302     case GST_RIFF_TAG_strh:
1303     {
1304       gst_avi_demux_strh (avi_demux);
1305       break;
1306     }
1307     case GST_RIFF_TAG_strf:
1308       switch (avi_demux->fcc_type) {
1309         case GST_RIFF_FCC_vids:
1310           gst_avi_demux_strf_vids (avi_demux);
1311           break;
1312         case GST_RIFF_FCC_auds:
1313           gst_avi_demux_strf_auds (avi_demux);
1314           break;
1315         case GST_RIFF_FCC_iavs:
1316           gst_avi_demux_strf_iavs (avi_demux);
1317           break;
1318         case GST_RIFF_FCC_pads:
1319         case GST_RIFF_FCC_txts:
1320         default:
1321           GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux_chain: strh type %s not supported", 
1322                           gst_riff_id_to_fourcc (avi_demux->fcc_type));
1323           break;
1324       }
1325       break;
1326     case GST_RIFF_00dc:
1327     case GST_RIFF_00db:
1328     case GST_RIFF_00__:
1329     case GST_RIFF_01wb:
1330     {
1331       gint stream_id;
1332       avi_stream_context *stream;
1333       gint64 next_ts;
1334       GstFormat format;
1335       
1336       stream_id = CHUNKID_TO_STREAMNR (chunkid);
1337                    
1338       stream = &avi_demux->stream[stream_id];
1339
1340       GST_DEBUG (0,"gst_avi_demux_chain: tag found %08x size %08x stream_id %d",
1341                     chunkid, *chunksize, stream_id);
1342
1343       format = GST_FORMAT_TIME;
1344       gst_pad_query (stream->pad, GST_PAD_QUERY_POSITION, &format, &next_ts);
1345
1346       if (stream->strh.init_frames == stream->current_frame && stream->delay==0)
1347         stream->delay = next_ts;
1348
1349       stream->current_frame++;
1350       stream->current_byte += *chunksize;
1351
1352       if (stream->skip) {
1353         stream->skip--;
1354       }
1355       else {
1356         if (GST_PAD_IS_USABLE (stream->pad)) {
1357           if (next_ts >= stream->end_pos) {
1358             gst_pad_push (stream->pad, GST_BUFFER (gst_event_new (GST_EVENT_EOS)));
1359             GST_DEBUG (0, "end stream %d: %lld %d %lld", stream_id, next_ts, stream->current_frame - 1,
1360                             stream->end_pos);
1361           }
1362           else {
1363             GstBuffer *buf;
1364             guint32   got_bytes;
1365
1366             if (*chunksize) {
1367               got_bytes = gst_bytestream_peek (bs, &buf, *chunksize);
1368
1369               GST_BUFFER_TIMESTAMP (buf) = next_ts;
1370
1371               if (stream->need_flush) {
1372                  /* FIXME, do some flush event here */
1373                 stream->need_flush = FALSE;
1374               }
1375               GST_DEBUG (0, "send stream %d: %lld %d %lld %08x", stream_id, next_ts, stream->current_frame - 1,
1376                             stream->delay, *chunksize);
1377
1378               gst_pad_push(stream->pad, buf);
1379             }
1380           }
1381         }
1382       }
1383
1384       *chunksize = (*chunksize + 1) & ~1;
1385       break;
1386     }
1387     default:
1388       GST_DEBUG (0, "  *****  unknown chunkid %08x (%s)", chunkid, gst_riff_id_to_fourcc (chunkid));
1389       *chunksize = (*chunksize + 1) & ~1;
1390       break;
1391   }
1392   GST_INFO (GST_CAT_PLUGIN_INFO, "chunkid %s, flush %08x, filepos %08llx", 
1393                   gst_riff_id_to_fourcc (chunkid), *chunksize, *filepos);
1394
1395   *filepos += *chunksize;
1396   if (!gst_bytestream_flush (bs, *chunksize)) {
1397     return gst_avi_demux_handle_sink_event (avi_demux);
1398   }
1399
1400 done:
1401
1402   return TRUE;
1403 }
1404
1405 static void
1406 gst_avi_demux_loop (GstElement *element)
1407 {
1408   GstAviDemux *avi_demux;
1409   guint32 chunksize;
1410   guint64 filepos = 0;
1411
1412   g_return_if_fail (element != NULL);
1413   g_return_if_fail (GST_IS_AVI_DEMUX (element));
1414
1415   avi_demux = GST_AVI_DEMUX (element);
1416
1417   avi_demux->restart = FALSE;
1418
1419   /* this is basically an infinite loop */
1420   if (!gst_avi_demux_process_chunk (avi_demux, &filepos, GST_RIFF_TAG_RIFF, 0, &chunksize)) {
1421     gst_element_error (element, "This doesn't appear to be an AVI file");
1422     return;
1423   }
1424   if (!avi_demux->restart)
1425     /* if we exit the loop we are EOS */
1426     gst_pad_event_default (avi_demux->sinkpad, gst_event_new (GST_EVENT_EOS));
1427 }
1428
1429 static GstElementStateReturn
1430 gst_avi_demux_change_state (GstElement *element)
1431 {
1432   GstAviDemux *avi_demux = GST_AVI_DEMUX (element);
1433
1434   switch (GST_STATE_TRANSITION (element)) {
1435     case GST_STATE_NULL_TO_READY:
1436       break;
1437     case GST_STATE_READY_TO_PAUSED:
1438       avi_demux->bs = gst_bytestream_new (avi_demux->sinkpad);
1439       avi_demux->last_seek = 0;
1440       break;
1441     case GST_STATE_PAUSED_TO_PLAYING:
1442       break;
1443     case GST_STATE_PLAYING_TO_PAUSED:
1444       break;
1445     case GST_STATE_PAUSED_TO_READY:
1446       gst_bytestream_destroy (avi_demux->bs);
1447       avi_demux->restart = TRUE;
1448       break;
1449     case GST_STATE_READY_TO_NULL:
1450       break;
1451     default:
1452       break;
1453   }
1454
1455   parent_class->change_state (element);
1456
1457   return GST_STATE_SUCCESS;
1458 }
1459
1460 static void
1461 gst_avi_demux_get_property (GObject *object, guint prop_id, GValue *value,
1462                             GParamSpec *pspec)
1463 {
1464   GstAviDemux *src;
1465
1466   g_return_if_fail (GST_IS_AVI_DEMUX (object));
1467
1468   src = GST_AVI_DEMUX (object);
1469
1470   switch (prop_id) {
1471     case ARG_BITRATE:
1472       break;
1473     default:
1474       break;
1475   }
1476 }
1477
1478 static gboolean
1479 plugin_init (GModule *module, GstPlugin *plugin)
1480 {
1481   GstElementFactory *factory;
1482   GstTypeFactory *type;
1483
1484   /* this filter needs the riff parser */
1485   if (!gst_library_load ("gstbytestream"))
1486     return FALSE;
1487   if (!gst_library_load ("gstriff"))
1488     return FALSE;
1489
1490   /* create an elementfactory for the avi_demux element */
1491   factory = gst_element_factory_new ("avidemux", GST_TYPE_AVI_DEMUX,
1492                                      &gst_avi_demux_details);
1493   g_return_val_if_fail (factory != NULL, FALSE);
1494   gst_element_factory_set_rank (factory, GST_ELEMENT_RANK_PRIMARY);
1495
1496   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_audio_templ));
1497   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_video_templ));
1498   gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (sink_templ));
1499
1500   type = gst_type_factory_new (&avidefinition);
1501   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type));
1502
1503   gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
1504
1505   return TRUE;
1506 }
1507
1508 GstPluginDesc plugin_desc = {
1509   GST_VERSION_MAJOR,
1510   GST_VERSION_MINOR,
1511   "avidemux",
1512   plugin_init
1513 };
1514