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