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