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