avi: add missing include for sscanf
[platform/upstream/gst-plugins-good.git] / gst / avi / gstavidemux.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
3  * Copyright (C) <2006> Nokia Corporation (contact <stefan.kost@nokia.com>)
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 /* Element-Checklist-Version: 5 */
21
22 /**
23  * SECTION:element-avidemux
24  *
25  * Demuxes an .avi file into raw or compressed audio and/or video streams.
26  *
27  * This element supports both push and pull-based scheduling, depending on the
28  * capabilities of the upstream elements.
29  *
30  * <refsect2>
31  * <title>Example launch line</title>
32  * |[
33  * gst-launch filesrc location=test.avi ! avidemux name=demux  demux.audio_00 ! decodebin ! audioconvert ! audioresample ! autoaudiosink   demux.video_00 ! queue ! decodebin ! ffmpegcolorspace ! videoscale ! autovideosink
34  * ]| Play (parse and decode) an .avi file and try to output it to
35  * an automatically detected soundcard and videosink. If the AVI file contains
36  * compressed audio or video data, this will only work if you have the
37  * right decoder elements/plugins installed.
38  * </refsect2>
39  *
40  * Last reviewed on 2006-12-29 (0.10.6)
41  */
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46
47 #include <string.h>
48 #include <stdio.h>
49
50 #include "gst/riff/riff-media.h"
51 #include "gstavidemux.h"
52 #include "avi-ids.h"
53 #include <gst/gst-i18n-plugin.h>
54 #include <gst/base/gstadapter.h>
55
56
57 #define DIV_ROUND_UP(s,v) (((s) + ((v)-1)) / (v))
58
59 GST_DEBUG_CATEGORY_STATIC (avidemux_debug);
60 #define GST_CAT_DEFAULT avidemux_debug
61
62 static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
63     GST_PAD_SINK,
64     GST_PAD_ALWAYS,
65     GST_STATIC_CAPS ("video/x-msvideo")
66     );
67
68 static void gst_avi_demux_base_init (GstAviDemuxClass * klass);
69 static void gst_avi_demux_class_init (GstAviDemuxClass * klass);
70 static void gst_avi_demux_init (GstAviDemux * avi);
71 static void gst_avi_demux_finalize (GObject * object);
72
73 static void gst_avi_demux_reset (GstAviDemux * avi);
74
75 #if 0
76 static const GstEventMask *gst_avi_demux_get_event_mask (GstPad * pad);
77 #endif
78 static gboolean gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event);
79 static gboolean gst_avi_demux_handle_sink_event (GstPad * pad,
80     GstEvent * event);
81 static gboolean gst_avi_demux_push_event (GstAviDemux * avi, GstEvent * event);
82
83 #if 0
84 static const GstFormat *gst_avi_demux_get_src_formats (GstPad * pad);
85 #endif
86 static const GstQueryType *gst_avi_demux_get_src_query_types (GstPad * pad);
87 static gboolean gst_avi_demux_handle_src_query (GstPad * pad, GstQuery * query);
88 static gboolean gst_avi_demux_src_convert (GstPad * pad, GstFormat src_format,
89     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
90
91 static gboolean gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment);
92 static gboolean gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad,
93     GstEvent * event);
94 static gboolean gst_avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad,
95     GstEvent * event);
96 static void gst_avi_demux_loop (GstPad * pad);
97 static gboolean gst_avi_demux_sink_activate (GstPad * sinkpad);
98 static gboolean gst_avi_demux_sink_activate_pull (GstPad * sinkpad,
99     gboolean active);
100 static gboolean gst_avi_demux_activate_push (GstPad * pad, gboolean active);
101 static GstFlowReturn gst_avi_demux_chain (GstPad * pad, GstBuffer * buf);
102
103 static void gst_avi_demux_set_index (GstElement * element, GstIndex * index);
104 static GstIndex *gst_avi_demux_get_index (GstElement * element);
105 static GstStateChangeReturn gst_avi_demux_change_state (GstElement * element,
106     GstStateChange transition);
107
108 static void gst_avi_demux_parse_idit (GstAviDemux * avi, GstBuffer * buf);
109
110 static GstElementClass *parent_class = NULL;
111
112 /* GObject methods */
113
114 GType
115 gst_avi_demux_get_type (void)
116 {
117   static GType avi_demux_type = 0;
118
119   if (!avi_demux_type) {
120     static const GTypeInfo avi_demux_info = {
121       sizeof (GstAviDemuxClass),
122       (GBaseInitFunc) gst_avi_demux_base_init,
123       NULL,
124       (GClassInitFunc) gst_avi_demux_class_init,
125       NULL,
126       NULL,
127       sizeof (GstAviDemux),
128       0,
129       (GInstanceInitFunc) gst_avi_demux_init,
130     };
131
132     avi_demux_type =
133         g_type_register_static (GST_TYPE_ELEMENT,
134         "GstAviDemux", &avi_demux_info, 0);
135   }
136
137   return avi_demux_type;
138 }
139
140 static void
141 gst_avi_demux_base_init (GstAviDemuxClass * klass)
142 {
143   static const GstElementDetails gst_avi_demux_details =
144       GST_ELEMENT_DETAILS ("Avi demuxer",
145       "Codec/Demuxer",
146       "Demultiplex an avi file into audio and video",
147       "Erik Walthinsen <omega@cse.ogi.edu>\n"
148       "Wim Taymans <wim.taymans@chello.be>\n"
149       "Thijs Vermeir <thijsvermeir@gmail.com>");
150   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
151   GstPadTemplate *videosrctempl, *audiosrctempl, *subsrctempl;
152   GstCaps *audcaps, *vidcaps, *subcaps;
153
154   audcaps = gst_riff_create_audio_template_caps ();
155   gst_caps_append (audcaps, gst_caps_new_simple ("audio/x-avi-unknown", NULL));
156   audiosrctempl = gst_pad_template_new ("audio_%02d",
157       GST_PAD_SRC, GST_PAD_SOMETIMES, audcaps);
158
159   vidcaps = gst_riff_create_video_template_caps ();
160   gst_caps_append (vidcaps, gst_riff_create_iavs_template_caps ());
161   gst_caps_append (vidcaps, gst_caps_new_simple ("video/x-avi-unknown", NULL));
162   videosrctempl = gst_pad_template_new ("video_%02d",
163       GST_PAD_SRC, GST_PAD_SOMETIMES, vidcaps);
164
165   subcaps = gst_caps_new_simple ("application/x-subtitle-avi", NULL);
166   subsrctempl = gst_pad_template_new ("subtitle_%02d",
167       GST_PAD_SRC, GST_PAD_SOMETIMES, subcaps);
168   gst_element_class_add_pad_template (element_class, audiosrctempl);
169   gst_element_class_add_pad_template (element_class, videosrctempl);
170   gst_element_class_add_pad_template (element_class, subsrctempl);
171   gst_element_class_add_pad_template (element_class,
172       gst_static_pad_template_get (&sink_templ));
173   gst_element_class_set_details (element_class, &gst_avi_demux_details);
174 }
175
176 static void
177 gst_avi_demux_class_init (GstAviDemuxClass * klass)
178 {
179   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
180   GObjectClass *gobject_class = (GObjectClass *) klass;
181
182   GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux",
183       0, "Demuxer for AVI streams");
184
185   parent_class = g_type_class_peek_parent (klass);
186
187   gobject_class->finalize = gst_avi_demux_finalize;
188   gstelement_class->change_state =
189       GST_DEBUG_FUNCPTR (gst_avi_demux_change_state);
190
191   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_avi_demux_set_index);
192   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_avi_demux_get_index);
193 }
194
195 static void
196 gst_avi_demux_init (GstAviDemux * avi)
197 {
198   avi->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
199   gst_pad_set_activate_function (avi->sinkpad,
200       GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate));
201   gst_pad_set_activatepull_function (avi->sinkpad,
202       GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate_pull));
203   gst_pad_set_activatepush_function (avi->sinkpad,
204       GST_DEBUG_FUNCPTR (gst_avi_demux_activate_push));
205   gst_pad_set_chain_function (avi->sinkpad,
206       GST_DEBUG_FUNCPTR (gst_avi_demux_chain));
207   gst_pad_set_event_function (avi->sinkpad,
208       GST_DEBUG_FUNCPTR (gst_avi_demux_handle_sink_event));
209   gst_element_add_pad (GST_ELEMENT (avi), avi->sinkpad);
210
211   avi->adapter = gst_adapter_new ();
212
213   gst_avi_demux_reset (avi);
214 }
215
216 static void
217 gst_avi_demux_finalize (GObject * object)
218 {
219   GstAviDemux *avi = GST_AVI_DEMUX (object);
220
221   GST_DEBUG ("AVI: finalize");
222
223   g_object_unref (avi->adapter);
224
225   G_OBJECT_CLASS (parent_class)->finalize (object);
226 }
227
228 static void
229 gst_avi_demux_reset_stream (GstAviDemux * avi, GstAviStream * stream)
230 {
231   g_free (stream->strh);
232   g_free (stream->strf.data);
233   g_free (stream->name);
234   g_free (stream->index);
235   g_free (stream->indexes);
236   if (stream->initdata)
237     gst_buffer_unref (stream->initdata);
238   if (stream->extradata)
239     gst_buffer_unref (stream->extradata);
240   if (stream->pad) {
241     if (stream->exposed) {
242       gst_pad_set_active (stream->pad, FALSE);
243       gst_element_remove_pad (GST_ELEMENT (avi), stream->pad);
244     } else
245       gst_object_unref (stream->pad);
246   }
247   if (stream->taglist) {
248     gst_tag_list_free (stream->taglist);
249     stream->taglist = NULL;
250   }
251   memset (stream, 0, sizeof (GstAviStream));
252 }
253
254 static void
255 gst_avi_demux_reset (GstAviDemux * avi)
256 {
257   gint i;
258
259   GST_DEBUG ("AVI: reset");
260
261   for (i = 0; i < avi->num_streams; i++)
262     gst_avi_demux_reset_stream (avi, &avi->stream[i]);
263
264   avi->header_state = GST_AVI_DEMUX_HEADER_TAG_LIST;
265   avi->num_streams = 0;
266   avi->num_v_streams = 0;
267   avi->num_a_streams = 0;
268   avi->num_t_streams = 0;
269   avi->main_stream = -1;
270
271   avi->state = GST_AVI_DEMUX_START;
272   avi->offset = 0;
273
274   avi->index_offset = 0;
275   g_free (avi->avih);
276   avi->avih = NULL;
277
278   if (avi->element_index)
279     gst_object_unref (avi->element_index);
280   avi->element_index = NULL;
281
282   if (avi->seek_event) {
283     gst_event_unref (avi->seek_event);
284     avi->seek_event = NULL;
285   }
286
287   if (avi->globaltags)
288     gst_tag_list_free (avi->globaltags);
289   avi->globaltags = NULL;
290
291   avi->got_tags = TRUE;         /* we always want to push global tags */
292   avi->have_eos = FALSE;
293   avi->seekable = TRUE;
294
295   gst_adapter_clear (avi->adapter);
296
297   gst_segment_init (&avi->segment, GST_FORMAT_TIME);
298 }
299
300
301 /* GstElement methods */
302
303 #if 0
304 static const GstFormat *
305 gst_avi_demux_get_src_formats (GstPad * pad)
306 {
307   GstAviStream *stream = gst_pad_get_element_private (pad);
308
309   static const GstFormat src_a_formats[] = {
310     GST_FORMAT_TIME,
311     GST_FORMAT_BYTES,
312     GST_FORMAT_DEFAULT,
313     0
314   };
315   static const GstFormat src_v_formats[] = {
316     GST_FORMAT_TIME,
317     GST_FORMAT_DEFAULT,
318     0
319   };
320
321   return (stream->strh->type == GST_RIFF_FCC_auds ?
322       src_a_formats : src_v_formats);
323 }
324 #endif
325
326 /* assumes stream->strf.auds->av_bps != 0 */
327 static inline GstClockTime
328 avi_stream_convert_bytes_to_time_unchecked (GstAviStream * stream,
329     guint64 bytes)
330 {
331   return gst_util_uint64_scale_int (bytes, GST_SECOND,
332       stream->strf.auds->av_bps);
333 }
334
335 static inline guint64
336 avi_stream_convert_time_to_bytes_unchecked (GstAviStream * stream,
337     GstClockTime time)
338 {
339   return gst_util_uint64_scale_int (time, stream->strf.auds->av_bps,
340       GST_SECOND);
341 }
342
343 /* assumes stream->strh->rate != 0 */
344 static inline GstClockTime
345 avi_stream_convert_frames_to_time_unchecked (GstAviStream * stream,
346     guint64 frames)
347 {
348   return gst_util_uint64_scale (frames, stream->strh->scale * GST_SECOND,
349       stream->strh->rate);
350 }
351
352 static inline guint64
353 avi_stream_convert_time_to_frames_unchecked (GstAviStream * stream,
354     GstClockTime time)
355 {
356   return gst_util_uint64_scale (time, stream->strh->rate,
357       stream->strh->scale * GST_SECOND);
358 }
359
360 static gboolean
361 gst_avi_demux_src_convert (GstPad * pad,
362     GstFormat src_format,
363     gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
364 {
365   GstAviStream *stream = gst_pad_get_element_private (pad);
366   gboolean res = TRUE;
367
368   GST_LOG_OBJECT (pad,
369       "Received  src_format:%s, src_value:%" G_GUINT64_FORMAT
370       ", dest_format:%s", gst_format_get_name (src_format), src_value,
371       gst_format_get_name (*dest_format));
372
373   if (G_UNLIKELY (src_format == *dest_format)) {
374     *dest_value = src_value;
375     goto done;
376   }
377   if (G_UNLIKELY (!stream->strh || !stream->strf.data)) {
378     res = FALSE;
379     goto done;
380   }
381   if (G_UNLIKELY (stream->strh->type == GST_RIFF_FCC_vids &&
382           (src_format == GST_FORMAT_BYTES
383               || *dest_format == GST_FORMAT_BYTES))) {
384     res = FALSE;
385     goto done;
386   }
387
388   switch (src_format) {
389     case GST_FORMAT_TIME:
390       switch (*dest_format) {
391         case GST_FORMAT_BYTES:
392           *dest_value = gst_util_uint64_scale_int (src_value,
393               stream->strf.auds->av_bps, GST_SECOND);
394           break;
395         case GST_FORMAT_DEFAULT:
396           *dest_value =
397               gst_util_uint64_scale_round (src_value, stream->strh->rate,
398               stream->strh->scale * GST_SECOND);
399           break;
400         default:
401           res = FALSE;
402           break;
403       }
404       break;
405     case GST_FORMAT_BYTES:
406       switch (*dest_format) {
407         case GST_FORMAT_TIME:
408           if (stream->strf.auds->av_bps != 0) {
409             *dest_value = avi_stream_convert_bytes_to_time_unchecked (stream,
410                 src_value);
411           } else
412             res = FALSE;
413           break;
414         default:
415           res = FALSE;
416           break;
417       }
418       break;
419     case GST_FORMAT_DEFAULT:
420       switch (*dest_format) {
421         case GST_FORMAT_TIME:
422           *dest_value =
423               avi_stream_convert_frames_to_time_unchecked (stream, src_value);
424           break;
425         default:
426           res = FALSE;
427           break;
428       }
429       break;
430     default:
431       res = FALSE;
432   }
433
434 done:
435   GST_LOG_OBJECT (pad,
436       "Returning res:%d dest_format:%s dest_value:%" G_GUINT64_FORMAT, res,
437       gst_format_get_name (*dest_format), *dest_value);
438   return res;
439 }
440
441 static const GstQueryType *
442 gst_avi_demux_get_src_query_types (GstPad * pad)
443 {
444   static const GstQueryType src_types[] = {
445     GST_QUERY_POSITION,
446     GST_QUERY_DURATION,
447     GST_QUERY_SEEKING,
448     GST_QUERY_CONVERT,
449     0
450   };
451
452   return src_types;
453 }
454
455 static gboolean
456 gst_avi_demux_handle_src_query (GstPad * pad, GstQuery * query)
457 {
458   gboolean res = TRUE;
459   GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
460
461   GstAviStream *stream = gst_pad_get_element_private (pad);
462
463   if (!stream->strh || !stream->strf.data)
464     return gst_pad_query_default (pad, query);
465
466   switch (GST_QUERY_TYPE (query)) {
467     case GST_QUERY_POSITION:{
468       gint64 pos = 0;
469
470       GST_DEBUG ("pos query for stream %u: frames %u, bytes %u",
471           stream->num, stream->current_entry, stream->current_total);
472
473       /* FIXME, this looks clumsy */
474       if (stream->strh->type == GST_RIFF_FCC_auds) {
475         if (stream->is_vbr) {
476           /* VBR */
477           pos = gst_util_uint64_scale ((gint64) stream->current_entry *
478               stream->strh->scale, GST_SECOND, (guint64) stream->strh->rate);
479           GST_DEBUG_OBJECT (avi, "VBR convert frame %u, time %"
480               GST_TIME_FORMAT, stream->current_entry, GST_TIME_ARGS (pos));
481         } else if (stream->strf.auds->av_bps != 0) {
482           /* CBR */
483           pos = gst_util_uint64_scale (stream->current_total, GST_SECOND,
484               (guint64) stream->strf.auds->av_bps);
485           GST_DEBUG_OBJECT (avi,
486               "CBR convert bytes %u, time %" GST_TIME_FORMAT,
487               stream->current_total, GST_TIME_ARGS (pos));
488         } else if (stream->idx_n != 0 && stream->total_bytes != 0) {
489           /* calculate timestamps based on percentage of length */
490           guint64 xlen = avi->avih->us_frame *
491               avi->avih->tot_frames * GST_USECOND;
492
493           if (stream->is_vbr) {
494             pos = gst_util_uint64_scale (xlen, stream->current_entry,
495                 stream->idx_n);
496             GST_DEBUG_OBJECT (avi, "VBR perc convert frame %u, time %"
497                 GST_TIME_FORMAT, stream->current_entry, GST_TIME_ARGS (pos));
498           } else {
499             pos = gst_util_uint64_scale (xlen, stream->current_total,
500                 stream->total_bytes);
501             GST_DEBUG_OBJECT (avi,
502                 "CBR perc convert bytes %u, time %" GST_TIME_FORMAT,
503                 stream->current_total, GST_TIME_ARGS (pos));
504           }
505         } else {
506           /* we don't know */
507           res = FALSE;
508         }
509       } else {
510         if (stream->strh->rate != 0) {
511           pos = gst_util_uint64_scale ((guint64) stream->current_entry *
512               stream->strh->scale, GST_SECOND, (guint64) stream->strh->rate);
513         } else {
514           pos = stream->current_entry * avi->avih->us_frame * GST_USECOND;
515         }
516       }
517       if (res) {
518         GST_DEBUG ("pos query : %" GST_TIME_FORMAT, GST_TIME_ARGS (pos));
519         gst_query_set_position (query, GST_FORMAT_TIME, pos);
520       } else
521         GST_WARNING ("pos query failed");
522       break;
523     }
524     case GST_QUERY_DURATION:
525     {
526       GstFormat fmt;
527
528       if (stream->strh->type != GST_RIFF_FCC_auds &&
529           stream->strh->type != GST_RIFF_FCC_vids) {
530         res = FALSE;
531         break;
532       }
533
534       gst_query_parse_duration (query, &fmt, NULL);
535
536       switch (fmt) {
537         case GST_FORMAT_TIME:
538           gst_query_set_duration (query, fmt, stream->duration);
539           break;
540         case GST_FORMAT_DEFAULT:
541         {
542           gint64 dur;
543           GST_DEBUG_OBJECT (query, "total frames is %" G_GUINT32_FORMAT,
544               stream->idx_n);
545
546           if (stream->idx_n >= 0)
547             gst_query_set_duration (query, fmt, stream->idx_n);
548           else if (gst_pad_query_convert (pad, GST_FORMAT_TIME,
549                   stream->duration, &fmt, &dur))
550             gst_query_set_duration (query, fmt, dur);
551           break;
552         }
553         default:
554           res = FALSE;
555           break;
556       }
557       break;
558     }
559     case GST_QUERY_SEEKING:{
560       GstFormat fmt;
561
562       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
563       if (fmt == GST_FORMAT_TIME) {
564         gboolean seekable = TRUE;
565
566         if (avi->streaming) {
567           seekable = avi->seekable;
568         }
569
570         gst_query_set_seeking (query, GST_FORMAT_TIME, seekable,
571             0, stream->duration);
572         res = TRUE;
573       }
574       break;
575     }
576     case GST_QUERY_CONVERT:{
577       GstFormat src_fmt, dest_fmt;
578       gint64 src_val, dest_val;
579
580       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
581       if ((res = gst_avi_demux_src_convert (pad, src_fmt, src_val, &dest_fmt,
582                   &dest_val)))
583         gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
584       else
585         res = gst_pad_query_default (pad, query);
586       break;
587     }
588     default:
589       res = gst_pad_query_default (pad, query);
590       break;
591   }
592
593   gst_object_unref (avi);
594   return res;
595 }
596
597 #if 0
598 static const GstEventMask *
599 gst_avi_demux_get_event_mask (GstPad * pad)
600 {
601   static const GstEventMask masks[] = {
602     {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT},
603     {0,}
604   };
605
606   return masks;
607 }
608 #endif
609
610 static guint64
611 gst_avi_demux_seek_streams (GstAviDemux * avi, guint64 offset, gboolean before)
612 {
613   GstAviStream *stream;
614   GstIndexEntry *entry;
615   gint i;
616   gint64 val, min = offset;
617
618   for (i = 0; i < avi->num_streams; i++) {
619     stream = &avi->stream[i];
620
621     entry = gst_index_get_assoc_entry (avi->element_index, stream->index_id,
622         before ? GST_INDEX_LOOKUP_BEFORE : GST_INDEX_LOOKUP_AFTER,
623         GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, offset);
624
625     if (before) {
626       if (entry) {
627         GST_DEBUG_OBJECT (avi, "stream %d, previous entry at %"
628             G_GUINT64_FORMAT, i, val);
629         gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &val);
630         if (val < min)
631           min = val;
632       }
633       continue;
634     }
635
636     if (!entry) {
637       GST_DEBUG_OBJECT (avi, "no position for stream %d, assuming at start", i);
638       stream->current_entry = 0;
639       stream->current_total = 0;
640       continue;
641     }
642
643     gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &val);
644     GST_DEBUG_OBJECT (avi, "stream %d, next entry at %" G_GUINT64_FORMAT,
645         i, val);
646
647     gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &val);
648     stream->current_total = val;
649     gst_index_entry_assoc_map (entry, GST_FORMAT_DEFAULT, &val);
650     stream->current_entry = val;
651   }
652
653   return min;
654 }
655
656 #define GST_AVI_SEEK_PUSH_DISPLACE     (4 * GST_SECOND)
657
658 static gboolean
659 gst_avi_demux_handle_sink_event (GstPad * pad, GstEvent * event)
660 {
661   gboolean res = TRUE;
662   GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
663
664   GST_DEBUG_OBJECT (avi,
665       "have event type %s: %p on sink pad", GST_EVENT_TYPE_NAME (event), event);
666
667   switch (GST_EVENT_TYPE (event)) {
668     case GST_EVENT_NEWSEGMENT:
669     {
670       GstFormat format;
671       gdouble rate, arate;
672       gint64 start, stop, time, offset = 0;
673       gboolean update;
674       GstSegment segment;
675       GstIndexEntry *entry;
676
677       /* some debug output */
678       gst_segment_init (&segment, GST_FORMAT_UNDEFINED);
679       gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
680           &start, &stop, &time);
681       gst_segment_set_newsegment_full (&segment, update, rate, arate, format,
682           start, stop, time);
683       GST_DEBUG_OBJECT (avi,
684           "received format %d newsegment %" GST_SEGMENT_FORMAT, format,
685           &segment);
686
687       /* chain will send initial newsegment after pads have been added */
688       if (avi->state != GST_AVI_DEMUX_MOVI) {
689         GST_DEBUG_OBJECT (avi, "still starting, eating event");
690         goto exit;
691       }
692
693       /* we only expect a BYTE segment, e.g. following a seek */
694       if (format != GST_FORMAT_BYTES) {
695         GST_DEBUG_OBJECT (avi, "unsupported segment format, ignoring");
696         goto exit;
697       }
698
699       if (!avi->element_index) {
700         GST_WARNING_OBJECT (avi, "no index data, forcing EOS");
701         goto eos;
702       }
703
704       /* Let's check if we have an index entry for this position */
705       entry = gst_index_get_assoc_entry (avi->element_index, avi->index_id,
706           GST_INDEX_LOOKUP_AFTER, GST_ASSOCIATION_FLAG_NONE,
707           GST_FORMAT_BYTES, start);
708
709       /* we can not go where we have not yet been before ... */
710       if (!entry) {
711         GST_WARNING_OBJECT (avi, "insufficient index data, forcing EOS");
712         goto eos;
713       }
714
715       offset = start;
716       gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
717       gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &start);
718       stop = GST_CLOCK_TIME_NONE;
719
720       /* compensate for slack */
721       if (time)
722         time += GST_AVI_SEEK_PUSH_DISPLACE;
723
724       /* set up segment and send downstream */
725       gst_segment_set_newsegment_full (&avi->segment, update, rate, arate,
726           GST_FORMAT_TIME, time, stop, time);
727       GST_DEBUG_OBJECT (avi, "Pushing newseg update %d, rate %g, "
728           "applied rate %g, format %d, start %" G_GINT64_FORMAT ", "
729           "stop %" G_GINT64_FORMAT, update, rate, arate, GST_FORMAT_TIME,
730           time, stop);
731       gst_avi_demux_push_event (avi,
732           gst_event_new_new_segment_full (update, rate, arate, GST_FORMAT_TIME,
733               time, stop, time));
734
735       GST_DEBUG_OBJECT (avi, "next chunk expected at %" G_GINT64_FORMAT, start);
736
737       /* adjust state for streaming thread accordingly */
738       avi->offset = offset;
739       gst_avi_demux_seek_streams (avi, offset, FALSE);
740
741       /* set up streaming thread */
742       avi->offset = offset;
743       avi->todrop = start - offset;
744
745     exit:
746       /* in any case, clear leftover in current segment, if any */
747       gst_adapter_clear (avi->adapter);
748       gst_event_unref (event);
749       res = TRUE;
750       break;
751     eos:
752       /* set up for EOS */
753       avi->have_eos = TRUE;
754       goto exit;
755     }
756     case GST_EVENT_EOS:
757     {
758       if (avi->state != GST_AVI_DEMUX_MOVI) {
759         gst_event_unref (event);
760         GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
761             (NULL), ("got eos and didn't receive a complete header object"));
762       } else if (!gst_avi_demux_push_event (avi, event)) {
763         GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
764             (NULL), ("got eos but no streams (yet)"));
765       }
766       break;
767     }
768     default:
769       res = gst_pad_event_default (pad, event);
770       break;
771   }
772
773   gst_object_unref (avi);
774
775   return res;
776 }
777
778 static gboolean
779 gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event)
780 {
781   gboolean res = TRUE;
782   GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
783
784   GST_DEBUG_OBJECT (avi,
785       "have event type %s: %p on src pad", GST_EVENT_TYPE_NAME (event), event);
786
787   switch (GST_EVENT_TYPE (event)) {
788     case GST_EVENT_SEEK:
789       /* handle seeking only in pull mode */
790       if (!avi->streaming) {
791         res = gst_avi_demux_handle_seek (avi, pad, event);
792       } else {
793         res = gst_avi_demux_handle_seek_push (avi, pad, event);
794       }
795       gst_event_unref (event);
796       break;
797     case GST_EVENT_QOS:
798     case GST_EVENT_NAVIGATION:
799       res = FALSE;
800       gst_event_unref (event);
801       break;
802     default:
803       res = gst_pad_event_default (pad, event);
804       break;
805   }
806
807   gst_object_unref (avi);
808
809   return res;
810 }
811
812 /* streaming helper (push) */
813
814 /*
815  * gst_avi_demux_peek_chunk_info:
816  * @avi: Avi object
817  * @tag: holder for tag
818  * @size: holder for tag size
819  *
820  * Peek next chunk info (tag and size)
821  *
822  * Returns: TRUE when one chunk info has been got
823  */
824 static gboolean
825 gst_avi_demux_peek_chunk_info (GstAviDemux * avi, guint32 * tag, guint32 * size)
826 {
827   const guint8 *data = NULL;
828
829   if (gst_adapter_available (avi->adapter) < 8)
830     return FALSE;
831
832   data = gst_adapter_peek (avi->adapter, 8);
833   *tag = GST_READ_UINT32_LE (data);
834   *size = GST_READ_UINT32_LE (data + 4);
835
836   return TRUE;
837 }
838
839 /*
840  * gst_avi_demux_peek_chunk:
841  * @avi: Avi object
842  * @tag: holder for tag
843  * @size: holder for tag size
844  *
845  * Peek enough data for one full chunk
846  *
847  * Returns: %TRUE when one chunk has been got
848  */
849 static gboolean
850 gst_avi_demux_peek_chunk (GstAviDemux * avi, guint32 * tag, guint32 * size)
851 {
852   guint32 peek_size = 0;
853   gint available;
854
855   if (!gst_avi_demux_peek_chunk_info (avi, tag, size))
856     goto peek_failed;
857
858   /* size 0 -> empty data buffer would surprise most callers,
859    * large size -> do not bother trying to squeeze that into adapter,
860    * so we throw poor man's exception, which can be caught if caller really
861    * wants to handle 0 size chunk */
862   if (!(*size) || (*size) >= (1 << 30))
863     goto strange_size;
864
865   peek_size = (*size + 1) & ~1;
866   available = gst_adapter_available (avi->adapter);
867
868   GST_DEBUG_OBJECT (avi,
869       "Need to peek chunk of %d bytes to read chunk %" GST_FOURCC_FORMAT
870       ", %d bytes available", *size, GST_FOURCC_ARGS (*tag), available);
871
872   if (available < (8 + peek_size))
873     goto need_more;
874
875   return TRUE;
876
877   /* ERRORS */
878 peek_failed:
879   {
880     GST_INFO_OBJECT (avi, "Failed to peek");
881     return FALSE;
882   }
883 strange_size:
884   {
885     GST_INFO_OBJECT (avi,
886         "Invalid/unexpected chunk size %d for tag %" GST_FOURCC_FORMAT, *size,
887         GST_FOURCC_ARGS (*tag));
888     /* chain should give up */
889     avi->abort_buffering = TRUE;
890     return FALSE;
891   }
892 need_more:
893   {
894     GST_INFO_OBJECT (avi, "need more %d < %" G_GUINT32_FORMAT,
895         available, 8 + peek_size);
896     return FALSE;
897   }
898 }
899
900 /* AVI init */
901
902 /*
903  * gst_avi_demux_parse_file_header:
904  * @element: caller element (used for errors/debug).
905  * @buf: input data to be used for parsing.
906  *
907  * "Open" a RIFF/AVI file. The buffer should be at least 12
908  * bytes long. Takes ownership of @buf.
909  *
910  * Returns: TRUE if the file is a RIFF/AVI file, FALSE otherwise.
911  *          Throws an error, caller should error out (fatal).
912  */
913 static gboolean
914 gst_avi_demux_parse_file_header (GstElement * element, GstBuffer * buf)
915 {
916   guint32 doctype;
917   GstClockTime stamp;
918
919   stamp = gst_util_get_timestamp ();
920
921   /* riff_parse posts an error */
922   if (!gst_riff_parse_file_header (element, buf, &doctype))
923     return FALSE;
924
925   if (doctype != GST_RIFF_RIFF_AVI)
926     goto not_avi;
927
928   stamp = gst_util_get_timestamp () - stamp;
929   GST_DEBUG_OBJECT (element, "header parsing took %" GST_TIME_FORMAT,
930       GST_TIME_ARGS (stamp));
931
932   return TRUE;
933
934   /* ERRORS */
935 not_avi:
936   {
937     GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
938         ("File is not an AVI file: %" GST_FOURCC_FORMAT,
939             GST_FOURCC_ARGS (doctype)));
940     return FALSE;
941   }
942 }
943
944 /*
945  * Read AVI file tag when streaming
946  */
947 static GstFlowReturn
948 gst_avi_demux_stream_init_push (GstAviDemux * avi)
949 {
950   if (gst_adapter_available (avi->adapter) >= 12) {
951     GstBuffer *tmp;
952
953     tmp = gst_adapter_take_buffer (avi->adapter, 12);
954
955     GST_DEBUG ("Parsing avi header");
956     if (!gst_avi_demux_parse_file_header (GST_ELEMENT (avi), tmp)) {
957       return GST_FLOW_ERROR;
958     }
959     GST_DEBUG ("header ok");
960     avi->offset += 12;
961
962     avi->state = GST_AVI_DEMUX_HEADER;
963   }
964   return GST_FLOW_OK;
965 }
966
967 /*
968  * Read AVI file tag
969  */
970 static GstFlowReturn
971 gst_avi_demux_stream_init_pull (GstAviDemux * avi)
972 {
973   GstFlowReturn res;
974   GstBuffer *buf = NULL;
975
976   res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf);
977   if (res != GST_FLOW_OK)
978     return res;
979   else if (!gst_avi_demux_parse_file_header (GST_ELEMENT_CAST (avi), buf))
980     goto wrong_header;
981
982   avi->offset += 12;
983
984   return GST_FLOW_OK;
985
986   /* ERRORS */
987 wrong_header:
988   {
989     GST_DEBUG_OBJECT (avi, "error parsing file header");
990     return GST_FLOW_ERROR;
991   }
992 }
993
994 /* AVI header handling */
995
996 /*
997  * gst_avi_demux_parse_avih:
998  * @element: caller element (used for errors/debug).
999  * @buf: input data to be used for parsing.
1000  * @avih: pointer to structure (filled in by function) containing
1001  *        stream information (such as flags, number of streams, etc.).
1002  *
1003  * Read 'avih' header. Discards buffer after use.
1004  *
1005  * Returns: TRUE on success, FALSE otherwise. Throws an error if
1006  *          the header is invalid. The caller should error out
1007  *          (fatal).
1008  */
1009 static gboolean
1010 gst_avi_demux_parse_avih (GstElement * element,
1011     GstBuffer * buf, gst_riff_avih ** _avih)
1012 {
1013   gst_riff_avih *avih;
1014
1015   if (buf == NULL)
1016     goto no_buffer;
1017
1018   if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_avih))
1019     goto avih_too_small;
1020
1021   avih = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
1022
1023 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
1024   avih->us_frame = GUINT32_FROM_LE (avih->us_frame);
1025   avih->max_bps = GUINT32_FROM_LE (avih->max_bps);
1026   avih->pad_gran = GUINT32_FROM_LE (avih->pad_gran);
1027   avih->flags = GUINT32_FROM_LE (avih->flags);
1028   avih->tot_frames = GUINT32_FROM_LE (avih->tot_frames);
1029   avih->init_frames = GUINT32_FROM_LE (avih->init_frames);
1030   avih->streams = GUINT32_FROM_LE (avih->streams);
1031   avih->bufsize = GUINT32_FROM_LE (avih->bufsize);
1032   avih->width = GUINT32_FROM_LE (avih->width);
1033   avih->height = GUINT32_FROM_LE (avih->height);
1034   avih->scale = GUINT32_FROM_LE (avih->scale);
1035   avih->rate = GUINT32_FROM_LE (avih->rate);
1036   avih->start = GUINT32_FROM_LE (avih->start);
1037   avih->length = GUINT32_FROM_LE (avih->length);
1038 #endif
1039
1040   /* debug stuff */
1041   GST_INFO_OBJECT (element, "avih tag found:");
1042   GST_INFO_OBJECT (element, " us_frame    %u", avih->us_frame);
1043   GST_INFO_OBJECT (element, " max_bps     %u", avih->max_bps);
1044   GST_INFO_OBJECT (element, " pad_gran    %u", avih->pad_gran);
1045   GST_INFO_OBJECT (element, " flags       0x%08x", avih->flags);
1046   GST_INFO_OBJECT (element, " tot_frames  %u", avih->tot_frames);
1047   GST_INFO_OBJECT (element, " init_frames %u", avih->init_frames);
1048   GST_INFO_OBJECT (element, " streams     %u", avih->streams);
1049   GST_INFO_OBJECT (element, " bufsize     %u", avih->bufsize);
1050   GST_INFO_OBJECT (element, " width       %u", avih->width);
1051   GST_INFO_OBJECT (element, " height      %u", avih->height);
1052   GST_INFO_OBJECT (element, " scale       %u", avih->scale);
1053   GST_INFO_OBJECT (element, " rate        %u", avih->rate);
1054   GST_INFO_OBJECT (element, " start       %u", avih->start);
1055   GST_INFO_OBJECT (element, " length      %u", avih->length);
1056
1057   *_avih = avih;
1058   gst_buffer_unref (buf);
1059
1060   return TRUE;
1061
1062   /* ERRORS */
1063 no_buffer:
1064   {
1065     GST_ELEMENT_ERROR (element, STREAM, DEMUX, (NULL), ("No buffer"));
1066     return FALSE;
1067   }
1068 avih_too_small:
1069   {
1070     GST_ELEMENT_ERROR (element, STREAM, DEMUX, (NULL),
1071         ("Too small avih (%d available, %d needed)",
1072             GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_avih)));
1073     gst_buffer_unref (buf);
1074     return FALSE;
1075   }
1076 }
1077
1078 /*
1079  * gst_avi_demux_parse_superindex:
1080  * @avi: caller element (used for debugging/errors).
1081  * @buf: input data to use for parsing.
1082  * @locations: locations in the file (byte-offsets) that contain
1083  *             the actual indexes (see get_avi_demux_parse_subindex()).
1084  *             The array ends with GST_BUFFER_OFFSET_NONE.
1085  *
1086  * Reads superindex (openDML-2 spec stuff) from the provided data.
1087  *
1088  * Returns: TRUE on success, FALSE otherwise. Indexes should be skipped
1089  *          on error, but they are not fatal.
1090  */
1091 static gboolean
1092 gst_avi_demux_parse_superindex (GstAviDemux * avi,
1093     GstBuffer * buf, guint64 ** _indexes)
1094 {
1095   guint8 *data;
1096   guint16 bpe = 16;
1097   guint32 num, i;
1098   guint64 *indexes;
1099   guint size;
1100
1101   *_indexes = NULL;
1102
1103   size = buf ? GST_BUFFER_SIZE (buf) : 0;
1104   if (size < 24)
1105     goto too_small;
1106
1107   data = GST_BUFFER_DATA (buf);
1108
1109   /* check type of index. The opendml2 specs state that
1110    * there should be 4 dwords per array entry. Type can be
1111    * either frame or field (and we don't care). */
1112   if (GST_READ_UINT16_LE (data) != 4 ||
1113       (data[2] & 0xfe) != 0x0 || data[3] != 0x0) {
1114     GST_WARNING_OBJECT (avi,
1115         "Superindex for stream has unexpected "
1116         "size_entry %d (bytes) or flags 0x%02x/0x%02x",
1117         GST_READ_UINT16_LE (data), data[2], data[3]);
1118     bpe = GST_READ_UINT16_LE (data) * 4;
1119   }
1120   num = GST_READ_UINT32_LE (&data[4]);
1121
1122   GST_DEBUG_OBJECT (avi, "got %d indexes", num);
1123
1124   indexes = g_new (guint64, num + 1);
1125   for (i = 0; i < num; i++) {
1126     if (size < 24 + bpe * (i + 1))
1127       break;
1128     indexes[i] = GST_READ_UINT64_LE (&data[24 + bpe * i]);
1129     GST_DEBUG_OBJECT (avi, "index %d at %" G_GUINT64_FORMAT, i, indexes[i]);
1130   }
1131   indexes[i] = GST_BUFFER_OFFSET_NONE;
1132   *_indexes = indexes;
1133
1134   gst_buffer_unref (buf);
1135
1136   return TRUE;
1137
1138   /* ERRORS */
1139 too_small:
1140   {
1141     GST_ERROR_OBJECT (avi,
1142         "Not enough data to parse superindex (%d available, 24 needed)", size);
1143     if (buf)
1144       gst_buffer_unref (buf);
1145     return FALSE;
1146   }
1147 }
1148
1149 /* add an entry to the index of a stream. @num should be an estimate of the
1150  * total amount of index entries for all streams and is used to dynamically
1151  * allocate memory for the index entries. */
1152 static inline gboolean
1153 gst_avi_demux_add_index (GstAviDemux * avi, GstAviStream * stream,
1154     guint num, GstAviIndexEntry * entry)
1155 {
1156   /* ensure index memory */
1157   if (G_UNLIKELY (stream->idx_n >= stream->idx_max)) {
1158     guint idx_max = stream->idx_max;
1159     GstAviIndexEntry *new_idx;
1160
1161     /* we need to make some more room */
1162     if (idx_max == 0) {
1163       /* initial size guess, assume each stream has an equal amount of entries,
1164        * overshoot with at least 8K */
1165       idx_max = (num / avi->num_streams) + (8192 / sizeof (GstAviIndexEntry));
1166     } else {
1167       idx_max += 8192 / sizeof (GstAviIndexEntry);
1168       GST_DEBUG_OBJECT (avi, "expanded index from %u to %u",
1169           stream->idx_max, idx_max);
1170     }
1171     new_idx = g_try_renew (GstAviIndexEntry, stream->index, idx_max);
1172     /* out of memory, if this fails stream->index is untouched. */
1173     if (G_UNLIKELY (!new_idx))
1174       return FALSE;
1175     /* use new index */
1176     stream->index = new_idx;
1177     stream->idx_max = idx_max;
1178   }
1179
1180   /* update entry total and stream stats. The entry total can be converted to
1181    * the timestamp of the entry easily. */
1182   if (stream->strh->type == GST_RIFF_FCC_auds) {
1183     gint blockalign;
1184
1185     if (stream->is_vbr) {
1186       entry->total = stream->total_blocks;
1187     } else {
1188       entry->total = stream->total_bytes;
1189     }
1190     blockalign = stream->strf.auds->blockalign;
1191     if (blockalign > 0)
1192       stream->total_blocks += DIV_ROUND_UP (entry->size, blockalign);
1193     else
1194       stream->total_blocks++;
1195   } else {
1196     if (stream->is_vbr) {
1197       entry->total = stream->idx_n;
1198     } else {
1199       entry->total = stream->total_bytes;
1200     }
1201   }
1202   stream->total_bytes += entry->size;
1203   if (ENTRY_IS_KEYFRAME (entry))
1204     stream->n_keyframes++;
1205
1206   /* and add */
1207   GST_LOG_OBJECT (avi,
1208       "Adding stream %u, index entry %d, kf %d, size %u "
1209       ", offset %" G_GUINT64_FORMAT ", total %" G_GUINT64_FORMAT, stream->num,
1210       stream->idx_n, ENTRY_IS_KEYFRAME (entry), entry->size, entry->offset,
1211       entry->total);
1212   stream->index[stream->idx_n++] = *entry;
1213
1214   return TRUE;
1215 }
1216
1217 /* given @entry_n in @stream, calculate info such as timestamps and
1218  * offsets for the entry. */
1219 static void
1220 gst_avi_demux_get_buffer_info (GstAviDemux * avi, GstAviStream * stream,
1221     guint entry_n, GstClockTime * timestamp, GstClockTime * ts_end,
1222     guint64 * offset, guint64 * offset_end)
1223 {
1224   GstAviIndexEntry *entry;
1225
1226   entry = &stream->index[entry_n];
1227
1228   if (stream->is_vbr) {
1229     /* VBR stream next timestamp */
1230     if (stream->strh->type == GST_RIFF_FCC_auds) {
1231       if (timestamp)
1232         *timestamp =
1233             avi_stream_convert_frames_to_time_unchecked (stream, entry->total);
1234       if (ts_end)
1235         *ts_end = avi_stream_convert_frames_to_time_unchecked (stream,
1236             entry->total + 1);
1237     } else {
1238       if (timestamp)
1239         *timestamp =
1240             avi_stream_convert_frames_to_time_unchecked (stream, entry_n);
1241       if (ts_end)
1242         *ts_end = avi_stream_convert_frames_to_time_unchecked (stream,
1243             entry_n + 1);
1244     }
1245   } else if (stream->strh->type == GST_RIFF_FCC_auds) {
1246     /* constant rate stream */
1247     if (timestamp)
1248       *timestamp =
1249           avi_stream_convert_bytes_to_time_unchecked (stream, entry->total);
1250     if (ts_end)
1251       *ts_end = avi_stream_convert_bytes_to_time_unchecked (stream,
1252           entry->total + entry->size);
1253   }
1254   if (stream->strh->type == GST_RIFF_FCC_vids) {
1255     /* video offsets are the frame number */
1256     if (offset)
1257       *offset = entry_n;
1258     if (offset_end)
1259       *offset_end = entry_n + 1;
1260   } else {
1261     /* no offsets for audio */
1262     if (offset)
1263       *offset = -1;
1264     if (offset_end)
1265       *offset_end = -1;
1266   }
1267 }
1268
1269 /* collect and debug stats about the indexes for all streams.
1270  * This method is also responsible for filling in the stream duration
1271  * as measured by the amount of index entries.
1272  *
1273  * Returns TRUE if the index is not empty, else FALSE */
1274 static gboolean
1275 gst_avi_demux_do_index_stats (GstAviDemux * avi)
1276 {
1277   guint total_idx = 0;
1278   guint i;
1279 #ifndef GST_DISABLE_GST_DEBUG
1280   guint total_max = 0;
1281 #endif
1282
1283   /* get stream stats now */
1284   for (i = 0; i < avi->num_streams; i++) {
1285     GstAviStream *stream;
1286
1287     if (G_UNLIKELY (!(stream = &avi->stream[i])))
1288       continue;
1289     if (G_UNLIKELY (!stream->strh))
1290       continue;
1291     if (G_UNLIKELY (!stream->index || stream->idx_n == 0))
1292       continue;
1293
1294     /* we interested in the end_ts of the last entry, which is the total
1295      * duration of this stream */
1296     gst_avi_demux_get_buffer_info (avi, stream, stream->idx_n - 1,
1297         NULL, &stream->idx_duration, NULL, NULL);
1298
1299     total_idx += stream->idx_n;
1300 #ifndef GST_DISABLE_GST_DEBUG
1301     total_max += stream->idx_max;
1302 #endif
1303     GST_INFO_OBJECT (avi, "Stream %d, dur %" GST_TIME_FORMAT ", %6u entries, "
1304         "%5u keyframes, entry size = %2u, total size = %10u, allocated %10u",
1305         i, GST_TIME_ARGS (stream->idx_duration), stream->idx_n,
1306         stream->n_keyframes, (guint) sizeof (GstAviIndexEntry),
1307         (guint) (stream->idx_n * sizeof (GstAviIndexEntry)),
1308         (guint) (stream->idx_max * sizeof (GstAviIndexEntry)));
1309   }
1310   total_idx *= sizeof (GstAviIndexEntry);
1311 #ifndef GST_DISABLE_GST_DEBUG
1312   total_max *= sizeof (GstAviIndexEntry);
1313 #endif
1314   GST_INFO_OBJECT (avi, "%u bytes for index vs %u ideally, %u wasted",
1315       total_max, total_idx, total_max - total_idx);
1316
1317   if (total_idx == 0) {
1318     GST_WARNING_OBJECT (avi, "Index is empty !");
1319     return FALSE;
1320   }
1321   return TRUE;
1322 }
1323
1324 /*
1325  * gst_avi_demux_parse_subindex:
1326  * @avi: Avi object
1327  * @buf: input data to use for parsing.
1328  * @stream: stream context.
1329  * @entries_list: a list (returned by the function) containing all the
1330  *           indexes parsed in this specific subindex. The first
1331  *           entry is also a pointer to allocated memory that needs
1332  *           to be free´ed. May be NULL if no supported indexes were
1333  *           found.
1334  *
1335  * Reads superindex (openDML-2 spec stuff) from the provided data.
1336  * The buffer should contain a GST_RIFF_TAG_ix?? chunk.
1337  *
1338  * Returns: TRUE on success, FALSE otherwise. Errors are fatal, we
1339  *          throw an error, caller should bail out asap.
1340  */
1341 static gboolean
1342 gst_avi_demux_parse_subindex (GstAviDemux * avi, GstAviStream * stream,
1343     GstBuffer * buf)
1344 {
1345   guint8 *data;
1346   guint16 bpe;
1347   guint32 num, i;
1348   guint64 baseoff;
1349   guint size;
1350
1351   if (!buf)
1352     return TRUE;
1353
1354   size = GST_BUFFER_SIZE (buf);
1355
1356   /* check size */
1357   if (size < 24)
1358     goto too_small;
1359
1360   data = GST_BUFFER_DATA (buf);
1361
1362   /* We don't support index-data yet */
1363   if (data[3] & 0x80)
1364     goto not_implemented;
1365
1366   /* check type of index. The opendml2 specs state that
1367    * there should be 4 dwords per array entry. Type can be
1368    * either frame or field (and we don't care). */
1369   bpe = (data[2] & 0x01) ? 12 : 8;
1370   if (GST_READ_UINT16_LE (data) != bpe / 4 ||
1371       (data[2] & 0xfe) != 0x0 || data[3] != 0x1) {
1372     GST_WARNING_OBJECT (avi,
1373         "Superindex for stream %d has unexpected "
1374         "size_entry %d (bytes) or flags 0x%02x/0x%02x",
1375         stream->num, GST_READ_UINT16_LE (data), data[2], data[3]);
1376     bpe = GST_READ_UINT16_LE (data) * 4;
1377   }
1378   num = GST_READ_UINT32_LE (&data[4]);
1379   baseoff = GST_READ_UINT64_LE (&data[12]);
1380
1381   /* If there's nothing, just return ! */
1382   if (num == 0)
1383     goto empty_index;
1384
1385   GST_INFO_OBJECT (avi, "Parsing subindex, nr_entries = %6d", num);
1386
1387   for (i = 0; i < num; i++) {
1388     GstAviIndexEntry entry;
1389
1390     if (size < 24 + bpe * (i + 1))
1391       break;
1392
1393     /* fill in offset and size. offset contains the keyframe flag in the
1394      * upper bit*/
1395     entry.offset = baseoff + GST_READ_UINT32_LE (&data[24 + bpe * i]);
1396     entry.size = GST_READ_UINT32_LE (&data[24 + bpe * i + 4]);
1397     /* handle flags */
1398     if (stream->strh->type == GST_RIFF_FCC_auds) {
1399       /* all audio frames are keyframes */
1400       ENTRY_SET_KEYFRAME (&entry);
1401     } else {
1402       /* else read flags */
1403       entry.flags = (entry.size & 0x80000000) ? 0 : GST_AVI_KEYFRAME;
1404     }
1405     entry.size &= ~0x80000000;
1406
1407     /* and add */
1408     if (G_UNLIKELY (!gst_avi_demux_add_index (avi, stream, num, &entry)))
1409       goto out_of_mem;
1410   }
1411   gst_buffer_unref (buf);
1412
1413   return TRUE;
1414
1415   /* ERRORS */
1416 too_small:
1417   {
1418     GST_ERROR_OBJECT (avi,
1419         "Not enough data to parse subindex (%d available, 24 needed)", size);
1420     gst_buffer_unref (buf);
1421     return TRUE;                /* continue */
1422   }
1423 not_implemented:
1424   {
1425     GST_ELEMENT_ERROR (avi, STREAM, NOT_IMPLEMENTED, (NULL),
1426         ("Subindex-is-data is not implemented"));
1427     gst_buffer_unref (buf);
1428     return FALSE;
1429   }
1430 empty_index:
1431   {
1432     GST_DEBUG_OBJECT (avi, "the index is empty");
1433     gst_buffer_unref (buf);
1434     return TRUE;
1435   }
1436 out_of_mem:
1437   {
1438     GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL),
1439         ("Cannot allocate memory for %u*%u=%u bytes",
1440             (guint) sizeof (GstAviIndexEntry), num,
1441             (guint) sizeof (GstAviIndexEntry) * num));
1442     gst_buffer_unref (buf);
1443     return FALSE;
1444   }
1445 }
1446
1447 #if 0
1448 /*
1449  * Read AVI index when streaming
1450  */
1451 static void
1452 gst_avi_demux_read_subindexes_push (GstAviDemux * avi)
1453 {
1454   guint32 tag = 0, size;
1455   GstBuffer *buf = NULL;
1456   gint i, n;
1457
1458   GST_DEBUG_OBJECT (avi, "read subindexes for %d streams", avi->num_streams);
1459
1460   for (n = 0; n < avi->num_streams; n++) {
1461     GstAviStream *stream = &avi->stream[n];
1462
1463     for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) {
1464       if (!gst_avi_demux_peek_chunk (avi, &tag, &size))
1465         continue;
1466       else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10,
1467                   '0' + stream->num % 10)) &&
1468           (tag != GST_MAKE_FOURCC ('0' + stream->num / 10,
1469                   '0' + stream->num % 10, 'i', 'x'))) {
1470         GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")",
1471             GST_FOURCC_ARGS (tag));
1472         continue;
1473       }
1474
1475       avi->offset += 8 + GST_ROUND_UP_2 (size);
1476
1477       buf = gst_buffer_new ();
1478       GST_BUFFER_DATA (buf) = gst_adapter_take (avi->adapter, size);
1479       GST_BUFFER_SIZE (buf) = size;
1480
1481       if (!gst_avi_demux_parse_subindex (avi, stream, buf))
1482         continue;
1483     }
1484
1485     g_free (stream->indexes);
1486     stream->indexes = NULL;
1487   }
1488   /* get stream stats now */
1489   avi->have_index = gst_avi_demux_do_index_stats (avi);
1490 }
1491 #endif
1492
1493 /*
1494  * Read AVI index
1495  */
1496 static void
1497 gst_avi_demux_read_subindexes_pull (GstAviDemux * avi)
1498 {
1499   guint32 tag;
1500   GstBuffer *buf;
1501   gint i, n;
1502
1503   GST_DEBUG_OBJECT (avi, "read subindexes for %d streams", avi->num_streams);
1504
1505   for (n = 0; n < avi->num_streams; n++) {
1506     GstAviStream *stream = &avi->stream[n];
1507
1508     for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) {
1509       if (gst_riff_read_chunk (GST_ELEMENT_CAST (avi), avi->sinkpad,
1510               &stream->indexes[i], &tag, &buf) != GST_FLOW_OK)
1511         continue;
1512       else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10,
1513                   '0' + stream->num % 10)) &&
1514           (tag != GST_MAKE_FOURCC ('0' + stream->num / 10,
1515                   '0' + stream->num % 10, 'i', 'x'))) {
1516         /* Some ODML files (created by god knows what muxer) have a ##ix format
1517          * instead of the 'official' ix##. They are still valid though. */
1518         GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")",
1519             GST_FOURCC_ARGS (tag));
1520         gst_buffer_unref (buf);
1521         continue;
1522       }
1523
1524       if (!gst_avi_demux_parse_subindex (avi, stream, buf))
1525         continue;
1526     }
1527
1528     g_free (stream->indexes);
1529     stream->indexes = NULL;
1530   }
1531   /* get stream stats now */
1532   avi->have_index = gst_avi_demux_do_index_stats (avi);
1533 }
1534
1535 /*
1536  * gst_avi_demux_riff_parse_vprp:
1537  * @element: caller element (used for debugging/error).
1538  * @buf: input data to be used for parsing, stripped from header.
1539  * @vprp: a pointer (returned by this function) to a filled-in vprp
1540  *        structure. Caller should free it.
1541  *
1542  * Parses a video stream´s vprp. This function takes ownership of @buf.
1543  *
1544  * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream
1545  *          should be skipped on error, but it is not fatal.
1546  */
1547 static gboolean
1548 gst_avi_demux_riff_parse_vprp (GstElement * element,
1549     GstBuffer * buf, gst_riff_vprp ** _vprp)
1550 {
1551   gst_riff_vprp *vprp;
1552   gint k;
1553
1554   g_return_val_if_fail (buf != NULL, FALSE);
1555   g_return_val_if_fail (_vprp != NULL, FALSE);
1556
1557   if (GST_BUFFER_SIZE (buf) < G_STRUCT_OFFSET (gst_riff_vprp, field_info))
1558     goto too_small;
1559
1560   vprp = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
1561
1562 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
1563   vprp->format_token = GUINT32_FROM_LE (vprp->format_token);
1564   vprp->standard = GUINT32_FROM_LE (vprp->standard);
1565   vprp->vert_rate = GUINT32_FROM_LE (vprp->vert_rate);
1566   vprp->hor_t_total = GUINT32_FROM_LE (vprp->hor_t_total);
1567   vprp->vert_lines = GUINT32_FROM_LE (vprp->vert_lines);
1568   vprp->aspect = GUINT32_FROM_LE (vprp->aspect);
1569   vprp->width = GUINT32_FROM_LE (vprp->width);
1570   vprp->height = GUINT32_FROM_LE (vprp->height);
1571   vprp->fields = GUINT32_FROM_LE (vprp->fields);
1572 #endif
1573
1574   /* size checking */
1575   /* calculate fields based on size */
1576   k = (GST_BUFFER_SIZE (buf) - G_STRUCT_OFFSET (gst_riff_vprp, field_info)) /
1577       vprp->fields;
1578   if (vprp->fields > k) {
1579     GST_WARNING_OBJECT (element,
1580         "vprp header indicated %d fields, only %d available", vprp->fields, k);
1581     vprp->fields = k;
1582   }
1583   if (vprp->fields > GST_RIFF_VPRP_VIDEO_FIELDS) {
1584     GST_WARNING_OBJECT (element,
1585         "vprp header indicated %d fields, at most %d supported", vprp->fields,
1586         GST_RIFF_VPRP_VIDEO_FIELDS);
1587     vprp->fields = GST_RIFF_VPRP_VIDEO_FIELDS;
1588   }
1589 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
1590   for (k = 0; k < vprp->fields; k++) {
1591     gst_riff_vprp_video_field_desc *fd;
1592
1593     fd = &vprp->field_info[k];
1594     fd->compressed_bm_height = GUINT32_FROM_LE (fd->compressed_bm_height);
1595     fd->compressed_bm_width = GUINT32_FROM_LE (fd->compressed_bm_width);
1596     fd->valid_bm_height = GUINT32_FROM_LE (fd->valid_bm_height);
1597     fd->valid_bm_width = GUINT16_FROM_LE (fd->valid_bm_width);
1598     fd->valid_bm_x_offset = GUINT16_FROM_LE (fd->valid_bm_x_offset);
1599     fd->valid_bm_y_offset = GUINT32_FROM_LE (fd->valid_bm_y_offset);
1600     fd->video_x_t_offset = GUINT32_FROM_LE (fd->video_x_t_offset);
1601     fd->video_y_start = GUINT32_FROM_LE (fd->video_y_start);
1602   }
1603 #endif
1604
1605   /* debug */
1606   GST_INFO_OBJECT (element, "vprp tag found in context vids:");
1607   GST_INFO_OBJECT (element, " format_token  %d", vprp->format_token);
1608   GST_INFO_OBJECT (element, " standard      %d", vprp->standard);
1609   GST_INFO_OBJECT (element, " vert_rate     %d", vprp->vert_rate);
1610   GST_INFO_OBJECT (element, " hor_t_total   %d", vprp->hor_t_total);
1611   GST_INFO_OBJECT (element, " vert_lines    %d", vprp->vert_lines);
1612   GST_INFO_OBJECT (element, " aspect        %d:%d", vprp->aspect >> 16,
1613       vprp->aspect & 0xffff);
1614   GST_INFO_OBJECT (element, " width         %d", vprp->width);
1615   GST_INFO_OBJECT (element, " height        %d", vprp->height);
1616   GST_INFO_OBJECT (element, " fields        %d", vprp->fields);
1617   for (k = 0; k < vprp->fields; k++) {
1618     gst_riff_vprp_video_field_desc *fd;
1619
1620     fd = &(vprp->field_info[k]);
1621     GST_INFO_OBJECT (element, " field %u description:", k);
1622     GST_INFO_OBJECT (element, "  compressed_bm_height  %d",
1623         fd->compressed_bm_height);
1624     GST_INFO_OBJECT (element, "  compressed_bm_width  %d",
1625         fd->compressed_bm_width);
1626     GST_INFO_OBJECT (element, "  valid_bm_height       %d",
1627         fd->valid_bm_height);
1628     GST_INFO_OBJECT (element, "  valid_bm_width        %d", fd->valid_bm_width);
1629     GST_INFO_OBJECT (element, "  valid_bm_x_offset     %d",
1630         fd->valid_bm_x_offset);
1631     GST_INFO_OBJECT (element, "  valid_bm_y_offset     %d",
1632         fd->valid_bm_y_offset);
1633     GST_INFO_OBJECT (element, "  video_x_t_offset      %d",
1634         fd->video_x_t_offset);
1635     GST_INFO_OBJECT (element, "  video_y_start         %d", fd->video_y_start);
1636   }
1637
1638   gst_buffer_unref (buf);
1639
1640   *_vprp = vprp;
1641
1642   return TRUE;
1643
1644   /* ERRORS */
1645 too_small:
1646   {
1647     GST_ERROR_OBJECT (element,
1648         "Too small vprp (%d available, at least %d needed)",
1649         GST_BUFFER_SIZE (buf),
1650         (int) G_STRUCT_OFFSET (gst_riff_vprp, field_info));
1651     gst_buffer_unref (buf);
1652     return FALSE;
1653   }
1654 }
1655
1656 static void
1657 gst_avi_demux_expose_streams (GstAviDemux * avi, gboolean force)
1658 {
1659   guint i;
1660
1661   GST_DEBUG_OBJECT (avi, "force : %d", force);
1662
1663   for (i = 0; i < avi->num_streams; i++) {
1664     GstAviStream *stream = &avi->stream[i];
1665
1666     if (force || stream->idx_n != 0) {
1667       GST_LOG_OBJECT (avi, "Added pad %s with caps %" GST_PTR_FORMAT,
1668           GST_PAD_NAME (stream->pad), GST_PAD_CAPS (stream->pad));
1669       gst_element_add_pad ((GstElement *) avi, stream->pad);
1670       stream->exposed = TRUE;
1671       if (avi->main_stream == -1)
1672         avi->main_stream = i;
1673     } else {
1674       GST_WARNING_OBJECT (avi, "Stream #%d doesn't have any entry, removing it",
1675           i);
1676       gst_avi_demux_reset_stream (avi, stream);
1677     }
1678   }
1679 }
1680
1681 /*
1682  * gst_avi_demux_parse_stream:
1683  * @avi: calling element (used for debugging/errors).
1684  * @buf: input buffer used to parse the stream.
1685  *
1686  * Parses all subchunks in a strl chunk (which defines a single
1687  * stream). Discards the buffer after use. This function will
1688  * increment the stream counter internally.
1689  *
1690  * Returns: whether the stream was identified successfully.
1691  *          Errors are not fatal. It does indicate the stream
1692  *          was skipped.
1693  */
1694 static gboolean
1695 gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
1696 {
1697   GstAviStream *stream;
1698   GstElementClass *klass;
1699   GstPadTemplate *templ;
1700   GstBuffer *sub = NULL;
1701   guint offset = 4;
1702   guint32 tag = 0;
1703   gchar *codec_name = NULL, *padname = NULL;
1704   const gchar *tag_name;
1705   GstCaps *caps = NULL;
1706   GstPad *pad;
1707   GstElement *element;
1708   gboolean got_strh = FALSE, got_strf = FALSE, got_vprp = FALSE;
1709   gst_riff_vprp *vprp = NULL;
1710
1711   element = GST_ELEMENT_CAST (avi);
1712
1713   GST_DEBUG_OBJECT (avi, "Parsing stream");
1714
1715   if (avi->num_streams >= GST_AVI_DEMUX_MAX_STREAMS) {
1716     GST_WARNING_OBJECT (avi,
1717         "maximum no of streams (%d) exceeded, ignoring stream",
1718         GST_AVI_DEMUX_MAX_STREAMS);
1719     gst_buffer_unref (buf);
1720     /* not a fatal error, let's say */
1721     return TRUE;
1722   }
1723
1724   stream = &avi->stream[avi->num_streams];
1725
1726   /* initial settings */
1727   stream->idx_duration = GST_CLOCK_TIME_NONE;
1728   stream->hdr_duration = GST_CLOCK_TIME_NONE;
1729   stream->duration = GST_CLOCK_TIME_NONE;
1730
1731   while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) {
1732     /* sub can be NULL if the chunk is empty */
1733     if (sub == NULL) {
1734       GST_DEBUG_OBJECT (avi, "ignoring empty chunk %" GST_FOURCC_FORMAT,
1735           GST_FOURCC_ARGS (tag));
1736       continue;
1737     }
1738     switch (tag) {
1739       case GST_RIFF_TAG_strh:
1740       {
1741         gst_riff_strh *strh;
1742
1743         if (got_strh) {
1744           GST_WARNING_OBJECT (avi, "Ignoring additional strh chunk");
1745           break;
1746         }
1747         if (!gst_riff_parse_strh (element, sub, &stream->strh)) {
1748           /* ownership given away */
1749           sub = NULL;
1750           GST_WARNING_OBJECT (avi, "Failed to parse strh chunk");
1751           goto fail;
1752         }
1753         sub = NULL;
1754         strh = stream->strh;
1755         /* sanity check; stream header frame rate matches global header
1756          * frame duration */
1757         if (stream->strh->type == GST_RIFF_FCC_vids) {
1758           GstClockTime s_dur;
1759           GstClockTime h_dur = avi->avih->us_frame * GST_USECOND;
1760
1761           s_dur = gst_util_uint64_scale (GST_SECOND, strh->scale, strh->rate);
1762           GST_DEBUG_OBJECT (avi, "verifying stream framerate %d/%d, "
1763               "frame duration = %d ms", strh->rate, strh->scale,
1764               (gint) (s_dur / GST_MSECOND));
1765           if (h_dur > (10 * GST_MSECOND) && (s_dur > 10 * h_dur)) {
1766             strh->rate = GST_SECOND / GST_USECOND;
1767             strh->scale = h_dur / GST_USECOND;
1768             GST_DEBUG_OBJECT (avi, "correcting stream framerate to %d/%d",
1769                 strh->rate, strh->scale);
1770           }
1771         }
1772         /* determine duration as indicated by header */
1773         stream->hdr_duration = gst_util_uint64_scale ((guint64) strh->length *
1774             strh->scale, GST_SECOND, (guint64) strh->rate);
1775         GST_INFO ("Stream duration according to header: %" GST_TIME_FORMAT,
1776             GST_TIME_ARGS (stream->hdr_duration));
1777         if (stream->hdr_duration == 0)
1778           stream->hdr_duration = GST_CLOCK_TIME_NONE;
1779
1780         got_strh = TRUE;
1781         break;
1782       }
1783       case GST_RIFF_TAG_strf:
1784       {
1785         gboolean res = FALSE;
1786
1787         if (got_strf) {
1788           GST_WARNING_OBJECT (avi, "Ignoring additional strf chunk");
1789           break;
1790         }
1791         if (!got_strh) {
1792           GST_ERROR_OBJECT (avi, "Found strf chunk before strh chunk");
1793           goto fail;
1794         }
1795         switch (stream->strh->type) {
1796           case GST_RIFF_FCC_vids:
1797             stream->is_vbr = TRUE;
1798             res = gst_riff_parse_strf_vids (element, sub,
1799                 &stream->strf.vids, &stream->extradata);
1800             sub = NULL;
1801             GST_DEBUG_OBJECT (element, "marking video as VBR, res %d", res);
1802             break;
1803           case GST_RIFF_FCC_auds:
1804             stream->is_vbr = (stream->strh->samplesize == 0)
1805                 && stream->strh->scale > 1;
1806             res =
1807                 gst_riff_parse_strf_auds (element, sub, &stream->strf.auds,
1808                 &stream->extradata);
1809             sub = NULL;
1810             GST_DEBUG_OBJECT (element, "marking audio as VBR:%d, res %d",
1811                 stream->is_vbr, res);
1812             break;
1813           case GST_RIFF_FCC_iavs:
1814             stream->is_vbr = TRUE;
1815             res = gst_riff_parse_strf_iavs (element, sub,
1816                 &stream->strf.iavs, &stream->extradata);
1817             sub = NULL;
1818             GST_DEBUG_OBJECT (element, "marking iavs as VBR, res %d", res);
1819             break;
1820           case GST_RIFF_FCC_txts:
1821             /* nothing to parse here */
1822             stream->is_vbr = (stream->strh->samplesize == 0)
1823                 && (stream->strh->scale > 1);
1824             res = TRUE;
1825             break;
1826           default:
1827             GST_ERROR_OBJECT (avi,
1828                 "Don´t know how to handle stream type %" GST_FOURCC_FORMAT,
1829                 GST_FOURCC_ARGS (stream->strh->type));
1830             break;
1831         }
1832         if (sub) {
1833           gst_buffer_unref (sub);
1834           sub = NULL;
1835         }
1836         if (!res)
1837           goto fail;
1838         got_strf = TRUE;
1839         break;
1840       }
1841       case GST_RIFF_TAG_vprp:
1842       {
1843         if (got_vprp) {
1844           GST_WARNING_OBJECT (avi, "Ignoring additional vprp chunk");
1845           break;
1846         }
1847         if (!got_strh) {
1848           GST_ERROR_OBJECT (avi, "Found vprp chunk before strh chunk");
1849           goto fail;
1850         }
1851         if (!got_strf) {
1852           GST_ERROR_OBJECT (avi, "Found vprp chunk before strf chunk");
1853           goto fail;
1854         }
1855
1856         if (!gst_avi_demux_riff_parse_vprp (element, sub, &vprp)) {
1857           GST_WARNING_OBJECT (avi, "Failed to parse vprp chunk");
1858           /* not considered fatal */
1859           g_free (vprp);
1860           vprp = NULL;
1861         } else
1862           got_vprp = TRUE;
1863         sub = NULL;
1864         break;
1865       }
1866       case GST_RIFF_TAG_strd:
1867         if (stream->initdata)
1868           gst_buffer_unref (stream->initdata);
1869         stream->initdata = sub;
1870         sub = NULL;
1871         break;
1872       case GST_RIFF_TAG_strn:
1873         g_free (stream->name);
1874         if (sub != NULL) {
1875           stream->name =
1876               g_strndup ((gchar *) GST_BUFFER_DATA (sub),
1877               (gsize) GST_BUFFER_SIZE (sub));
1878           gst_buffer_unref (sub);
1879           sub = NULL;
1880         } else {
1881           stream->name = g_strdup ("");
1882         }
1883         GST_DEBUG_OBJECT (avi, "stream name: %s", stream->name);
1884         break;
1885       default:
1886         if (tag == GST_MAKE_FOURCC ('i', 'n', 'd', 'x') ||
1887             tag == GST_MAKE_FOURCC ('i', 'x', '0' + avi->num_streams / 10,
1888                 '0' + avi->num_streams % 10)) {
1889           g_free (stream->indexes);
1890           gst_avi_demux_parse_superindex (avi, sub, &stream->indexes);
1891           stream->superindex = TRUE;
1892           sub = NULL;
1893           break;
1894         }
1895         GST_WARNING_OBJECT (avi,
1896             "Unknown stream header tag %" GST_FOURCC_FORMAT ", ignoring",
1897             GST_FOURCC_ARGS (tag));
1898         /* fall-through */
1899       case GST_RIFF_TAG_JUNK:
1900         break;
1901     }
1902     if (sub != NULL) {
1903       gst_buffer_unref (sub);
1904       sub = NULL;
1905     }
1906   }
1907
1908   if (!got_strh) {
1909     GST_WARNING_OBJECT (avi, "Failed to find strh chunk");
1910     goto fail;
1911   }
1912
1913   if (!got_strf) {
1914     GST_WARNING_OBJECT (avi, "Failed to find strf chunk");
1915     goto fail;
1916   }
1917
1918   /* get class to figure out the template */
1919   klass = GST_ELEMENT_GET_CLASS (avi);
1920
1921   /* we now have all info, let´s set up a pad and a caps and be done */
1922   /* create stream name + pad */
1923   switch (stream->strh->type) {
1924     case GST_RIFF_FCC_vids:{
1925       guint32 fourcc;
1926
1927       fourcc = (stream->strf.vids->compression) ?
1928           stream->strf.vids->compression : stream->strh->fcc_handler;
1929       padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
1930       templ = gst_element_class_get_pad_template (klass, "video_%02d");
1931       caps = gst_riff_create_video_caps (fourcc, stream->strh,
1932           stream->strf.vids, stream->extradata, stream->initdata, &codec_name);
1933       if (!caps) {
1934         caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc",
1935             GST_TYPE_FOURCC, fourcc, NULL);
1936       } else if (got_vprp && vprp) {
1937         guint32 aspect_n, aspect_d;
1938         gint n, d;
1939
1940         aspect_n = vprp->aspect >> 16;
1941         aspect_d = vprp->aspect & 0xffff;
1942         /* calculate the pixel aspect ratio using w/h and aspect ratio */
1943         n = aspect_n * stream->strf.vids->height;
1944         d = aspect_d * stream->strf.vids->width;
1945         if (n && d)
1946           gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1947               n, d, NULL);
1948         /* very local, not needed elsewhere */
1949         g_free (vprp);
1950         vprp = NULL;
1951       }
1952       tag_name = GST_TAG_VIDEO_CODEC;
1953       avi->num_v_streams++;
1954       break;
1955     }
1956     case GST_RIFF_FCC_auds:{
1957       padname = g_strdup_printf ("audio_%02d", avi->num_a_streams);
1958       templ = gst_element_class_get_pad_template (klass, "audio_%02d");
1959       caps = gst_riff_create_audio_caps (stream->strf.auds->format,
1960           stream->strh, stream->strf.auds, stream->extradata,
1961           stream->initdata, &codec_name);
1962       if (!caps) {
1963         caps = gst_caps_new_simple ("audio/x-avi-unknown", "codec_id",
1964             G_TYPE_INT, stream->strf.auds->format, NULL);
1965       }
1966       tag_name = GST_TAG_AUDIO_CODEC;
1967       avi->num_a_streams++;
1968       break;
1969     }
1970     case GST_RIFF_FCC_iavs:{
1971       guint32 fourcc = stream->strh->fcc_handler;
1972
1973       padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
1974       templ = gst_element_class_get_pad_template (klass, "video_%02d");
1975       caps = gst_riff_create_iavs_caps (fourcc, stream->strh,
1976           stream->strf.iavs, stream->extradata, stream->initdata, &codec_name);
1977       if (!caps) {
1978         caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc",
1979             GST_TYPE_FOURCC, fourcc, NULL);
1980       }
1981       tag_name = GST_TAG_VIDEO_CODEC;
1982       avi->num_v_streams++;
1983       break;
1984     }
1985     case GST_RIFF_FCC_txts:{
1986       padname = g_strdup_printf ("subtitle_%02d", avi->num_t_streams);
1987       templ = gst_element_class_get_pad_template (klass, "subtitle_%02d");
1988       caps = gst_caps_new_simple ("application/x-subtitle-avi", NULL);
1989       tag_name = NULL;
1990       avi->num_t_streams++;
1991       break;
1992     }
1993     default:
1994       g_assert_not_reached ();
1995   }
1996
1997   /* no caps means no stream */
1998   if (!caps) {
1999     GST_ERROR_OBJECT (element, "Did not find caps for stream %s", padname);
2000     goto fail;
2001   }
2002
2003   GST_DEBUG_OBJECT (element, "codec-name=%s",
2004       (codec_name ? codec_name : "NULL"));
2005   GST_DEBUG_OBJECT (element, "caps=%" GST_PTR_FORMAT, caps);
2006
2007   /* set proper settings and add it */
2008   if (stream->pad)
2009     gst_object_unref (stream->pad);
2010   pad = stream->pad = gst_pad_new_from_template (templ, padname);
2011   g_free (padname);
2012
2013   gst_pad_use_fixed_caps (pad);
2014 #if 0
2015   gst_pad_set_formats_function (pad,
2016       GST_DEBUG_FUNCPTR (gst_avi_demux_get_src_formats));
2017   gst_pad_set_event_mask_function (pad,
2018       GST_DEBUG_FUNCPTR (gst_avi_demux_get_event_mask));
2019 #endif
2020   gst_pad_set_event_function (pad,
2021       GST_DEBUG_FUNCPTR (gst_avi_demux_handle_src_event));
2022   gst_pad_set_query_type_function (pad,
2023       GST_DEBUG_FUNCPTR (gst_avi_demux_get_src_query_types));
2024   gst_pad_set_query_function (pad,
2025       GST_DEBUG_FUNCPTR (gst_avi_demux_handle_src_query));
2026 #if 0
2027   gst_pad_set_convert_function (pad,
2028       GST_DEBUG_FUNCPTR (gst_avi_demux_src_convert));
2029 #endif
2030
2031   if (avi->element_index)
2032     gst_index_get_writer_id (avi->element_index, GST_OBJECT (stream->pad),
2033         &stream->index_id);
2034
2035   stream->num = avi->num_streams;
2036
2037   stream->start_entry = 0;
2038   stream->step_entry = 0;
2039   stream->stop_entry = 0;
2040
2041   stream->current_entry = -1;
2042   stream->current_total = 0;
2043
2044   stream->last_flow = GST_FLOW_OK;
2045   stream->discont = TRUE;
2046
2047   stream->total_bytes = 0;
2048   stream->total_blocks = 0;
2049   stream->n_keyframes = 0;
2050
2051   stream->idx_n = 0;
2052   stream->idx_max = 0;
2053
2054   gst_pad_set_element_private (pad, stream);
2055   avi->num_streams++;
2056
2057   gst_pad_set_caps (pad, caps);
2058   gst_pad_set_active (pad, TRUE);
2059   gst_caps_unref (caps);
2060
2061   /* make tags */
2062   if (codec_name) {
2063     if (!stream->taglist)
2064       stream->taglist = gst_tag_list_new ();
2065
2066     avi->got_tags = TRUE;
2067
2068     gst_tag_list_add (stream->taglist, GST_TAG_MERGE_APPEND, tag_name,
2069         codec_name, NULL);
2070     g_free (codec_name);
2071   }
2072
2073   gst_buffer_unref (buf);
2074
2075   return TRUE;
2076
2077   /* ERRORS */
2078 fail:
2079   {
2080     /* unref any mem that may be in use */
2081     if (buf)
2082       gst_buffer_unref (buf);
2083     if (sub)
2084       gst_buffer_unref (sub);
2085     g_free (vprp);
2086     g_free (codec_name);
2087     gst_avi_demux_reset_stream (avi, stream);
2088     avi->num_streams++;
2089     return FALSE;
2090   }
2091 }
2092
2093 /*
2094  * gst_avi_demux_parse_odml:
2095  * @avi: calling element (used for debug/error).
2096  * @buf: input buffer to be used for parsing.
2097  *
2098  * Read an openDML-2.0 extension header. Fills in the frame number
2099  * in the avi demuxer object when reading succeeds.
2100  */
2101 static void
2102 gst_avi_demux_parse_odml (GstAviDemux * avi, GstBuffer * buf)
2103 {
2104   guint32 tag = 0;
2105   guint offset = 4;
2106   GstBuffer *sub = NULL;
2107
2108   while (gst_riff_parse_chunk (GST_ELEMENT_CAST (avi), buf, &offset, &tag,
2109           &sub)) {
2110     switch (tag) {
2111       case GST_RIFF_TAG_dmlh:{
2112         gst_riff_dmlh dmlh, *_dmlh;
2113         guint size;
2114
2115         /* sub == NULL is possible and means an empty buffer */
2116         size = sub ? GST_BUFFER_SIZE (sub) : 0;
2117
2118         /* check size */
2119         if (size < sizeof (gst_riff_dmlh)) {
2120           GST_ERROR_OBJECT (avi,
2121               "DMLH entry is too small (%d bytes, %d needed)",
2122               size, (int) sizeof (gst_riff_dmlh));
2123           goto next;
2124         }
2125         _dmlh = (gst_riff_dmlh *) GST_BUFFER_DATA (sub);
2126         dmlh.totalframes = GST_READ_UINT32_LE (&_dmlh->totalframes);
2127
2128         GST_INFO_OBJECT (avi, "dmlh tag found: totalframes: %u",
2129             dmlh.totalframes);
2130
2131         avi->avih->tot_frames = dmlh.totalframes;
2132         goto next;
2133       }
2134
2135       default:
2136         GST_WARNING_OBJECT (avi,
2137             "Unknown tag %" GST_FOURCC_FORMAT " in ODML header",
2138             GST_FOURCC_ARGS (tag));
2139         /* fall-through */
2140       case GST_RIFF_TAG_JUNK:
2141       next:
2142         /* skip and move to next chunk */
2143         if (sub) {
2144           gst_buffer_unref (sub);
2145           sub = NULL;
2146         }
2147         break;
2148     }
2149   }
2150   if (buf)
2151     gst_buffer_unref (buf);
2152 }
2153
2154 /* Index helper */
2155 static guint
2156 gst_avi_demux_index_last (GstAviDemux * avi, GstAviStream * stream)
2157 {
2158   return stream->idx_n - 1;
2159 }
2160
2161 /* find a previous entry in the index with the given flags */
2162 static guint
2163 gst_avi_demux_index_prev (GstAviDemux * avi, GstAviStream * stream,
2164     guint last, gboolean keyframe)
2165 {
2166   GstAviIndexEntry *entry;
2167   guint i;
2168
2169   for (i = last; i > 0; i--) {
2170     entry = &stream->index[i - 1];
2171     if (!keyframe || ENTRY_IS_KEYFRAME (entry)) {
2172       return i - 1;
2173     }
2174   }
2175   return 0;
2176 }
2177
2178 static guint
2179 gst_avi_demux_index_next (GstAviDemux * avi, GstAviStream * stream,
2180     guint last, gboolean keyframe)
2181 {
2182   GstAviIndexEntry *entry;
2183   gint i;
2184
2185   for (i = last + 1; i < stream->idx_n; i++) {
2186     entry = &stream->index[i];
2187     if (!keyframe || ENTRY_IS_KEYFRAME (entry)) {
2188       return i;
2189     }
2190   }
2191   return stream->idx_n - 1;
2192 }
2193
2194 static guint
2195 gst_avi_demux_index_entry_search (GstAviIndexEntry * entry, guint64 * total)
2196 {
2197   if (entry->total < *total)
2198     return -1;
2199   else if (entry->total > *total)
2200     return 1;
2201   return 0;
2202 }
2203
2204 /*
2205  * gst_avi_demux_index_for_time:
2206  * @avi: Avi object
2207  * @stream: the stream
2208  * @time: a time position
2209  *
2210  * Finds the index entry which time is less or equal than the requested time.
2211  * Try to avoid binary search when we can convert the time to an index
2212  * position directly (for example for video frames with a fixed duration).
2213  *
2214  * Returns: the found position in the index.
2215  */
2216 static guint
2217 gst_avi_demux_index_for_time (GstAviDemux * avi,
2218     GstAviStream * stream, guint64 time)
2219 {
2220   guint index = -1;
2221   guint64 total;
2222
2223   GST_LOG_OBJECT (avi, "search time:%" GST_TIME_FORMAT, GST_TIME_ARGS (time));
2224
2225   /* easy (and common) cases */
2226   if (time == 0 || stream->idx_n == 0)
2227     return 0;
2228   if (time >= stream->idx_duration)
2229     return stream->idx_n - 1;
2230
2231   /* figure out where we need to go. For that we convert the time to an
2232    * index entry or we convert it to a total and then do a binary search. */
2233   if (stream->is_vbr) {
2234     /* VBR stream next timestamp */
2235     if (stream->strh->type == GST_RIFF_FCC_auds) {
2236       total = avi_stream_convert_time_to_frames_unchecked (stream, time);
2237     } else {
2238       index = avi_stream_convert_time_to_frames_unchecked (stream, time);
2239     }
2240   } else {
2241     /* constant rate stream */
2242     total = avi_stream_convert_time_to_bytes_unchecked (stream, time);
2243   }
2244
2245   if (index == -1) {
2246     GstAviIndexEntry *entry;
2247
2248     /* no index, find index with binary search on total */
2249     GST_LOG_OBJECT (avi, "binary search for entry with total %"
2250         G_GUINT64_FORMAT, total);
2251
2252     entry = gst_util_array_binary_search (stream->index,
2253         stream->idx_n, sizeof (GstAviIndexEntry),
2254         (GCompareDataFunc) gst_avi_demux_index_entry_search,
2255         GST_SEARCH_MODE_BEFORE, &total, NULL);
2256
2257     if (entry == NULL) {
2258       GST_LOG_OBJECT (avi, "not found, assume index 0");
2259       index = 0;
2260     } else {
2261       index = entry - stream->index;
2262       GST_LOG_OBJECT (avi, "found at %u", index);
2263     }
2264   } else {
2265     GST_LOG_OBJECT (avi, "converted time to index %u", index);
2266   }
2267
2268   return index;
2269 }
2270
2271 static inline GstAviStream *
2272 gst_avi_demux_stream_for_id (GstAviDemux * avi, guint32 id)
2273 {
2274   guint stream_nr;
2275   GstAviStream *stream;
2276
2277   /* get the stream for this entry */
2278   stream_nr = CHUNKID_TO_STREAMNR (id);
2279   if (G_UNLIKELY (stream_nr >= avi->num_streams)) {
2280     GST_WARNING_OBJECT (avi, "invalid stream nr %d", stream_nr);
2281     return NULL;
2282   }
2283   stream = &avi->stream[stream_nr];
2284   if (G_UNLIKELY (!stream->strh)) {
2285     GST_WARNING_OBJECT (avi, "Unhandled stream %d, skipping", stream_nr);
2286     return NULL;
2287   }
2288   return stream;
2289 }
2290
2291 /*
2292  * gst_avi_demux_parse_index:
2293  * @avi: calling element (used for debugging/errors).
2294  * @buf: buffer containing the full index.
2295  *
2296  * Read index entries from the provided buffer.
2297  * The buffer should contain a GST_RIFF_TAG_idx1 chunk.
2298  */
2299 static gboolean
2300 gst_avi_demux_parse_index (GstAviDemux * avi, GstBuffer * buf)
2301 {
2302   guint64 pos_before;
2303   guint8 *data;
2304   guint size;
2305   guint i, num, n;
2306   gst_riff_index_entry *index;
2307   GstClockTime stamp;
2308   GstAviStream *stream;
2309   GstAviIndexEntry entry;
2310   guint32 id;
2311
2312   if (!buf)
2313     return FALSE;
2314
2315   data = GST_BUFFER_DATA (buf);
2316   size = GST_BUFFER_SIZE (buf);
2317
2318   stamp = gst_util_get_timestamp ();
2319
2320   /* see how many items in the index */
2321   num = size / sizeof (gst_riff_index_entry);
2322   if (num == 0)
2323     goto empty_list;
2324
2325   GST_INFO_OBJECT (avi, "Parsing index, nr_entries = %6d", num);
2326
2327   index = (gst_riff_index_entry *) data;
2328   pos_before = avi->offset;
2329
2330   /* figure out if the index is 0 based or relative to the MOVI start */
2331   entry.offset = GST_READ_UINT32_LE (&index[0].offset);
2332   if (entry.offset < avi->offset) {
2333     avi->index_offset = avi->offset + 8;
2334     GST_DEBUG ("index_offset = %" G_GUINT64_FORMAT, avi->index_offset);
2335   } else {
2336     avi->index_offset = 0;
2337     GST_DEBUG ("index is 0 based");
2338   }
2339
2340   for (i = 0, n = 0; i < num; i++) {
2341     id = GST_READ_UINT32_LE (&index[i].id);
2342     entry.offset = GST_READ_UINT32_LE (&index[i].offset);
2343
2344     /* some sanity checks */
2345     if (G_UNLIKELY (id == GST_RIFF_rec || id == 0 ||
2346             (entry.offset == 0 && n > 0)))
2347       continue;
2348
2349     /* get the stream for this entry */
2350     stream = gst_avi_demux_stream_for_id (avi, id);
2351     if (G_UNLIKELY (!stream))
2352       continue;
2353
2354     /* handle offset and size */
2355     entry.offset += avi->index_offset + 8;
2356     entry.size = GST_READ_UINT32_LE (&index[i].size);
2357
2358     /* handle flags */
2359     if (stream->strh->type == GST_RIFF_FCC_auds) {
2360       /* all audio frames are keyframes */
2361       ENTRY_SET_KEYFRAME (&entry);
2362     } else {
2363       guint32 flags;
2364       /* else read flags */
2365       flags = GST_READ_UINT32_LE (&index[i].flags);
2366       if (flags & GST_RIFF_IF_KEYFRAME) {
2367         ENTRY_SET_KEYFRAME (&entry);
2368       } else {
2369         ENTRY_UNSET_KEYFRAME (&entry);
2370       }
2371     }
2372
2373     /* and add */
2374     if (G_UNLIKELY (!gst_avi_demux_add_index (avi, stream, num, &entry)))
2375       goto out_of_mem;
2376
2377     n++;
2378   }
2379   gst_buffer_unref (buf);
2380
2381   /* get stream stats now */
2382   avi->have_index = gst_avi_demux_do_index_stats (avi);
2383
2384   stamp = gst_util_get_timestamp () - stamp;
2385   GST_DEBUG_OBJECT (avi, "index parsing took %" GST_TIME_FORMAT,
2386       GST_TIME_ARGS (stamp));
2387
2388   return TRUE;
2389
2390   /* ERRORS */
2391 empty_list:
2392   {
2393     GST_DEBUG_OBJECT (avi, "empty index");
2394     gst_buffer_unref (buf);
2395     return FALSE;
2396   }
2397 out_of_mem:
2398   {
2399     GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL),
2400         ("Cannot allocate memory for %u*%u=%u bytes",
2401             (guint) sizeof (GstAviIndexEntry), num,
2402             (guint) sizeof (GstAviIndexEntry) * num));
2403     gst_buffer_unref (buf);
2404     return FALSE;
2405   }
2406 }
2407
2408 /*
2409  * gst_avi_demux_stream_index:
2410  * @avi: avi demuxer object.
2411  *
2412  * Seeks to index and reads it.
2413  */
2414 static void
2415 gst_avi_demux_stream_index (GstAviDemux * avi)
2416 {
2417   GstFlowReturn res;
2418   guint64 offset = avi->offset;
2419   GstBuffer *buf;
2420   guint32 tag;
2421   guint32 size;
2422
2423   GST_DEBUG ("demux stream index at offset %" G_GUINT64_FORMAT, offset);
2424
2425   /* get chunk information */
2426   res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf);
2427   if (res != GST_FLOW_OK)
2428     goto pull_failed;
2429   else if (GST_BUFFER_SIZE (buf) < 8)
2430     goto too_small;
2431
2432   /* check tag first before blindy trying to read 'size' bytes */
2433   tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
2434   size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
2435   if (tag == GST_RIFF_TAG_LIST) {
2436     /* this is the movi tag */
2437     GST_DEBUG_OBJECT (avi, "skip LIST chunk, size %" G_GUINT32_FORMAT,
2438         (8 + GST_ROUND_UP_2 (size)));
2439     offset += 8 + GST_ROUND_UP_2 (size);
2440     gst_buffer_unref (buf);
2441     res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf);
2442     if (res != GST_FLOW_OK)
2443       goto pull_failed;
2444     else if (GST_BUFFER_SIZE (buf) < 8)
2445       goto too_small;
2446     tag = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf));
2447     size = GST_READ_UINT32_LE (GST_BUFFER_DATA (buf) + 4);
2448   }
2449
2450   if (tag != GST_RIFF_TAG_idx1)
2451     goto no_index;
2452   if (!size)
2453     goto zero_index;
2454
2455   gst_buffer_unref (buf);
2456
2457   GST_DEBUG ("index found at offset %" G_GUINT64_FORMAT, offset);
2458
2459   /* read chunk, advance offset */
2460   if (gst_riff_read_chunk (GST_ELEMENT_CAST (avi),
2461           avi->sinkpad, &offset, &tag, &buf) != GST_FLOW_OK)
2462     return;
2463
2464   GST_DEBUG ("will parse index chunk size %u for tag %"
2465       GST_FOURCC_FORMAT, GST_BUFFER_SIZE (buf), GST_FOURCC_ARGS (tag));
2466
2467   gst_avi_demux_parse_index (avi, buf);
2468
2469 #ifndef GST_DISABLE_GST_DEBUG
2470   /* debug our indexes */
2471   {
2472     gint i;
2473     GstAviStream *stream;
2474
2475     for (i = 0; i < avi->num_streams; i++) {
2476       stream = &avi->stream[i];
2477       GST_DEBUG_OBJECT (avi, "stream %u: %u frames, %" G_GINT64_FORMAT " bytes",
2478           i, stream->idx_n, stream->total_bytes);
2479     }
2480   }
2481 #endif
2482   return;
2483
2484   /* ERRORS */
2485 pull_failed:
2486   {
2487     GST_DEBUG_OBJECT (avi,
2488         "pull range failed: pos=%" G_GUINT64_FORMAT " size=8", offset);
2489     return;
2490   }
2491 too_small:
2492   {
2493     GST_DEBUG_OBJECT (avi, "Buffer is too small");
2494     gst_buffer_unref (buf);
2495     return;
2496   }
2497 no_index:
2498   {
2499     GST_WARNING_OBJECT (avi,
2500         "No index data (idx1) after movi chunk, but %" GST_FOURCC_FORMAT,
2501         GST_FOURCC_ARGS (tag));
2502     gst_buffer_unref (buf);
2503     return;
2504   }
2505 zero_index:
2506   {
2507     GST_WARNING_OBJECT (avi, "Empty index data (idx1) after movi chunk");
2508     gst_buffer_unref (buf);
2509     return;
2510   }
2511 }
2512
2513 /*
2514  * gst_avi_demux_peek_tag:
2515  *
2516  * Returns the tag and size of the next chunk
2517  */
2518 static GstFlowReturn
2519 gst_avi_demux_peek_tag (GstAviDemux * avi, guint64 offset, guint32 * tag,
2520     guint * size)
2521 {
2522   GstFlowReturn res = GST_FLOW_OK;
2523   GstBuffer *buf = NULL;
2524   guint bufsize;
2525   guint8 *bufdata;
2526
2527   res = gst_pad_pull_range (avi->sinkpad, offset, 8, &buf);
2528   if (res != GST_FLOW_OK)
2529     goto pull_failed;
2530
2531   bufsize = GST_BUFFER_SIZE (buf);
2532   if (bufsize != 8)
2533     goto wrong_size;
2534
2535   bufdata = GST_BUFFER_DATA (buf);
2536
2537   *tag = GST_READ_UINT32_LE (bufdata);
2538   *size = GST_READ_UINT32_LE (bufdata + 4);
2539
2540   GST_LOG_OBJECT (avi, "Tag[%" GST_FOURCC_FORMAT "] (size:%d) %"
2541       G_GINT64_FORMAT " -- %" G_GINT64_FORMAT, GST_FOURCC_ARGS (*tag),
2542       *size, offset + 8, offset + 8 + (gint64) * size);
2543
2544 done:
2545   gst_buffer_unref (buf);
2546
2547   return res;
2548
2549   /* ERRORS */
2550 pull_failed:
2551   {
2552     GST_DEBUG_OBJECT (avi, "pull_ranged returned %s", gst_flow_get_name (res));
2553     return res;
2554   }
2555 wrong_size:
2556   {
2557     GST_DEBUG_OBJECT (avi, "got %d bytes which is <> 8 bytes", bufsize);
2558     res = GST_FLOW_ERROR;
2559     goto done;
2560   }
2561 }
2562
2563 /*
2564  * gst_avi_demux_next_data_buffer:
2565  *
2566  * Returns the offset and size of the next buffer
2567  * Position is the position of the buffer (after tag and size)
2568  */
2569 static GstFlowReturn
2570 gst_avi_demux_next_data_buffer (GstAviDemux * avi, guint64 * offset,
2571     guint32 * tag, guint * size)
2572 {
2573   guint64 off = *offset;
2574   guint _size = 0;
2575   GstFlowReturn res;
2576
2577   do {
2578     res = gst_avi_demux_peek_tag (avi, off, tag, &_size);
2579     if (res != GST_FLOW_OK)
2580       break;
2581     if (*tag == GST_RIFF_TAG_LIST || *tag == GST_RIFF_TAG_RIFF)
2582       off += 8 + 4;             /* skip tag + size + subtag */
2583     else {
2584       *offset = off + 8;
2585       *size = _size;
2586       break;
2587     }
2588   } while (TRUE);
2589
2590   return res;
2591 }
2592
2593 /*
2594  * gst_avi_demux_stream_scan:
2595  * @avi: calling element (used for debugging/errors).
2596  *
2597  * Scan the file for all chunks to "create" a new index.
2598  * pull-range based
2599  */
2600 static gboolean
2601 gst_avi_demux_stream_scan (GstAviDemux * avi)
2602 {
2603   GstFlowReturn res;
2604   GstAviStream *stream;
2605   GstFormat format;
2606   guint64 pos = 0;
2607   guint64 length;
2608   gint64 tmplength;
2609   guint32 tag = 0;
2610   guint num;
2611
2612   /* FIXME:
2613    * - implement non-seekable source support.
2614    */
2615   GST_DEBUG_OBJECT (avi, "Creating index");
2616
2617   /* get the size of the file */
2618   format = GST_FORMAT_BYTES;
2619   if (!gst_pad_query_peer_duration (avi->sinkpad, &format, &tmplength))
2620     return FALSE;
2621   length = tmplength;
2622
2623   /* guess the total amount of entries we expect */
2624   num = 16000;
2625
2626   while (TRUE) {
2627     GstAviIndexEntry entry;
2628     guint size = 0;
2629
2630     /* start reading data buffers to find the id and offset */
2631     res = gst_avi_demux_next_data_buffer (avi, &pos, &tag, &size);
2632     if (G_UNLIKELY (res != GST_FLOW_OK))
2633       break;
2634
2635     /* get stream */
2636     stream = gst_avi_demux_stream_for_id (avi, tag);
2637     if (G_UNLIKELY (!stream))
2638       goto next;
2639
2640     /* we can't figure out the keyframes, assume they all are */
2641     entry.flags = GST_AVI_KEYFRAME;
2642     entry.offset = pos;
2643     entry.size = size;
2644
2645     /* and add to the index of this stream */
2646     if (G_UNLIKELY (!gst_avi_demux_add_index (avi, stream, num, &entry)))
2647       goto out_of_mem;
2648
2649   next:
2650     /* update position */
2651     pos += GST_ROUND_UP_2 (size);
2652     if (G_UNLIKELY (pos > length)) {
2653       GST_WARNING_OBJECT (avi,
2654           "Stopping index lookup since we are further than EOF");
2655       break;
2656     }
2657   }
2658
2659   /* collect stats */
2660   avi->have_index = gst_avi_demux_do_index_stats (avi);
2661
2662
2663   return TRUE;
2664
2665   /* ERRORS */
2666 out_of_mem:
2667   {
2668     GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL),
2669         ("Cannot allocate memory for %u*%u=%u bytes",
2670             (guint) sizeof (GstAviIndexEntry), num,
2671             (guint) sizeof (GstAviIndexEntry) * num));
2672     return FALSE;
2673   }
2674 }
2675
2676 static void
2677 gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi)
2678 {
2679   guint i;
2680   GstClockTime total;
2681   GstAviStream *stream;
2682
2683   total = GST_CLOCK_TIME_NONE;
2684
2685   /* all streams start at a timestamp 0 */
2686   for (i = 0; i < avi->num_streams; i++) {
2687     GstClockTime duration, hduration;
2688     gst_riff_strh *strh;
2689
2690     stream = &avi->stream[i];
2691     if (G_UNLIKELY (!stream || !stream->idx_n || !(strh = stream->strh)))
2692       continue;
2693
2694     /* get header duration for the stream */
2695     hduration = stream->hdr_duration;
2696     /* index duration calculated during parsing */
2697     duration = stream->idx_duration;
2698
2699     /* now pick a good duration */
2700     if (GST_CLOCK_TIME_IS_VALID (duration)) {
2701       /* index gave valid duration, use that */
2702       GST_INFO ("Stream %p duration according to index: %" GST_TIME_FORMAT,
2703           stream, GST_TIME_ARGS (duration));
2704     } else {
2705       /* fall back to header info to calculate a duration */
2706       duration = hduration;
2707     }
2708     GST_INFO ("Setting duration of stream #%d to %" GST_TIME_FORMAT,
2709         i, GST_TIME_ARGS (duration));
2710     /* set duration for the stream */
2711     stream->duration = duration;
2712
2713     /* find total duration */
2714     if (total == GST_CLOCK_TIME_NONE ||
2715         (GST_CLOCK_TIME_IS_VALID (duration) && duration > total))
2716       total = duration;
2717   }
2718
2719   if (GST_CLOCK_TIME_IS_VALID (total) && (total > 0)) {
2720     /* now update the duration for those streams where we had none */
2721     for (i = 0; i < avi->num_streams; i++) {
2722       stream = &avi->stream[i];
2723
2724       if (!GST_CLOCK_TIME_IS_VALID (stream->duration)
2725           || stream->duration == 0) {
2726         stream->duration = total;
2727
2728         GST_INFO ("Stream %p duration according to total: %" GST_TIME_FORMAT,
2729             stream, GST_TIME_ARGS (total));
2730       }
2731     }
2732   }
2733
2734   /* and set the total duration in the segment. */
2735   GST_INFO ("Setting total duration to: %" GST_TIME_FORMAT,
2736       GST_TIME_ARGS (total));
2737
2738   gst_segment_set_duration (&avi->segment, GST_FORMAT_TIME, total);
2739 }
2740
2741 /* returns FALSE if there are no pads to deliver event to,
2742  * otherwise TRUE (whatever the outcome of event sending),
2743  * takes ownership of the event. */
2744 static gboolean
2745 gst_avi_demux_push_event (GstAviDemux * avi, GstEvent * event)
2746 {
2747   gboolean result = FALSE;
2748   gint i;
2749
2750   GST_DEBUG_OBJECT (avi, "sending %s event to %d streams",
2751       GST_EVENT_TYPE_NAME (event), avi->num_streams);
2752
2753   for (i = 0; i < avi->num_streams; i++) {
2754     GstAviStream *stream = &avi->stream[i];
2755
2756     if (stream->pad) {
2757       result = TRUE;
2758       gst_pad_push_event (stream->pad, gst_event_ref (event));
2759     }
2760   }
2761   gst_event_unref (event);
2762   return result;
2763 }
2764
2765 static void
2766 gst_avi_demux_check_seekability (GstAviDemux * avi)
2767 {
2768   GstQuery *query;
2769   gboolean seekable = FALSE;
2770   gint64 start = -1, stop = -1;
2771
2772   query = gst_query_new_seeking (GST_FORMAT_BYTES);
2773   if (!gst_pad_peer_query (avi->sinkpad, query)) {
2774     GST_DEBUG_OBJECT (avi, "seeking query failed");
2775     goto done;
2776   }
2777
2778   gst_query_parse_seeking (query, NULL, &seekable, &start, &stop);
2779
2780   /* try harder to query upstream size if we didn't get it the first time */
2781   if (seekable && stop == -1) {
2782     GstFormat fmt = GST_FORMAT_BYTES;
2783
2784     GST_DEBUG_OBJECT (avi, "doing duration query to fix up unset stop");
2785     gst_pad_query_peer_duration (avi->sinkpad, &fmt, &stop);
2786   }
2787
2788   /* if upstream doesn't know the size, it's likely that it's not seekable in
2789    * practice even if it technically may be seekable */
2790   if (seekable && (start != 0 || stop <= start)) {
2791     GST_DEBUG_OBJECT (avi, "seekable but unknown start/stop -> disable");
2792     seekable = FALSE;
2793   }
2794
2795   if (!avi->element_index) {
2796     GST_DEBUG_OBJECT (avi, "no index");
2797     seekable = FALSE;
2798   }
2799
2800 done:
2801   GST_INFO_OBJECT (avi, "seekable: %d (%" G_GUINT64_FORMAT " - %"
2802       G_GUINT64_FORMAT ")", seekable, start, stop);
2803   avi->seekable = seekable;
2804
2805   gst_query_unref (query);
2806 }
2807
2808 /*
2809  * Read AVI headers when streaming
2810  */
2811 static GstFlowReturn
2812 gst_avi_demux_stream_header_push (GstAviDemux * avi)
2813 {
2814   GstFlowReturn ret = GST_FLOW_OK;
2815   guint32 tag = 0;
2816   guint32 ltag = 0;
2817   guint32 size = 0;
2818   const guint8 *data;
2819   GstBuffer *buf = NULL, *sub = NULL;
2820   guint offset = 4;
2821   gint64 stop;
2822   gint i;
2823   GstTagList *tags = NULL;
2824
2825   GST_DEBUG ("Reading and parsing avi headers: %d", avi->header_state);
2826
2827   switch (avi->header_state) {
2828     case GST_AVI_DEMUX_HEADER_TAG_LIST:
2829       if (gst_avi_demux_peek_chunk (avi, &tag, &size)) {
2830         avi->offset += 8 + GST_ROUND_UP_2 (size);
2831         if (tag != GST_RIFF_TAG_LIST)
2832           goto header_no_list;
2833
2834         gst_adapter_flush (avi->adapter, 8);
2835         /* Find the 'hdrl' LIST tag */
2836         GST_DEBUG ("Reading %d bytes", size);
2837         buf = gst_adapter_take_buffer (avi->adapter, size);
2838
2839         if (GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)) != GST_RIFF_LIST_hdrl)
2840           goto header_no_hdrl;
2841
2842         /* mind padding */
2843         if (size & 1)
2844           gst_adapter_flush (avi->adapter, 1);
2845
2846         GST_DEBUG ("'hdrl' LIST tag found. Parsing next chunk");
2847
2848         /* the hdrl starts with a 'avih' header */
2849         if (!gst_riff_parse_chunk (GST_ELEMENT (avi), buf, &offset, &tag, &sub))
2850           goto header_no_avih;
2851
2852         if (tag != GST_RIFF_TAG_avih)
2853           goto header_no_avih;
2854
2855         if (!gst_avi_demux_parse_avih (GST_ELEMENT (avi), sub, &avi->avih))
2856           goto header_wrong_avih;
2857
2858         GST_DEBUG_OBJECT (avi, "AVI header ok, reading elemnts from header");
2859
2860         /* now, read the elements from the header until the end */
2861         while (gst_riff_parse_chunk (GST_ELEMENT (avi), buf, &offset, &tag,
2862                 &sub)) {
2863           /* sub can be NULL on empty tags */
2864           if (!sub)
2865             continue;
2866
2867           switch (tag) {
2868             case GST_RIFF_TAG_LIST:
2869               if (GST_BUFFER_SIZE (sub) < 4)
2870                 goto next;
2871
2872               switch (GST_READ_UINT32_LE (GST_BUFFER_DATA (sub))) {
2873                 case GST_RIFF_LIST_strl:
2874                   if (!(gst_avi_demux_parse_stream (avi, sub))) {
2875                     sub = NULL;
2876                     GST_ELEMENT_WARNING (avi, STREAM, DEMUX, (NULL),
2877                         ("failed to parse stream, ignoring"));
2878                     goto next;
2879                   }
2880                   sub = NULL;
2881                   goto next;
2882                 case GST_RIFF_LIST_odml:
2883                   gst_avi_demux_parse_odml (avi, sub);
2884                   sub = NULL;
2885                   break;
2886                 default:
2887                   GST_WARNING_OBJECT (avi,
2888                       "Unknown list %" GST_FOURCC_FORMAT " in AVI header",
2889                       GST_FOURCC_ARGS (GST_READ_UINT32_LE (GST_BUFFER_DATA
2890                               (sub))));
2891                   /* fall-through */
2892                 case GST_RIFF_TAG_JUNK:
2893                   goto next;
2894               }
2895               break;
2896             case GST_RIFF_IDIT:
2897               gst_avi_demux_parse_idit (avi, sub);
2898               goto next;
2899             default:
2900               GST_WARNING_OBJECT (avi,
2901                   "Unknown off %d tag %" GST_FOURCC_FORMAT " in AVI header",
2902                   offset, GST_FOURCC_ARGS (tag));
2903               /* fall-through */
2904             case GST_RIFF_TAG_JUNK:
2905             next:
2906               /* move to next chunk */
2907               if (sub)
2908                 gst_buffer_unref (sub);
2909               sub = NULL;
2910               break;
2911           }
2912         }
2913         gst_buffer_unref (buf);
2914         GST_DEBUG ("elements parsed");
2915
2916         /* check parsed streams */
2917         if (avi->num_streams == 0) {
2918           goto no_streams;
2919         } else if (avi->num_streams != avi->avih->streams) {
2920           GST_WARNING_OBJECT (avi,
2921               "Stream header mentioned %d streams, but %d available",
2922               avi->avih->streams, avi->num_streams);
2923         }
2924         GST_DEBUG ("Get junk and info next");
2925         avi->header_state = GST_AVI_DEMUX_HEADER_INFO;
2926       } else {
2927         /* Need more data */
2928         return ret;
2929       }
2930       /* fall-though */
2931     case GST_AVI_DEMUX_HEADER_INFO:
2932       GST_DEBUG_OBJECT (avi, "skipping junk between header and data ...");
2933       while (TRUE) {
2934         if (gst_adapter_available (avi->adapter) < 12)
2935           return GST_FLOW_OK;
2936
2937         data = gst_adapter_peek (avi->adapter, 12);
2938         tag = GST_READ_UINT32_LE (data);
2939         size = GST_READ_UINT32_LE (data + 4);
2940         ltag = GST_READ_UINT32_LE (data + 8);
2941
2942         if (tag == GST_RIFF_TAG_LIST) {
2943           switch (ltag) {
2944             case GST_RIFF_LIST_movi:
2945               gst_adapter_flush (avi->adapter, 12);
2946               avi->offset += 12;
2947               goto skipping_done;
2948             case GST_RIFF_LIST_INFO:
2949               GST_DEBUG ("Found INFO chunk");
2950               if (gst_avi_demux_peek_chunk (avi, &tag, &size)) {
2951                 GST_DEBUG ("got size %d", size);
2952                 avi->offset += 12;
2953                 gst_adapter_flush (avi->adapter, 12);
2954                 if (size > 4) {
2955                   buf = gst_adapter_take_buffer (avi->adapter, size - 4);
2956                   /* mind padding */
2957                   if (size & 1)
2958                     gst_adapter_flush (avi->adapter, 1);
2959                   gst_riff_parse_info (GST_ELEMENT (avi), buf, &tags);
2960                   if (tags) {
2961                     if (avi->globaltags) {
2962                       gst_tag_list_insert (avi->globaltags, tags,
2963                           GST_TAG_MERGE_REPLACE);
2964                     } else {
2965                       avi->globaltags = tags;
2966                     }
2967                   }
2968                   tags = NULL;
2969                   gst_buffer_unref (buf);
2970
2971                   avi->offset += GST_ROUND_UP_2 (size) - 4;
2972                 } else {
2973                   GST_DEBUG ("skipping INFO LIST prefix");
2974                 }
2975               } else {
2976                 /* Need more data */
2977                 return GST_FLOW_OK;
2978               }
2979               break;
2980             default:
2981               if (gst_avi_demux_peek_chunk (avi, &tag, &size)) {
2982                 avi->offset += 8 + GST_ROUND_UP_2 (size);
2983                 gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
2984                 // ??? goto iterate; ???
2985               } else {
2986                 /* Need more data */
2987                 return GST_FLOW_OK;
2988               }
2989               break;
2990           }
2991         } else {
2992           if (gst_avi_demux_peek_chunk (avi, &tag, &size)) {
2993             avi->offset += 8 + GST_ROUND_UP_2 (size);
2994             gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
2995             //goto iterate;
2996           } else {
2997             /* Need more data */
2998             return GST_FLOW_OK;
2999           }
3000         }
3001       }
3002       break;
3003     default:
3004       GST_WARNING ("unhandled header state: %d", avi->header_state);
3005       break;
3006   }
3007 skipping_done:
3008
3009   GST_DEBUG_OBJECT (avi, "skipping done ... (streams=%u, stream[0].indexes=%p)",
3010       avi->num_streams, avi->stream[0].indexes);
3011
3012   GST_DEBUG ("Found movi chunk. Starting to stream data");
3013   avi->state = GST_AVI_DEMUX_MOVI;
3014
3015   /* no indexes in push mode, but it still sets some variables */
3016   gst_avi_demux_calculate_durations_from_index (avi);
3017
3018   gst_avi_demux_expose_streams (avi, TRUE);
3019
3020   /* prepare all streams for index 0 */
3021   for (i = 0; i < avi->num_streams; i++)
3022     avi->stream[i].current_entry = 0;
3023
3024   /* create initial NEWSEGMENT event */
3025   if ((stop = avi->segment.stop) == GST_CLOCK_TIME_NONE)
3026     stop = avi->segment.duration;
3027
3028   GST_DEBUG_OBJECT (avi, "segment stop %" G_GINT64_FORMAT, stop);
3029
3030   if (avi->seek_event)
3031     gst_event_unref (avi->seek_event);
3032   avi->seek_event = gst_event_new_new_segment_full
3033       (FALSE, avi->segment.rate, avi->segment.applied_rate, GST_FORMAT_TIME,
3034       avi->segment.start, stop, avi->segment.time);
3035
3036   gst_avi_demux_check_seekability (avi);
3037
3038   /* at this point we know all the streams and we can signal the no more
3039    * pads signal */
3040   GST_DEBUG_OBJECT (avi, "signaling no more pads");
3041   gst_element_no_more_pads (GST_ELEMENT (avi));
3042
3043   return GST_FLOW_OK;
3044
3045   /* ERRORS */
3046 no_streams:
3047   {
3048     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No streams found"));
3049     return GST_FLOW_ERROR;
3050   }
3051 header_no_list:
3052   {
3053     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
3054         ("Invalid AVI header (no LIST at start): %"
3055             GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
3056     return GST_FLOW_ERROR;
3057   }
3058 header_no_hdrl:
3059   {
3060     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
3061         ("Invalid AVI header (no hdrl at start): %"
3062             GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
3063     gst_buffer_unref (buf);
3064     return GST_FLOW_ERROR;
3065   }
3066 header_no_avih:
3067   {
3068     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
3069         ("Invalid AVI header (no avih at start): %"
3070             GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
3071     if (sub)
3072       gst_buffer_unref (sub);
3073
3074     gst_buffer_unref (buf);
3075     return GST_FLOW_ERROR;
3076   }
3077 header_wrong_avih:
3078   {
3079     gst_buffer_unref (buf);
3080     return GST_FLOW_ERROR;
3081   }
3082 }
3083
3084 static void
3085 gst_avi_demux_add_date_tag (GstAviDemux * avi, gint y, gint m, gint d)
3086 {
3087   GDate *date;
3088   date = g_date_new_dmy (d, m, y);
3089   if (!g_date_valid (date)) {
3090     /* bogus date */
3091     GST_WARNING_OBJECT (avi, "Refusing to add invalid date %d-%d-%d", y, m, d);
3092     g_date_free (date);
3093     return;
3094   }
3095
3096   if (avi->globaltags == NULL)
3097     avi->globaltags = gst_tag_list_new ();
3098
3099   gst_tag_list_add (avi->globaltags, GST_TAG_MERGE_REPLACE, GST_TAG_DATE, date,
3100       NULL);
3101   g_date_free (date);
3102 }
3103
3104 static void
3105 gst_avi_demux_parse_idit_nums_only (GstAviDemux * avi, gchar * data)
3106 {
3107   gint y, m, d;
3108   gint ret;
3109
3110   ret = sscanf (data, "%d:%d:%d", &y, &m, &d);
3111   if (ret != 3) {
3112     GST_WARNING_OBJECT (avi, "Failed to parse IDIT tag");
3113     return;
3114   }
3115   gst_avi_demux_add_date_tag (avi, y, m, d);
3116 }
3117
3118 static gint
3119 get_month_num (gchar * data, guint size)
3120 {
3121   if (g_ascii_strncasecmp (data, "jan", 3) == 0) {
3122     return 1;
3123   } else if (g_ascii_strncasecmp (data, "feb", 3) == 0) {
3124     return 2;
3125   } else if (g_ascii_strncasecmp (data, "mar", 3) == 0) {
3126     return 3;
3127   } else if (g_ascii_strncasecmp (data, "apr", 3) == 0) {
3128     return 4;
3129   } else if (g_ascii_strncasecmp (data, "may", 3) == 0) {
3130     return 5;
3131   } else if (g_ascii_strncasecmp (data, "jun", 3) == 0) {
3132     return 6;
3133   } else if (g_ascii_strncasecmp (data, "jul", 3) == 0) {
3134     return 7;
3135   } else if (g_ascii_strncasecmp (data, "aug", 3) == 0) {
3136     return 8;
3137   } else if (g_ascii_strncasecmp (data, "sep", 3) == 0) {
3138     return 9;
3139   } else if (g_ascii_strncasecmp (data, "oct", 3) == 0) {
3140     return 10;
3141   } else if (g_ascii_strncasecmp (data, "nov", 3) == 0) {
3142     return 11;
3143   } else if (g_ascii_strncasecmp (data, "dec", 3) == 0) {
3144     return 12;
3145   }
3146
3147   return 0;
3148 }
3149
3150 static void
3151 gst_avi_demux_parse_idit_text (GstAviDemux * avi, gchar * data)
3152 {
3153   gint year, month, day;
3154   gint hour, min, sec;
3155   gint ret;
3156   gchar weekday[4];
3157   gchar monthstr[4];
3158
3159   ret = sscanf (data, "%3s %3s %d %d:%d:%d %d", weekday, monthstr, &day, &hour,
3160       &min, &sec, &year);
3161   if (ret != 7) {
3162     GST_WARNING_OBJECT (avi, "Failed to parse IDIT tag");
3163     return;
3164   }
3165   month = get_month_num (monthstr, strlen (monthstr));
3166   gst_avi_demux_add_date_tag (avi, year, month, day);
3167 }
3168
3169 static void
3170 gst_avi_demux_parse_idit (GstAviDemux * avi, GstBuffer * buf)
3171 {
3172   gchar *data = (gchar *) GST_BUFFER_DATA (buf);
3173   guint size = GST_BUFFER_SIZE (buf);
3174   gchar *safedata = NULL;
3175
3176   /*
3177    * According to:
3178    * http://www.eden-foundation.org/products/code/film_date_stamp/index.html
3179    *
3180    * This tag could be in one of the below formats
3181    * 2005:08:17 11:42:43
3182    * THU OCT 26 16:46:04 2006
3183    * Mon Mar  3 09:44:56 2008
3184    *
3185    * FIXME: Our date tag doesn't include hours
3186    */
3187
3188   /* skip eventual initial whitespace */
3189   while (size > 0 && g_ascii_isspace (data[0])) {
3190     data++;
3191     size--;
3192   }
3193
3194   if (size == 0) {
3195     goto non_parsable;
3196   }
3197
3198   /* make a safe copy to add a \0 to the end of the string */
3199   safedata = g_strndup (data, size);
3200
3201   /* test if the first char is a alpha or a number */
3202   if (g_ascii_isdigit (data[0])) {
3203     gst_avi_demux_parse_idit_nums_only (avi, safedata);
3204     g_free (safedata);
3205     return;
3206   } else if (g_ascii_isalpha (data[0])) {
3207     gst_avi_demux_parse_idit_text (avi, safedata);
3208     g_free (safedata);
3209     return;
3210   }
3211
3212   g_free (safedata);
3213
3214 non_parsable:
3215   GST_WARNING_OBJECT (avi, "IDIT tag has no parsable info");
3216 }
3217
3218 /*
3219  * Read full AVI headers.
3220  */
3221 static GstFlowReturn
3222 gst_avi_demux_stream_header_pull (GstAviDemux * avi)
3223 {
3224   GstFlowReturn res;
3225   GstBuffer *buf, *sub = NULL;
3226   guint32 tag;
3227   guint offset = 4;
3228   gint64 stop;
3229   GstElement *element = GST_ELEMENT_CAST (avi);
3230   GstClockTime stamp;
3231   GstTagList *tags = NULL;
3232
3233   stamp = gst_util_get_timestamp ();
3234
3235   /* the header consists of a 'hdrl' LIST tag */
3236   res = gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag, &buf);
3237   if (res != GST_FLOW_OK)
3238     goto pull_range_failed;
3239   else if (tag != GST_RIFF_TAG_LIST)
3240     goto no_list;
3241   else if (GST_BUFFER_SIZE (buf) < 4)
3242     goto no_header;
3243
3244   GST_DEBUG_OBJECT (avi, "parsing headers");
3245
3246   /* Find the 'hdrl' LIST tag */
3247   while (GST_READ_UINT32_LE (GST_BUFFER_DATA (buf)) != GST_RIFF_LIST_hdrl) {
3248     GST_LOG_OBJECT (avi, "buffer contains %" GST_FOURCC_FORMAT,
3249         GST_FOURCC_ARGS (GST_READ_UINT32_LE (GST_BUFFER_DATA (buf))));
3250
3251     /* Eat up */
3252     gst_buffer_unref (buf);
3253
3254     /* read new chunk */
3255     res = gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag, &buf);
3256     if (res != GST_FLOW_OK)
3257       goto pull_range_failed;
3258     else if (tag != GST_RIFF_TAG_LIST)
3259       goto no_list;
3260     else if (GST_BUFFER_SIZE (buf) < 4)
3261       goto no_header;
3262   }
3263
3264   GST_DEBUG_OBJECT (avi, "hdrl LIST tag found");
3265
3266   /* the hdrl starts with a 'avih' header */
3267   if (!gst_riff_parse_chunk (element, buf, &offset, &tag, &sub))
3268     goto no_avih;
3269   else if (tag != GST_RIFF_TAG_avih)
3270     goto no_avih;
3271   else if (!gst_avi_demux_parse_avih (element, sub, &avi->avih))
3272     goto invalid_avih;
3273
3274   GST_DEBUG_OBJECT (avi, "AVI header ok, reading elements from header");
3275
3276   /* now, read the elements from the header until the end */
3277   while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) {
3278     /* sub can be NULL on empty tags */
3279     if (!sub)
3280       continue;
3281
3282     switch (tag) {
3283       case GST_RIFF_TAG_LIST:
3284       {
3285         guint8 *data;
3286         guint32 fourcc;
3287
3288         if (GST_BUFFER_SIZE (sub) < 4)
3289           goto next;
3290
3291         data = GST_BUFFER_DATA (sub);
3292         fourcc = GST_READ_UINT32_LE (data);
3293
3294         switch (fourcc) {
3295           case GST_RIFF_LIST_strl:
3296             if (!(gst_avi_demux_parse_stream (avi, sub))) {
3297               GST_ELEMENT_WARNING (avi, STREAM, DEMUX, (NULL),
3298                   ("failed to parse stream, ignoring"));
3299               sub = NULL;
3300             }
3301             sub = NULL;
3302             goto next;
3303           case GST_RIFF_LIST_odml:
3304             gst_avi_demux_parse_odml (avi, sub);
3305             sub = NULL;
3306             break;
3307           case GST_RIFF_LIST_INFO:
3308             GST_BUFFER_DATA (sub) = data + 4;
3309             GST_BUFFER_SIZE (sub) -= 4;
3310             gst_riff_parse_info (element, sub, &tags);
3311             if (tags) {
3312               if (avi->globaltags) {
3313                 gst_tag_list_insert (avi->globaltags, tags,
3314                     GST_TAG_MERGE_REPLACE);
3315               } else {
3316                 avi->globaltags = tags;
3317               }
3318             }
3319             tags = NULL;
3320             break;
3321           default:
3322             GST_WARNING_OBJECT (avi,
3323                 "Unknown list %" GST_FOURCC_FORMAT " in AVI header",
3324                 GST_FOURCC_ARGS (fourcc));
3325             GST_MEMDUMP_OBJECT (avi, "Unknown list", GST_BUFFER_DATA (sub),
3326                 GST_BUFFER_SIZE (sub));
3327             /* fall-through */
3328           case GST_RIFF_TAG_JUNK:
3329             goto next;
3330         }
3331         break;
3332       }
3333       case GST_RIFF_IDIT:
3334         gst_avi_demux_parse_idit (avi, sub);
3335         goto next;
3336       default:
3337         GST_WARNING_OBJECT (avi,
3338             "Unknown tag %" GST_FOURCC_FORMAT " in AVI header at off %d",
3339             GST_FOURCC_ARGS (tag), offset);
3340         GST_MEMDUMP_OBJECT (avi, "Unknown tag", GST_BUFFER_DATA (sub),
3341             GST_BUFFER_SIZE (sub));
3342         /* fall-through */
3343       case GST_RIFF_TAG_JUNK:
3344       next:
3345         if (sub)
3346           gst_buffer_unref (sub);
3347         sub = NULL;
3348         break;
3349     }
3350   }
3351   gst_buffer_unref (buf);
3352   GST_DEBUG ("elements parsed");
3353
3354   /* check parsed streams */
3355   if (avi->num_streams == 0)
3356     goto no_streams;
3357   else if (avi->num_streams != avi->avih->streams) {
3358     GST_WARNING_OBJECT (avi,
3359         "Stream header mentioned %d streams, but %d available",
3360         avi->avih->streams, avi->num_streams);
3361   }
3362
3363   GST_DEBUG_OBJECT (avi, "skipping junk between header and data, offset=%"
3364       G_GUINT64_FORMAT, avi->offset);
3365
3366   /* Now, find the data (i.e. skip all junk between header and data) */
3367   do {
3368     guint size;
3369     guint8 *data;
3370     guint32 tag, ltag;
3371
3372     res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf);
3373     if (res != GST_FLOW_OK) {
3374       GST_DEBUG_OBJECT (avi, "pull_range failure while looking for tags");
3375       goto pull_range_failed;
3376     } else if (GST_BUFFER_SIZE (buf) < 12) {
3377       GST_DEBUG_OBJECT (avi, "got %d bytes which is less than 12 bytes",
3378           GST_BUFFER_SIZE (buf));
3379       gst_buffer_unref (buf);
3380       return GST_FLOW_ERROR;
3381     }
3382
3383     data = GST_BUFFER_DATA (buf);
3384
3385     tag = GST_READ_UINT32_LE (data);
3386     size = GST_READ_UINT32_LE (data + 4);
3387     ltag = GST_READ_UINT32_LE (data + 8);
3388
3389     GST_DEBUG ("tag %" GST_FOURCC_FORMAT ", size %u",
3390         GST_FOURCC_ARGS (tag), size);
3391     GST_MEMDUMP ("Tag content", data, GST_BUFFER_SIZE (buf));
3392     gst_buffer_unref (buf);
3393
3394     switch (tag) {
3395       case GST_RIFF_TAG_LIST:{
3396         switch (ltag) {
3397           case GST_RIFF_LIST_movi:
3398             GST_DEBUG_OBJECT (avi,
3399                 "Reached the 'movi' tag, we're done with skipping");
3400             goto skipping_done;
3401           case GST_RIFF_LIST_INFO:
3402             res =
3403                 gst_riff_read_chunk (element, avi->sinkpad, &avi->offset, &tag,
3404                 &buf);
3405             if (res != GST_FLOW_OK) {
3406               GST_DEBUG_OBJECT (avi, "couldn't read INFO chunk");
3407               goto pull_range_failed;
3408             }
3409             GST_DEBUG ("got size %u", GST_BUFFER_SIZE (buf));
3410             if (size < 4) {
3411               GST_DEBUG ("skipping INFO LIST prefix");
3412               avi->offset += (4 - GST_ROUND_UP_2 (size));
3413               gst_buffer_unref (buf);
3414               continue;
3415             }
3416
3417             sub = gst_buffer_create_sub (buf, 4, GST_BUFFER_SIZE (buf) - 4);
3418             gst_riff_parse_info (element, sub, &tags);
3419             if (tags) {
3420               if (avi->globaltags) {
3421                 gst_tag_list_insert (avi->globaltags, tags,
3422                     GST_TAG_MERGE_REPLACE);
3423               } else {
3424                 avi->globaltags = tags;
3425               }
3426             }
3427             tags = NULL;
3428             if (sub) {
3429               gst_buffer_unref (sub);
3430               sub = NULL;
3431             }
3432             gst_buffer_unref (buf);
3433             /* gst_riff_read_chunk() has already advanced avi->offset */
3434             break;
3435           default:
3436             GST_WARNING_OBJECT (avi,
3437                 "Skipping unknown list tag %" GST_FOURCC_FORMAT,
3438                 GST_FOURCC_ARGS (ltag));
3439             avi->offset += 8 + GST_ROUND_UP_2 (size);
3440             break;
3441         }
3442       }
3443         break;
3444       default:
3445         GST_WARNING_OBJECT (avi, "Skipping unknown tag %" GST_FOURCC_FORMAT,
3446             GST_FOURCC_ARGS (tag));
3447         /* Fall-through */
3448       case GST_MAKE_FOURCC ('J', 'U', 'N', 'Q'):
3449       case GST_MAKE_FOURCC ('J', 'U', 'N', 'K'):
3450         /* Only get buffer for debugging if the memdump is needed  */
3451         if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= 9) {
3452           res = gst_pad_pull_range (avi->sinkpad, avi->offset, size, &buf);
3453           if (res != GST_FLOW_OK) {
3454             GST_DEBUG_OBJECT (avi, "couldn't read INFO chunk");
3455             goto pull_range_failed;
3456           }
3457           GST_MEMDUMP ("Junk", GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
3458           gst_buffer_unref (buf);
3459         }
3460         avi->offset += 8 + GST_ROUND_UP_2 (size);
3461         break;
3462     }
3463   } while (1);
3464 skipping_done:
3465
3466   GST_DEBUG_OBJECT (avi, "skipping done ... (streams=%u, stream[0].indexes=%p)",
3467       avi->num_streams, avi->stream[0].indexes);
3468
3469   /* create or read stream index (for seeking) */
3470   if (avi->stream[0].indexes != NULL) {
3471     /* we read a super index already (gst_avi_demux_parse_superindex() ) */
3472     gst_avi_demux_read_subindexes_pull (avi);
3473   }
3474   if (!avi->have_index) {
3475     if (avi->avih->flags & GST_RIFF_AVIH_HASINDEX)
3476       gst_avi_demux_stream_index (avi);
3477
3478     /* still no index, scan */
3479     if (!avi->have_index) {
3480       gst_avi_demux_stream_scan (avi);
3481
3482       /* still no index.. this is a fatal error for now.
3483        * FIXME, we should switch to plain push mode without seeking
3484        * instead of failing. */
3485       if (!avi->have_index)
3486         goto no_index;
3487     }
3488   }
3489   /* use the indexes now to construct nice durations */
3490   gst_avi_demux_calculate_durations_from_index (avi);
3491
3492   gst_avi_demux_expose_streams (avi, FALSE);
3493
3494   /* create initial NEWSEGMENT event */
3495   if ((stop = avi->segment.stop) == GST_CLOCK_TIME_NONE)
3496     stop = avi->segment.duration;
3497
3498   GST_DEBUG_OBJECT (avi, "segment stop %" G_GINT64_FORMAT, stop);
3499
3500   /* do initial seek to the default segment values */
3501   gst_avi_demux_do_seek (avi, &avi->segment);
3502
3503   /* prepare initial segment */
3504   if (avi->seek_event)
3505     gst_event_unref (avi->seek_event);
3506   avi->seek_event = gst_event_new_new_segment_full
3507       (FALSE, avi->segment.rate, avi->segment.applied_rate, GST_FORMAT_TIME,
3508       avi->segment.start, stop, avi->segment.time);
3509
3510   stamp = gst_util_get_timestamp () - stamp;
3511   GST_DEBUG_OBJECT (avi, "pulling header took %" GST_TIME_FORMAT,
3512       GST_TIME_ARGS (stamp));
3513
3514   /* at this point we know all the streams and we can signal the no more
3515    * pads signal */
3516   GST_DEBUG_OBJECT (avi, "signaling no more pads");
3517   gst_element_no_more_pads (GST_ELEMENT_CAST (avi));
3518
3519   return GST_FLOW_OK;
3520
3521   /* ERRORS */
3522 no_list:
3523   {
3524     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
3525         ("Invalid AVI header (no LIST at start): %"
3526             GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
3527     gst_buffer_unref (buf);
3528     return GST_FLOW_ERROR;
3529   }
3530 no_header:
3531   {
3532     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
3533         ("Invalid AVI header (no hdrl at start): %"
3534             GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
3535     gst_buffer_unref (buf);
3536     return GST_FLOW_ERROR;
3537   }
3538 no_avih:
3539   {
3540     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
3541         ("Invalid AVI header (no avih at start): %"
3542             GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
3543     if (sub)
3544       gst_buffer_unref (sub);
3545     gst_buffer_unref (buf);
3546     return GST_FLOW_ERROR;
3547   }
3548 invalid_avih:
3549   {
3550     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
3551         ("Invalid AVI header (cannot parse avih at start)"));
3552     gst_buffer_unref (buf);
3553     return GST_FLOW_ERROR;
3554   }
3555 no_streams:
3556   {
3557     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No streams found"));
3558     return GST_FLOW_ERROR;
3559   }
3560 no_index:
3561   {
3562     GST_WARNING ("file without or too big index");
3563     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
3564         ("Could not get/create index"));
3565     return GST_FLOW_ERROR;
3566   }
3567 pull_range_failed:
3568   {
3569     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
3570         ("pull_range flow reading header: %s", gst_flow_get_name (res)));
3571     return GST_FLOW_ERROR;
3572   }
3573 }
3574
3575 /* move a stream to @index */
3576 static void
3577 gst_avi_demux_move_stream (GstAviDemux * avi, GstAviStream * stream,
3578     GstSegment * segment, guint index)
3579 {
3580   GST_DEBUG_OBJECT (avi, "Move stream %d to %u", stream->num, index);
3581
3582   if (segment->rate < 0.0) {
3583     guint next_key;
3584     /* Because we don't know the frame order we need to push from the prev keyframe
3585      * to the next keyframe. If there is a smart decoder downstream he will notice
3586      * that there are too many encoded frames send and return UNEXPECTED when there
3587      * are enough decoded frames to fill the segment. */
3588     next_key = gst_avi_demux_index_next (avi, stream, index, TRUE);
3589
3590     /* FIXME, we go back to 0, we should look at segment.start. We will however
3591      * stop earlier when the see the timestamp < segment.start */
3592     stream->start_entry = 0;
3593     stream->step_entry = index;
3594     stream->current_entry = index;
3595     stream->stop_entry = next_key;
3596
3597     GST_DEBUG_OBJECT (avi, "reverse seek: start %u, step %u, stop %u",
3598         stream->start_entry, stream->step_entry, stream->stop_entry);
3599   } else {
3600     stream->start_entry = index;
3601     stream->step_entry = index;
3602     stream->stop_entry = gst_avi_demux_index_last (avi, stream);
3603   }
3604   if (stream->current_entry != index) {
3605     GST_DEBUG_OBJECT (avi, "Move DISCONT from %u to %u",
3606         stream->current_entry, index);
3607     stream->current_entry = index;
3608     stream->discont = TRUE;
3609   }
3610
3611   /* update the buffer info */
3612   gst_avi_demux_get_buffer_info (avi, stream, index,
3613       &stream->current_timestamp, &stream->current_ts_end,
3614       &stream->current_offset, &stream->current_offset_end);
3615
3616   GST_DEBUG_OBJECT (avi, "Moved to %u, ts %" GST_TIME_FORMAT
3617       ", ts_end %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
3618       ", off_end %" G_GUINT64_FORMAT, index,
3619       GST_TIME_ARGS (stream->current_timestamp),
3620       GST_TIME_ARGS (stream->current_ts_end), stream->current_offset,
3621       stream->current_offset_end);
3622 }
3623
3624 /*
3625  * Do the actual seeking.
3626  */
3627 static gboolean
3628 gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment)
3629 {
3630   GstClockTime seek_time;
3631   gboolean keyframe;
3632   guint i, index;
3633   GstAviStream *stream;
3634
3635   seek_time = segment->last_stop;
3636   keyframe = !!(segment->flags & GST_SEEK_FLAG_KEY_UNIT);
3637
3638   GST_DEBUG_OBJECT (avi, "seek to: %" GST_TIME_FORMAT
3639       " keyframe seeking:%d", GST_TIME_ARGS (seek_time), keyframe);
3640
3641   /* FIXME, this code assumes the main stream with keyframes is stream 0,
3642    * which is mostly correct... */
3643   stream = &avi->stream[avi->main_stream];
3644
3645   /* get the entry index for the requested position */
3646   index = gst_avi_demux_index_for_time (avi, stream, seek_time);
3647   GST_DEBUG_OBJECT (avi, "Got entry %u", index);
3648
3649   /* check if we are already on a keyframe */
3650   if (!ENTRY_IS_KEYFRAME (&stream->index[index])) {
3651     GST_DEBUG_OBJECT (avi, "not keyframe, searching back");
3652     /* now go to the previous keyframe, this is where we should start
3653      * decoding from. */
3654     index = gst_avi_demux_index_prev (avi, stream, index, TRUE);
3655     GST_DEBUG_OBJECT (avi, "previous keyframe at %u", index);
3656   }
3657
3658   /* move the main stream to this position */
3659   gst_avi_demux_move_stream (avi, stream, segment, index);
3660
3661   if (keyframe) {
3662     /* when seeking to a keyframe, we update the result seek time
3663      * to the time of the keyframe. */
3664     seek_time = stream->current_timestamp;
3665     GST_DEBUG_OBJECT (avi, "keyframe adjusted to %" GST_TIME_FORMAT,
3666         GST_TIME_ARGS (seek_time));
3667   }
3668
3669   /* the seek time is also the last_stop and stream time when going
3670    * forwards */
3671   segment->last_stop = seek_time;
3672   if (segment->rate > 0.0)
3673     segment->time = seek_time;
3674
3675   /* now set DISCONT and align the other streams */
3676   for (i = 0; i < avi->num_streams; i++) {
3677     GstAviStream *ostream;
3678
3679     ostream = &avi->stream[i];
3680     if ((ostream == stream) || (ostream->index == NULL))
3681       continue;
3682
3683     /* get the entry index for the requested position */
3684     index = gst_avi_demux_index_for_time (avi, ostream, seek_time);
3685
3686     /* move to previous keyframe */
3687     if (!ENTRY_IS_KEYFRAME (&ostream->index[index]))
3688       index = gst_avi_demux_index_prev (avi, ostream, index, TRUE);
3689
3690     gst_avi_demux_move_stream (avi, ostream, segment, index);
3691   }
3692   GST_DEBUG_OBJECT (avi, "done seek to: %" GST_TIME_FORMAT,
3693       GST_TIME_ARGS (seek_time));
3694
3695   return TRUE;
3696 }
3697
3698 /*
3699  * Handle seek event.
3700  */
3701 static gboolean
3702 gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad, GstEvent * event)
3703 {
3704   gdouble rate;
3705   GstFormat format;
3706   GstSeekFlags flags;
3707   GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
3708   gint64 cur, stop;
3709   gboolean flush;
3710   gboolean update;
3711   GstSegment seeksegment = { 0, };
3712   gint i;
3713
3714   if (event) {
3715     GST_DEBUG_OBJECT (avi, "doing seek with event");
3716
3717     gst_event_parse_seek (event, &rate, &format, &flags,
3718         &cur_type, &cur, &stop_type, &stop);
3719
3720     /* we have to have a format as the segment format. Try to convert
3721      * if not. */
3722     if (format != GST_FORMAT_TIME) {
3723       GstFormat fmt = GST_FORMAT_TIME;
3724       gboolean res = TRUE;
3725
3726       if (cur_type != GST_SEEK_TYPE_NONE)
3727         res = gst_pad_query_convert (pad, format, cur, &fmt, &cur);
3728       if (res && stop_type != GST_SEEK_TYPE_NONE)
3729         res = gst_pad_query_convert (pad, format, stop, &fmt, &stop);
3730       if (!res)
3731         goto no_format;
3732
3733       format = fmt;
3734     }
3735     GST_DEBUG_OBJECT (avi,
3736         "seek requested: rate %g cur %" GST_TIME_FORMAT " stop %"
3737         GST_TIME_FORMAT, rate, GST_TIME_ARGS (cur), GST_TIME_ARGS (stop));
3738     /* FIXME: can we do anything with rate!=1.0 */
3739   } else {
3740     GST_DEBUG_OBJECT (avi, "doing seek without event");
3741     flags = 0;
3742     rate = 1.0;
3743   }
3744
3745   /* save flush flag */
3746   flush = flags & GST_SEEK_FLAG_FLUSH;
3747
3748   if (flush) {
3749     GstEvent *fevent = gst_event_new_flush_start ();
3750
3751     /* for a flushing seek, we send a flush_start on all pads. This will
3752      * eventually stop streaming with a WRONG_STATE. We can thus eventually
3753      * take the STREAM_LOCK. */
3754     GST_DEBUG_OBJECT (avi, "sending flush start");
3755     gst_avi_demux_push_event (avi, gst_event_ref (fevent));
3756     gst_pad_push_event (avi->sinkpad, fevent);
3757   } else {
3758     /* a non-flushing seek, we PAUSE the task so that we can take the
3759      * STREAM_LOCK */
3760     GST_DEBUG_OBJECT (avi, "non flushing seek, pausing task");
3761     gst_pad_pause_task (avi->sinkpad);
3762   }
3763
3764   /* wait for streaming to stop */
3765   GST_DEBUG_OBJECT (avi, "wait for streaming to stop");
3766   GST_PAD_STREAM_LOCK (avi->sinkpad);
3767
3768   /* copy segment, we need this because we still need the old
3769    * segment when we close the current segment. */
3770   memcpy (&seeksegment, &avi->segment, sizeof (GstSegment));
3771
3772   if (event) {
3773     GST_DEBUG_OBJECT (avi, "configuring seek");
3774     gst_segment_set_seek (&seeksegment, rate, format, flags,
3775         cur_type, cur, stop_type, stop, &update);
3776   }
3777   /* do the seek, seeksegment.last_stop contains the new position, this
3778    * actually never fails. */
3779   gst_avi_demux_do_seek (avi, &seeksegment);
3780
3781   if (flush) {
3782     GstEvent *fevent = gst_event_new_flush_stop ();
3783
3784     GST_DEBUG_OBJECT (avi, "sending flush stop");
3785     gst_avi_demux_push_event (avi, gst_event_ref (fevent));
3786     gst_pad_push_event (avi->sinkpad, fevent);
3787
3788     /* reset the last flow and mark discont, FLUSH is always DISCONT */
3789     for (i = 0; i < avi->num_streams; i++) {
3790       avi->stream[i].last_flow = GST_FLOW_OK;
3791       avi->stream[i].discont = TRUE;
3792     }
3793   } else if (avi->segment_running) {
3794     GstEvent *seg;
3795
3796     /* we are running the current segment and doing a non-flushing seek,
3797      * close the segment first based on the last_stop. */
3798     GST_DEBUG_OBJECT (avi, "closing running segment %" G_GINT64_FORMAT
3799         " to %" G_GINT64_FORMAT, avi->segment.start, avi->segment.last_stop);
3800     seg = gst_event_new_new_segment_full (TRUE,
3801         avi->segment.rate, avi->segment.applied_rate, avi->segment.format,
3802         avi->segment.start, avi->segment.last_stop, avi->segment.time);
3803     gst_avi_demux_push_event (avi, seg);
3804   }
3805
3806   /* now update the real segment info */
3807   memcpy (&avi->segment, &seeksegment, sizeof (GstSegment));
3808
3809   /* post the SEGMENT_START message when we do segmented playback */
3810   if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) {
3811     gst_element_post_message (GST_ELEMENT (avi),
3812         gst_message_new_segment_start (GST_OBJECT (avi),
3813             avi->segment.format, avi->segment.last_stop));
3814   }
3815
3816   /* prepare for streaming again */
3817   if ((stop = avi->segment.stop) == GST_CLOCK_TIME_NONE)
3818     stop = avi->segment.duration;
3819
3820   /* queue the segment event for the streaming thread. */
3821   if (avi->seek_event)
3822     gst_event_unref (avi->seek_event);
3823   if (avi->segment.rate > 0.0) {
3824     /* forwards goes from last_stop to stop */
3825     avi->seek_event = gst_event_new_new_segment_full (FALSE,
3826         avi->segment.rate, avi->segment.applied_rate, avi->segment.format,
3827         avi->segment.last_stop, stop, avi->segment.time);
3828   } else {
3829     /* reverse goes from start to last_stop */
3830     avi->seek_event = gst_event_new_new_segment_full (FALSE,
3831         avi->segment.rate, avi->segment.applied_rate, avi->segment.format,
3832         avi->segment.start, avi->segment.last_stop, avi->segment.time);
3833   }
3834
3835   if (!avi->streaming) {
3836     avi->segment_running = TRUE;
3837     gst_pad_start_task (avi->sinkpad, (GstTaskFunction) gst_avi_demux_loop,
3838         avi->sinkpad);
3839   }
3840   GST_PAD_STREAM_UNLOCK (avi->sinkpad);
3841
3842   return TRUE;
3843
3844   /* ERRORS */
3845 no_format:
3846   {
3847     GST_DEBUG_OBJECT (avi, "unsupported format given, seek aborted.");
3848     return FALSE;
3849   }
3850 }
3851
3852 static gboolean
3853 gst_avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad,
3854     GstEvent * event)
3855 {
3856   gdouble rate;
3857   GstFormat format;
3858   GstSeekFlags flags;
3859   GstSeekType cur_type, stop_type;
3860   gint64 cur, stop;
3861   gboolean res;
3862   gint64 byte_cur;
3863   gint64 time = 0;
3864   GstIndexEntry *entry;
3865
3866   GST_DEBUG_OBJECT (avi, "doing push-based seek");
3867
3868   gst_event_parse_seek (event, &rate, &format, &flags,
3869       &cur_type, &cur, &stop_type, &stop);
3870
3871   if (stop_type != GST_SEEK_TYPE_NONE)
3872     goto unsupported_seek;
3873   stop = -1;
3874
3875   /* only forward streaming and seeking is possible */
3876   if (rate <= 0)
3877     goto unsupported_seek;
3878
3879   /* only TIME */
3880   if (format != GST_FORMAT_TIME)
3881     goto unsupported_format;
3882
3883   /* not really advisable otherwise */
3884   if ((flags & GST_SEEK_FLAG_FLUSH) == 0)
3885     goto unsupported_seek;
3886
3887   /* should have index, let's check anyway */
3888   if (!avi->element_index)
3889     goto abort_seek;
3890
3891   /* find reasonable corresponding BYTE position
3892    * note that we have no keyframe info in push mode whatsoever,
3893    * so we can not cater for related stuff in any way */
3894
3895   /* some slack aiming for a keyframe */
3896   if (cur < GST_AVI_SEEK_PUSH_DISPLACE)
3897     cur = 0;
3898   else
3899     cur -= GST_AVI_SEEK_PUSH_DISPLACE;
3900
3901   entry = gst_index_get_assoc_entry (avi->element_index, avi->index_id,
3902       GST_INDEX_LOOKUP_BEFORE, GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_TIME, cur);
3903
3904   if (!entry)
3905     goto abort_seek;
3906
3907   gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &byte_cur);
3908   gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &time);
3909
3910   GST_DEBUG_OBJECT (avi, "found index entry for %" GST_TIME_FORMAT
3911       " at %" GST_TIME_FORMAT ", located at offset %" G_GINT64_FORMAT,
3912       GST_TIME_ARGS (cur), GST_TIME_ARGS (time), byte_cur);
3913
3914   /* adjust offset to be in each stream's region */
3915   byte_cur = gst_avi_demux_seek_streams (avi, byte_cur, TRUE);
3916
3917   /* let's not try push seeking if target and entry are too far apart */
3918   if (cur - time > 30 * GST_SECOND)
3919     goto abort_seek;
3920
3921   GST_DEBUG_OBJECT (avi, "Pushing BYTE seek rate %g, "
3922       "start %" G_GINT64_FORMAT ", stop %" G_GINT64_FORMAT, rate, byte_cur,
3923       stop);
3924   /* BYTE seek event */
3925   event = gst_event_new_seek (rate, GST_FORMAT_BYTES, flags, cur_type, byte_cur,
3926       stop_type, stop);
3927   res = gst_pad_push_event (avi->sinkpad, event);
3928
3929   return res;
3930
3931   /* ERRORS */
3932 abort_seek:
3933   {
3934     GST_DEBUG_OBJECT (avi, "could not determine byte position to seek to, "
3935         "seek aborted.");
3936     return FALSE;
3937   }
3938 unsupported_seek:
3939   {
3940     GST_DEBUG_OBJECT (avi, "unsupported seek, seek aborted.");
3941     return FALSE;
3942   }
3943 unsupported_format:
3944   {
3945     GST_DEBUG_OBJECT (avi, "unsupported format given, seek aborted.");
3946     return FALSE;
3947   }
3948 }
3949
3950 /*
3951  * Helper for gst_avi_demux_invert()
3952  */
3953 static inline void
3954 swap_line (guint8 * d1, guint8 * d2, guint8 * tmp, gint bytes)
3955 {
3956   memcpy (tmp, d1, bytes);
3957   memcpy (d1, d2, bytes);
3958   memcpy (d2, tmp, bytes);
3959 }
3960
3961
3962 #define gst_avi_demux_is_uncompressed(fourcc)           \
3963   (fourcc == GST_RIFF_DIB ||                            \
3964    fourcc == GST_RIFF_rgb ||                            \
3965    fourcc == GST_RIFF_RGB || fourcc == GST_RIFF_RAW)
3966
3967 /*
3968  * Invert DIB buffers... Takes existing buffer and
3969  * returns either the buffer or a new one (with old
3970  * one dereferenced).
3971  * FIXME: can't we preallocate tmp? and remember stride, bpp?
3972  */
3973 static GstBuffer *
3974 gst_avi_demux_invert (GstAviStream * stream, GstBuffer * buf)
3975 {
3976   GstStructure *s;
3977   gint y, w, h;
3978   gint bpp, stride;
3979   guint8 *tmp = NULL;
3980
3981   if (stream->strh->type != GST_RIFF_FCC_vids)
3982     return buf;
3983
3984   if (!gst_avi_demux_is_uncompressed (stream->strh->fcc_handler)) {
3985     return buf;                 /* Ignore non DIB buffers */
3986   }
3987
3988   s = gst_caps_get_structure (GST_PAD_CAPS (stream->pad), 0);
3989   if (!gst_structure_get_int (s, "bpp", &bpp)) {
3990     GST_WARNING ("Failed to retrieve depth from caps");
3991     return buf;
3992   }
3993
3994   if (stream->strf.vids == NULL) {
3995     GST_WARNING ("Failed to retrieve vids for stream");
3996     return buf;
3997   }
3998
3999   h = stream->strf.vids->height;
4000   w = stream->strf.vids->width;
4001   stride = w * (bpp / 8);
4002
4003   buf = gst_buffer_make_writable (buf);
4004   if (GST_BUFFER_SIZE (buf) < (stride * h)) {
4005     GST_WARNING ("Buffer is smaller than reported Width x Height x Depth");
4006     return buf;
4007   }
4008
4009   tmp = g_malloc (stride);
4010
4011   for (y = 0; y < h / 2; y++) {
4012     swap_line (GST_BUFFER_DATA (buf) + stride * y,
4013         GST_BUFFER_DATA (buf) + stride * (h - 1 - y), tmp, stride);
4014   }
4015
4016   g_free (tmp);
4017
4018   return buf;
4019 }
4020
4021 static void
4022 gst_avi_demux_add_assoc (GstAviDemux * avi, GstAviStream * stream,
4023     GstClockTime timestamp, guint64 offset, gboolean keyframe)
4024 {
4025   /* do not add indefinitely for open-ended streaming */
4026   if (G_UNLIKELY (avi->element_index && avi->seekable)) {
4027     GST_LOG_OBJECT (avi, "adding association %" GST_TIME_FORMAT "-> %"
4028         G_GUINT64_FORMAT, GST_TIME_ARGS (timestamp), offset);
4029     gst_index_add_association (avi->element_index, avi->index_id,
4030         keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT : GST_ASSOCIATION_FLAG_NONE,
4031         GST_FORMAT_TIME, timestamp, GST_FORMAT_BYTES, offset, NULL);
4032     /* well, current_total determines TIME and entry DEFAULT (frame #) ... */
4033     gst_index_add_association (avi->element_index, stream->index_id,
4034         GST_ASSOCIATION_FLAG_NONE,
4035         GST_FORMAT_TIME, stream->current_total, GST_FORMAT_BYTES, offset,
4036         GST_FORMAT_DEFAULT, stream->current_entry, NULL);
4037   }
4038 }
4039
4040 /*
4041  * Returns the aggregated GstFlowReturn.
4042  */
4043 static GstFlowReturn
4044 gst_avi_demux_combine_flows (GstAviDemux * avi, GstAviStream * stream,
4045     GstFlowReturn ret)
4046 {
4047   guint i;
4048   gboolean unexpected = FALSE, not_linked = TRUE;
4049
4050   /* store the value */
4051   stream->last_flow = ret;
4052
4053   /* any other error that is not-linked or eos can be returned right away */
4054   if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
4055     goto done;
4056
4057   /* only return NOT_LINKED if all other pads returned NOT_LINKED */
4058   for (i = 0; i < avi->num_streams; i++) {
4059     GstAviStream *ostream = &avi->stream[i];
4060
4061     ret = ostream->last_flow;
4062     /* no unexpected or unlinked, return */
4063     if (G_LIKELY (ret != GST_FLOW_UNEXPECTED && ret != GST_FLOW_NOT_LINKED))
4064       goto done;
4065
4066     /* we check to see if we have at least 1 unexpected or all unlinked */
4067     unexpected |= (ret == GST_FLOW_UNEXPECTED);
4068     not_linked &= (ret == GST_FLOW_NOT_LINKED);
4069   }
4070   /* when we get here, we all have unlinked or unexpected */
4071   if (not_linked)
4072     ret = GST_FLOW_NOT_LINKED;
4073   else if (unexpected)
4074     ret = GST_FLOW_UNEXPECTED;
4075 done:
4076   GST_LOG_OBJECT (avi, "combined %s to return %s",
4077       gst_flow_get_name (stream->last_flow), gst_flow_get_name (ret));
4078   return ret;
4079 }
4080
4081 /* move @stream to the next position in its index */
4082 static GstFlowReturn
4083 gst_avi_demux_advance (GstAviDemux * avi, GstAviStream * stream,
4084     GstFlowReturn ret)
4085 {
4086   guint old_entry, new_entry;
4087
4088   old_entry = stream->current_entry;
4089   /* move forwards */
4090   new_entry = old_entry + 1;
4091
4092   /* see if we reached the end */
4093   if (new_entry > stream->stop_entry) {
4094     if (avi->segment.rate < 0.0) {
4095       if (stream->step_entry == stream->start_entry) {
4096         /* we stepped all the way to the start, eos */
4097         GST_DEBUG_OBJECT (avi, "reverse reached start %u", stream->start_entry);
4098         goto eos;
4099       }
4100       /* backwards, stop becomes step, find a new step */
4101       stream->stop_entry = stream->step_entry;
4102       stream->step_entry = gst_avi_demux_index_prev (avi, stream,
4103           stream->stop_entry, TRUE);
4104
4105       GST_DEBUG_OBJECT (avi,
4106           "reverse playback jump: start %u, step %u, stop %u",
4107           stream->start_entry, stream->step_entry, stream->stop_entry);
4108
4109       /* and start from the previous keyframe now */
4110       new_entry = stream->step_entry;
4111     } else {
4112       /* EOS */
4113       GST_DEBUG_OBJECT (avi, "forward reached stop %u", stream->stop_entry);
4114       goto eos;
4115     }
4116   }
4117
4118   if (new_entry != old_entry) {
4119     stream->current_entry = new_entry;
4120     stream->current_total = stream->index[new_entry].total;
4121
4122     if (new_entry == old_entry + 1) {
4123       GST_DEBUG_OBJECT (avi, "moved forwards from %u to %u",
4124           old_entry, new_entry);
4125       /* we simply moved one step forwards, reuse current info */
4126       stream->current_timestamp = stream->current_ts_end;
4127       stream->current_offset = stream->current_offset_end;
4128       gst_avi_demux_get_buffer_info (avi, stream, new_entry,
4129           NULL, &stream->current_ts_end, NULL, &stream->current_offset_end);
4130     } else {
4131       /* we moved DISCONT, full update */
4132       gst_avi_demux_get_buffer_info (avi, stream, new_entry,
4133           &stream->current_timestamp, &stream->current_ts_end,
4134           &stream->current_offset, &stream->current_offset_end);
4135       /* and MARK discont for this stream */
4136       stream->last_flow = GST_FLOW_OK;
4137       stream->discont = TRUE;
4138       GST_DEBUG_OBJECT (avi, "Moved from %u to %u, ts %" GST_TIME_FORMAT
4139           ", ts_end %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
4140           ", off_end %" G_GUINT64_FORMAT, old_entry, new_entry,
4141           GST_TIME_ARGS (stream->current_timestamp),
4142           GST_TIME_ARGS (stream->current_ts_end), stream->current_offset,
4143           stream->current_offset_end);
4144     }
4145   }
4146   return ret;
4147
4148   /* ERROR */
4149 eos:
4150   {
4151     GST_DEBUG_OBJECT (avi, "we are EOS");
4152     /* setting current_timestamp to -1 marks EOS */
4153     stream->current_timestamp = -1;
4154     return GST_FLOW_UNEXPECTED;
4155   }
4156 }
4157
4158 /* find the stream with the lowest current position when going forwards or with
4159  * the highest position when going backwards, this is the stream
4160  * we should push from next */
4161 static gint
4162 gst_avi_demux_find_next (GstAviDemux * avi, gfloat rate)
4163 {
4164   guint64 min_time, max_time;
4165   guint stream_num, i;
4166
4167   max_time = 0;
4168   min_time = G_MAXUINT64;
4169   stream_num = -1;
4170
4171   for (i = 0; i < avi->num_streams; i++) {
4172     guint64 position;
4173     GstAviStream *stream;
4174
4175     stream = &avi->stream[i];
4176     position = stream->current_timestamp;
4177
4178     /* position of -1 is EOS */
4179     if (position != -1) {
4180       if (rate > 0.0 && position < min_time) {
4181         min_time = position;
4182         stream_num = i;
4183       } else if (rate < 0.0 && position >= max_time) {
4184         max_time = position;
4185         stream_num = i;
4186       }
4187     }
4188   }
4189   return stream_num;
4190 }
4191
4192 static GstFlowReturn
4193 gst_avi_demux_loop_data (GstAviDemux * avi)
4194 {
4195   GstFlowReturn ret = GST_FLOW_OK;
4196   guint stream_num;
4197   GstAviStream *stream;
4198   gboolean processed = FALSE;
4199   GstBuffer *buf;
4200   guint64 offset, size;
4201   GstClockTime timestamp, duration;
4202   guint64 out_offset, out_offset_end;
4203   gboolean keyframe;
4204   GstAviIndexEntry *entry;
4205
4206   do {
4207     stream_num = gst_avi_demux_find_next (avi, avi->segment.rate);
4208
4209     /* all are EOS */
4210     if (G_UNLIKELY (stream_num == -1)) {
4211       GST_DEBUG_OBJECT (avi, "all streams are EOS");
4212       goto eos;
4213     }
4214
4215     /* we have the stream now */
4216     stream = &avi->stream[stream_num];
4217
4218     /* skip streams without pads */
4219     if (!stream->pad) {
4220       GST_DEBUG_OBJECT (avi, "skipping entry from stream %d without pad",
4221           stream_num);
4222       goto next;
4223     }
4224
4225     /* get the timing info for the entry */
4226     timestamp = stream->current_timestamp;
4227     duration = stream->current_ts_end - timestamp;
4228     out_offset = stream->current_offset;
4229     out_offset_end = stream->current_offset_end;
4230
4231     /* get the entry data info */
4232     entry = &stream->index[stream->current_entry];
4233     offset = entry->offset;
4234     size = entry->size;
4235     keyframe = ENTRY_IS_KEYFRAME (entry);
4236
4237     /* skip empty entries */
4238     if (size == 0) {
4239       GST_DEBUG_OBJECT (avi, "Skipping entry %u (%" G_GUINT64_FORMAT ", %p)",
4240           stream->current_entry, size, stream->pad);
4241       goto next;
4242     }
4243
4244     if (avi->segment.rate > 0.0) {
4245       /* only check this for fowards playback for now */
4246       if (keyframe && GST_CLOCK_TIME_IS_VALID (avi->segment.stop)
4247           && (timestamp > avi->segment.stop)) {
4248         goto eos_stop;
4249       }
4250     }
4251
4252     GST_LOG ("reading buffer (size=%" G_GUINT64_FORMAT "), stream %d, pos %"
4253         G_GUINT64_FORMAT " (0x%" G_GINT64_MODIFIER "x), kf %d", size,
4254         stream_num, offset, offset, keyframe);
4255
4256     /* FIXME, check large chunks and cut them up */
4257
4258     /* pull in the data */
4259     ret = gst_pad_pull_range (avi->sinkpad, offset, size, &buf);
4260     if (ret != GST_FLOW_OK)
4261       goto pull_failed;
4262
4263     /* check for short buffers, this is EOS as well */
4264     if (GST_BUFFER_SIZE (buf) < size)
4265       goto short_buffer;
4266
4267     /* invert the picture if needed */
4268     buf = gst_avi_demux_invert (stream, buf);
4269
4270     /* mark non-keyframes */
4271     if (keyframe)
4272       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4273     else
4274       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
4275
4276     GST_BUFFER_TIMESTAMP (buf) = timestamp;
4277     GST_BUFFER_DURATION (buf) = duration;
4278     GST_BUFFER_OFFSET (buf) = out_offset;
4279     GST_BUFFER_OFFSET_END (buf) = out_offset_end;
4280
4281     /* mark discont when pending */
4282     if (stream->discont) {
4283       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4284       stream->discont = FALSE;
4285     }
4286
4287     gst_avi_demux_add_assoc (avi, stream, timestamp, offset, keyframe);
4288
4289     gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad));
4290
4291     /* update current position in the segment */
4292     gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, timestamp);
4293
4294     GST_DEBUG_OBJECT (avi, "Pushing buffer of size %u, ts %"
4295         GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
4296         ", off_end %" G_GUINT64_FORMAT,
4297         GST_BUFFER_SIZE (buf), GST_TIME_ARGS (timestamp),
4298         GST_TIME_ARGS (duration), out_offset, out_offset_end);
4299
4300     ret = gst_pad_push (stream->pad, buf);
4301
4302     /* mark as processed, we increment the frame and byte counters then
4303      * leave the while loop and return the GstFlowReturn */
4304     processed = TRUE;
4305
4306     if (avi->segment.rate < 0) {
4307       if (timestamp > avi->segment.stop && ret == GST_FLOW_UNEXPECTED) {
4308         /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
4309          * we are at the end of the segment, so we just need to jump
4310          * back to the previous section. */
4311         GST_DEBUG_OBJECT (avi, "downstream has reached end of segment");
4312         ret = GST_FLOW_OK;
4313       }
4314     }
4315   next:
4316     /* move to next item */
4317     ret = gst_avi_demux_advance (avi, stream, ret);
4318
4319     /* combine flows */
4320     ret = gst_avi_demux_combine_flows (avi, stream, ret);
4321   } while (!processed);
4322
4323 beach:
4324   return ret;
4325
4326   /* special cases */
4327 eos:
4328   {
4329     GST_DEBUG_OBJECT (avi, "No samples left for any streams - EOS");
4330     ret = GST_FLOW_UNEXPECTED;
4331     goto beach;
4332   }
4333 eos_stop:
4334   {
4335     GST_LOG_OBJECT (avi, "Found keyframe after segment,"
4336         " setting EOS (%" GST_TIME_FORMAT " > %" GST_TIME_FORMAT ")",
4337         GST_TIME_ARGS (timestamp), GST_TIME_ARGS (avi->segment.stop));
4338     ret = GST_FLOW_UNEXPECTED;
4339     goto beach;
4340   }
4341 pull_failed:
4342   {
4343     GST_DEBUG_OBJECT (avi, "pull range failed: pos=%" G_GUINT64_FORMAT
4344         " size=%" G_GUINT64_FORMAT, offset, size);
4345     goto beach;
4346   }
4347 short_buffer:
4348   {
4349     GST_WARNING_OBJECT (avi, "Short read at offset %" G_GUINT64_FORMAT
4350         ", only got %d/%" G_GUINT64_FORMAT " bytes (truncated file?)", offset,
4351         GST_BUFFER_SIZE (buf), size);
4352     gst_buffer_unref (buf);
4353     ret = GST_FLOW_UNEXPECTED;
4354     goto beach;
4355   }
4356 }
4357
4358 /*
4359  * Read data. If we have an index it delegates to
4360  * gst_avi_demux_process_next_entry().
4361  */
4362 static GstFlowReturn
4363 gst_avi_demux_stream_data (GstAviDemux * avi)
4364 {
4365   guint32 tag = 0;
4366   guint32 size = 0;
4367   gint stream_nr = 0;
4368   GstFlowReturn res = GST_FLOW_OK;
4369   GstFormat format = GST_FORMAT_TIME;
4370
4371   if (G_UNLIKELY (avi->have_eos)) {
4372     /* Clean adapter, we're done */
4373     gst_adapter_clear (avi->adapter);
4374     return GST_FLOW_UNEXPECTED;
4375   }
4376
4377   if (G_UNLIKELY (avi->todrop)) {
4378     guint drop;
4379
4380     if ((drop = gst_adapter_available (avi->adapter))) {
4381       if (drop > avi->todrop)
4382         drop = avi->todrop;
4383       GST_DEBUG_OBJECT (avi, "Dropping %d bytes", drop);
4384       gst_adapter_flush (avi->adapter, drop);
4385       avi->todrop -= drop;
4386       avi->offset += drop;
4387     }
4388   }
4389
4390   /* Iterate until need more data, so adapter won't grow too much */
4391   while (1) {
4392     if (G_UNLIKELY (!gst_avi_demux_peek_chunk_info (avi, &tag, &size))) {
4393       return GST_FLOW_OK;
4394     }
4395
4396     GST_DEBUG ("Trying chunk (%" GST_FOURCC_FORMAT "), size %d",
4397         GST_FOURCC_ARGS (tag), size);
4398
4399     if (G_LIKELY ((tag & 0xff) >= '0' && (tag & 0xff) <= '9' &&
4400             ((tag >> 8) & 0xff) >= '0' && ((tag >> 8) & 0xff) <= '9')) {
4401       GST_LOG ("Chunk ok");
4402     } else if ((tag & 0xffff) == (('x' << 8) | 'i')) {
4403       GST_DEBUG ("Found sub-index tag");
4404       if (gst_avi_demux_peek_chunk (avi, &tag, &size) || size == 0) {
4405         /* accept 0 size buffer here */
4406         avi->abort_buffering = FALSE;
4407         GST_DEBUG ("  skipping %d bytes for now", size);
4408         gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
4409       }
4410       return GST_FLOW_OK;
4411     } else if (tag == GST_RIFF_TAG_idx1) {
4412       GST_DEBUG ("Found index tag, stream done");
4413       avi->have_eos = TRUE;
4414       return GST_FLOW_UNEXPECTED;
4415     } else if (tag == GST_RIFF_TAG_LIST) {
4416       /* movi chunks might be grouped in rec list */
4417       if (gst_adapter_available (avi->adapter) >= 12) {
4418         GST_DEBUG ("Found LIST tag, skipping LIST header");
4419         gst_adapter_flush (avi->adapter, 12);
4420         continue;
4421       }
4422       return GST_FLOW_OK;
4423     } else if (tag == GST_RIFF_TAG_JUNK) {
4424       /* rec list might contain JUNK chunks */
4425       GST_DEBUG ("Found JUNK tag");
4426       if (gst_avi_demux_peek_chunk (avi, &tag, &size) || size == 0) {
4427         /* accept 0 size buffer here */
4428         avi->abort_buffering = FALSE;
4429         GST_DEBUG ("  skipping %d bytes for now", size);
4430         gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
4431       }
4432       return GST_FLOW_OK;
4433     } else {
4434       GST_DEBUG ("No more stream chunks, send EOS");
4435       avi->have_eos = TRUE;
4436       return GST_FLOW_UNEXPECTED;
4437     }
4438
4439     if (G_UNLIKELY (!gst_avi_demux_peek_chunk (avi, &tag, &size))) {
4440       /* supposedly one hopes to catch a nicer chunk later on ... */
4441       /* FIXME ?? give up here rather than possibly ending up going
4442        * through the whole file */
4443       if (avi->abort_buffering) {
4444         avi->abort_buffering = FALSE;
4445         gst_adapter_flush (avi->adapter, 8);
4446       }
4447       return GST_FLOW_OK;
4448     }
4449     GST_DEBUG ("chunk ID %" GST_FOURCC_FORMAT ", size %u",
4450         GST_FOURCC_ARGS (tag), size);
4451
4452     stream_nr = CHUNKID_TO_STREAMNR (tag);
4453
4454     if (G_UNLIKELY (stream_nr < 0 || stream_nr >= avi->num_streams)) {
4455       /* recoverable */
4456       GST_WARNING ("Invalid stream ID %d (%" GST_FOURCC_FORMAT ")",
4457           stream_nr, GST_FOURCC_ARGS (tag));
4458       avi->offset += 8 + GST_ROUND_UP_2 (size);
4459       gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
4460     } else {
4461       GstAviStream *stream;
4462       GstClockTime next_ts = 0;
4463       GstBuffer *buf;
4464       guint64 offset;
4465
4466       gst_adapter_flush (avi->adapter, 8);
4467
4468       /* get buffer */
4469       buf = gst_adapter_take_buffer (avi->adapter, GST_ROUND_UP_2 (size));
4470       /* patch the size */
4471       GST_BUFFER_SIZE (buf) = size;
4472       offset = avi->offset;
4473       avi->offset += 8 + GST_ROUND_UP_2 (size);
4474
4475       stream = &avi->stream[stream_nr];
4476
4477       /* set delay (if any)
4478          if (stream->strh->init_frames == stream->current_frame &&
4479          stream->delay == 0)
4480          stream->delay = next_ts;
4481        */
4482
4483       /* parsing of corresponding header may have failed */
4484       if (G_UNLIKELY (!stream->pad)) {
4485         GST_WARNING_OBJECT (avi, "no pad for stream ID %" GST_FOURCC_FORMAT,
4486             GST_FOURCC_ARGS (tag));
4487         gst_buffer_unref (buf);
4488       } else {
4489         GstClockTime dur_ts = 0;
4490
4491         /* get time of this buffer */
4492         gst_pad_query_position (stream->pad, &format, (gint64 *) & next_ts);
4493         if (G_UNLIKELY (format != GST_FORMAT_TIME))
4494           goto wrong_format;
4495
4496         gst_avi_demux_add_assoc (avi, stream, next_ts, offset, FALSE);
4497
4498         /* increment our positions */
4499         stream->current_entry++;
4500         stream->current_total += size;
4501
4502         /* invert the picture if needed */
4503         buf = gst_avi_demux_invert (stream, buf);
4504
4505         gst_pad_query_position (stream->pad, &format, (gint64 *) & dur_ts);
4506         if (G_UNLIKELY (format != GST_FORMAT_TIME))
4507           goto wrong_format;
4508
4509         GST_BUFFER_TIMESTAMP (buf) = next_ts;
4510         GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
4511         if (stream->strh->type == GST_RIFF_FCC_vids) {
4512           GST_BUFFER_OFFSET (buf) = stream->current_entry - 1;
4513           GST_BUFFER_OFFSET_END (buf) = stream->current_entry;
4514         } else {
4515           GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
4516           GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
4517         }
4518
4519         gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad));
4520         GST_DEBUG_OBJECT (avi,
4521             "Pushing buffer with time=%" GST_TIME_FORMAT ", duration %"
4522             GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
4523             " and size %d over pad %s", GST_TIME_ARGS (next_ts),
4524             GST_TIME_ARGS (GST_BUFFER_DURATION (buf)), GST_BUFFER_OFFSET (buf),
4525             size, GST_PAD_NAME (stream->pad));
4526
4527         /* update current position in the segment */
4528         gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, next_ts);
4529
4530         /* mark discont when pending */
4531         if (G_UNLIKELY (stream->discont)) {
4532           GST_DEBUG_OBJECT (avi, "Setting DISCONT");
4533           GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
4534           stream->discont = FALSE;
4535         }
4536         res = gst_pad_push (stream->pad, buf);
4537
4538         /* combine flows */
4539         res = gst_avi_demux_combine_flows (avi, stream, res);
4540         if (G_UNLIKELY (res != GST_FLOW_OK)) {
4541           GST_DEBUG ("Push failed; %s", gst_flow_get_name (res));
4542           return res;
4543         }
4544       }
4545     }
4546   }
4547
4548 done:
4549   return res;
4550
4551   /* ERRORS */
4552 wrong_format:
4553   {
4554     GST_DEBUG_OBJECT (avi, "format %s != GST_FORMAT_TIME",
4555         gst_format_get_name (format));
4556     res = GST_FLOW_ERROR;
4557     goto done;
4558   }
4559 }
4560
4561 /*
4562  * Send pending tags.
4563  */
4564 static void
4565 push_tag_lists (GstAviDemux * avi)
4566 {
4567   guint i;
4568   GstTagList *tags;
4569
4570   if (!avi->got_tags)
4571     return;
4572
4573   GST_DEBUG_OBJECT (avi, "Pushing pending tag lists");
4574
4575   for (i = 0; i < avi->num_streams; i++) {
4576     GstAviStream *stream = &avi->stream[i];
4577     GstPad *pad = stream->pad;
4578
4579     tags = stream->taglist;
4580
4581     if (pad && tags) {
4582       GST_DEBUG_OBJECT (pad, "Tags: %" GST_PTR_FORMAT, tags);
4583
4584       gst_element_found_tags_for_pad (GST_ELEMENT_CAST (avi), pad, tags);
4585       stream->taglist = NULL;
4586     }
4587   }
4588
4589   if (!(tags = avi->globaltags))
4590     tags = gst_tag_list_new ();
4591
4592   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
4593       GST_TAG_CONTAINER_FORMAT, "AVI", NULL);
4594
4595   GST_DEBUG_OBJECT (avi, "Global tags: %" GST_PTR_FORMAT, tags);
4596   gst_element_found_tags (GST_ELEMENT_CAST (avi), tags);
4597   avi->globaltags = NULL;
4598   avi->got_tags = FALSE;
4599 }
4600
4601 static void
4602 gst_avi_demux_loop (GstPad * pad)
4603 {
4604   GstFlowReturn res;
4605   GstAviDemux *avi = GST_AVI_DEMUX (GST_PAD_PARENT (pad));
4606
4607   switch (avi->state) {
4608     case GST_AVI_DEMUX_START:
4609       res = gst_avi_demux_stream_init_pull (avi);
4610       if (G_UNLIKELY (res != GST_FLOW_OK)) {
4611         GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res));
4612         goto pause;
4613       }
4614       avi->state = GST_AVI_DEMUX_HEADER;
4615       /* fall-through */
4616     case GST_AVI_DEMUX_HEADER:
4617       res = gst_avi_demux_stream_header_pull (avi);
4618       if (G_UNLIKELY (res != GST_FLOW_OK)) {
4619         GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res));
4620         goto pause;
4621       }
4622       avi->state = GST_AVI_DEMUX_MOVI;
4623       break;
4624     case GST_AVI_DEMUX_MOVI:
4625       if (G_UNLIKELY (avi->seek_event)) {
4626         gst_avi_demux_push_event (avi, avi->seek_event);
4627         avi->seek_event = NULL;
4628       }
4629       if (G_UNLIKELY (avi->got_tags)) {
4630         push_tag_lists (avi);
4631       }
4632       /* process each index entry in turn */
4633       res = gst_avi_demux_loop_data (avi);
4634
4635       /* pause when error */
4636       if (G_UNLIKELY (res != GST_FLOW_OK)) {
4637         GST_INFO ("stream_movi flow: %s", gst_flow_get_name (res));
4638         goto pause;
4639       }
4640       break;
4641     default:
4642       GST_ERROR_OBJECT (avi, "unknown state %d", avi->state);
4643       res = GST_FLOW_ERROR;
4644       goto pause;
4645   }
4646
4647   return;
4648
4649   /* ERRORS */
4650 pause:
4651   GST_LOG_OBJECT (avi, "pausing task, reason %s", gst_flow_get_name (res));
4652   avi->segment_running = FALSE;
4653   gst_pad_pause_task (avi->sinkpad);
4654
4655   if (GST_FLOW_IS_FATAL (res) || (res == GST_FLOW_NOT_LINKED)) {
4656     gboolean push_eos = TRUE;
4657
4658     if (res == GST_FLOW_UNEXPECTED) {
4659       /* handle end-of-stream/segment */
4660       if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4661         gint64 stop;
4662
4663         if ((stop = avi->segment.stop) == -1)
4664           stop = avi->segment.duration;
4665
4666         GST_INFO_OBJECT (avi, "sending segment_done");
4667
4668         gst_element_post_message
4669             (GST_ELEMENT (avi),
4670             gst_message_new_segment_done (GST_OBJECT (avi), GST_FORMAT_TIME,
4671                 stop));
4672         push_eos = FALSE;
4673       }
4674     } else {
4675       /* for fatal errors we post an error message */
4676       GST_ELEMENT_ERROR (avi, STREAM, FAILED,
4677           (_("Internal data stream error.")),
4678           ("streaming stopped, reason %s", gst_flow_get_name (res)));
4679     }
4680     if (push_eos) {
4681       GST_INFO_OBJECT (avi, "sending eos");
4682       if (!gst_avi_demux_push_event (avi, gst_event_new_eos ()) &&
4683           (res == GST_FLOW_UNEXPECTED)) {
4684         GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
4685             (NULL), ("got eos but no streams (yet)"));
4686       }
4687     }
4688   }
4689 }
4690
4691
4692 static GstFlowReturn
4693 gst_avi_demux_chain (GstPad * pad, GstBuffer * buf)
4694 {
4695   GstFlowReturn res;
4696   GstAviDemux *avi = GST_AVI_DEMUX (GST_PAD_PARENT (pad));
4697
4698   GST_DEBUG ("Store %d bytes in adapter", GST_BUFFER_SIZE (buf));
4699   gst_adapter_push (avi->adapter, buf);
4700
4701   switch (avi->state) {
4702     case GST_AVI_DEMUX_START:
4703       if ((res = gst_avi_demux_stream_init_push (avi)) != GST_FLOW_OK) {
4704         GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res));
4705         break;
4706       }
4707       break;
4708     case GST_AVI_DEMUX_HEADER:
4709       if ((res = gst_avi_demux_stream_header_push (avi)) != GST_FLOW_OK) {
4710         GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res));
4711         break;
4712       }
4713       break;
4714     case GST_AVI_DEMUX_MOVI:
4715       if (G_UNLIKELY (avi->seek_event)) {
4716         gst_avi_demux_push_event (avi, avi->seek_event);
4717         avi->seek_event = NULL;
4718       }
4719       if (G_UNLIKELY (avi->got_tags)) {
4720         push_tag_lists (avi);
4721       }
4722       res = gst_avi_demux_stream_data (avi);
4723       break;
4724     default:
4725       GST_ELEMENT_ERROR (avi, STREAM, FAILED, (NULL),
4726           ("Illegal internal state"));
4727       res = GST_FLOW_ERROR;
4728       break;
4729   }
4730
4731   GST_DEBUG_OBJECT (avi, "state: %d res:%s", avi->state,
4732       gst_flow_get_name (res));
4733
4734   if (G_UNLIKELY (avi->abort_buffering)) {
4735     avi->abort_buffering = FALSE;
4736     res = GST_FLOW_ERROR;
4737     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("unhandled buffer size"));
4738   }
4739
4740   return res;
4741 }
4742
4743 static gboolean
4744 gst_avi_demux_sink_activate (GstPad * sinkpad)
4745 {
4746   if (gst_pad_check_pull_range (sinkpad)) {
4747     GST_DEBUG ("going to pull mode");
4748     return gst_pad_activate_pull (sinkpad, TRUE);
4749   } else {
4750     GST_DEBUG ("going to push (streaming) mode");
4751     return gst_pad_activate_push (sinkpad, TRUE);
4752   }
4753 }
4754
4755 static gboolean
4756 gst_avi_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
4757 {
4758   GstAviDemux *avi = GST_AVI_DEMUX (GST_OBJECT_PARENT (sinkpad));
4759
4760   if (active) {
4761     avi->segment_running = TRUE;
4762     avi->streaming = FALSE;
4763     return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_avi_demux_loop,
4764         sinkpad);
4765   } else {
4766     avi->segment_running = FALSE;
4767     return gst_pad_stop_task (sinkpad);
4768   }
4769 }
4770
4771 static gboolean
4772 gst_avi_demux_activate_push (GstPad * pad, gboolean active)
4773 {
4774   GstAviDemux *avi = GST_AVI_DEMUX (GST_OBJECT_PARENT (pad));
4775
4776   if (active) {
4777     GST_DEBUG ("avi: activating push/chain function");
4778     avi->streaming = TRUE;
4779 #if 0
4780     /* create index for some push based seeking if not provided */
4781     GST_OBJECT_LOCK (avi);
4782     if (!avi->element_index) {
4783       GST_DEBUG_OBJECT (avi, "creating index");
4784       avi->element_index = gst_index_factory_make ("memindex");
4785     }
4786     GST_OBJECT_UNLOCK (avi);
4787     /* object lock might be taken again */
4788     gst_index_get_writer_id (avi->element_index, GST_OBJECT (avi),
4789         &avi->index_id);
4790 #endif
4791   } else {
4792     GST_DEBUG ("avi: deactivating push/chain function");
4793   }
4794
4795   return TRUE;
4796 }
4797
4798 static void
4799 gst_avi_demux_set_index (GstElement * element, GstIndex * index)
4800 {
4801   GstAviDemux *avi = GST_AVI_DEMUX (element);
4802
4803   GST_OBJECT_LOCK (avi);
4804   if (avi->element_index)
4805     gst_object_unref (avi->element_index);
4806   if (index) {
4807     avi->element_index = gst_object_ref (index);
4808   } else {
4809     avi->element_index = NULL;
4810   }
4811   GST_OBJECT_UNLOCK (avi);
4812   /* object lock might be taken again */
4813   if (index)
4814     gst_index_get_writer_id (index, GST_OBJECT (element), &avi->index_id);
4815   GST_DEBUG_OBJECT (avi, "Set index %" GST_PTR_FORMAT, avi->element_index);
4816 }
4817
4818 static GstIndex *
4819 gst_avi_demux_get_index (GstElement * element)
4820 {
4821   GstIndex *result = NULL;
4822   GstAviDemux *avi = GST_AVI_DEMUX (element);
4823
4824   GST_OBJECT_LOCK (avi);
4825   if (avi->element_index)
4826     result = gst_object_ref (avi->element_index);
4827   GST_OBJECT_UNLOCK (avi);
4828
4829   GST_DEBUG_OBJECT (avi, "Returning index %" GST_PTR_FORMAT, result);
4830
4831   return result;
4832 }
4833
4834 static GstStateChangeReturn
4835 gst_avi_demux_change_state (GstElement * element, GstStateChange transition)
4836 {
4837   GstStateChangeReturn ret;
4838   GstAviDemux *avi = GST_AVI_DEMUX (element);
4839
4840   switch (transition) {
4841     case GST_STATE_CHANGE_READY_TO_PAUSED:
4842       avi->streaming = FALSE;
4843       gst_segment_init (&avi->segment, GST_FORMAT_TIME);
4844       break;
4845     default:
4846       break;
4847   }
4848
4849   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4850   if (ret == GST_STATE_CHANGE_FAILURE)
4851     goto done;
4852
4853   switch (transition) {
4854     case GST_STATE_CHANGE_PAUSED_TO_READY:
4855       gst_avi_demux_reset (avi);
4856       break;
4857     default:
4858       break;
4859   }
4860
4861 done:
4862   return ret;
4863 }