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