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