avi: add support for ODML indexes again
[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 GST_DEBUG_CATEGORY_STATIC (GST_CAT_PERFORMANCE);
61
62 GST_DEBUG_CATEGORY_EXTERN (GST_CAT_EVENT);
63
64 static GstStaticPadTemplate sink_templ = GST_STATIC_PAD_TEMPLATE ("sink",
65     GST_PAD_SINK,
66     GST_PAD_ALWAYS,
67     GST_STATIC_CAPS ("video/x-msvideo")
68     );
69
70 static void gst_avi_demux_base_init (GstAviDemuxClass * klass);
71 static void gst_avi_demux_class_init (GstAviDemuxClass * klass);
72 static void gst_avi_demux_init (GstAviDemux * avi);
73 static void gst_avi_demux_finalize (GObject * object);
74
75 static void gst_avi_demux_reset (GstAviDemux * avi);
76
77 #if 0
78 static const GstEventMask *gst_avi_demux_get_event_mask (GstPad * pad);
79 #endif
80 static gboolean gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event);
81 static gboolean gst_avi_demux_handle_sink_event (GstPad * pad,
82     GstEvent * event);
83 static gboolean gst_avi_demux_push_event (GstAviDemux * avi, GstEvent * event);
84
85 #if 0
86 static const GstFormat *gst_avi_demux_get_src_formats (GstPad * pad);
87 #endif
88 static const GstQueryType *gst_avi_demux_get_src_query_types (GstPad * pad);
89 static gboolean gst_avi_demux_handle_src_query (GstPad * pad, GstQuery * query);
90 static gboolean gst_avi_demux_src_convert (GstPad * pad, GstFormat src_format,
91     gint64 src_value, GstFormat * dest_format, gint64 * dest_value);
92
93 static gboolean gst_avi_demux_do_seek (GstAviDemux * avi, GstSegment * segment);
94 static gboolean gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad,
95     GstEvent * event);
96 static void gst_avi_demux_loop (GstPad * pad);
97 static gboolean gst_avi_demux_sink_activate (GstPad * sinkpad);
98 static gboolean gst_avi_demux_sink_activate_pull (GstPad * sinkpad,
99     gboolean active);
100 static gboolean gst_avi_demux_activate_push (GstPad * pad, gboolean active);
101 static GstFlowReturn gst_avi_demux_chain (GstPad * pad, GstBuffer * buf);
102
103 static GstStateChangeReturn gst_avi_demux_change_state (GstElement * element,
104     GstStateChange transition);
105
106 static GstElementClass *parent_class = NULL;
107
108 /* GObject methods */
109
110 GType
111 gst_avi_demux_get_type (void)
112 {
113   static GType avi_demux_type = 0;
114
115   if (!avi_demux_type) {
116     static const GTypeInfo avi_demux_info = {
117       sizeof (GstAviDemuxClass),
118       (GBaseInitFunc) gst_avi_demux_base_init,
119       NULL,
120       (GClassInitFunc) gst_avi_demux_class_init,
121       NULL,
122       NULL,
123       sizeof (GstAviDemux),
124       0,
125       (GInstanceInitFunc) gst_avi_demux_init,
126     };
127
128     avi_demux_type =
129         g_type_register_static (GST_TYPE_ELEMENT,
130         "GstAviDemux", &avi_demux_info, 0);
131   }
132
133   return avi_demux_type;
134 }
135
136 static void
137 gst_avi_demux_base_init (GstAviDemuxClass * klass)
138 {
139   static const GstElementDetails gst_avi_demux_details =
140       GST_ELEMENT_DETAILS ("Avi demuxer",
141       "Codec/Demuxer",
142       "Demultiplex an avi file into audio and video",
143       "Erik Walthinsen <omega@cse.ogi.edu>\n"
144       "Wim Taymans <wim.taymans@chello.be>\n"
145       "Thijs Vermeir <thijsvermeir@gmail.com>");
146   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
147   GstPadTemplate *videosrctempl, *audiosrctempl, *subsrctempl;
148   GstCaps *audcaps, *vidcaps, *subcaps;
149
150   audcaps = gst_riff_create_audio_template_caps ();
151   gst_caps_append (audcaps, gst_caps_new_simple ("audio/x-avi-unknown", NULL));
152   audiosrctempl = gst_pad_template_new ("audio_%02d",
153       GST_PAD_SRC, GST_PAD_SOMETIMES, audcaps);
154
155   vidcaps = gst_riff_create_video_template_caps ();
156   gst_caps_append (vidcaps, gst_riff_create_iavs_template_caps ());
157   gst_caps_append (vidcaps, gst_caps_new_simple ("video/x-avi-unknown", NULL));
158   videosrctempl = gst_pad_template_new ("video_%02d",
159       GST_PAD_SRC, GST_PAD_SOMETIMES, vidcaps);
160
161   subcaps = gst_caps_new_simple ("application/x-subtitle-avi", NULL);
162   subsrctempl = gst_pad_template_new ("subtitle_%02d",
163       GST_PAD_SRC, GST_PAD_SOMETIMES, subcaps);
164   gst_element_class_add_pad_template (element_class, audiosrctempl);
165   gst_element_class_add_pad_template (element_class, videosrctempl);
166   gst_element_class_add_pad_template (element_class, subsrctempl);
167   gst_element_class_add_pad_template (element_class,
168       gst_static_pad_template_get (&sink_templ));
169   gst_element_class_set_details (element_class, &gst_avi_demux_details);
170 }
171
172 static void
173 gst_avi_demux_class_init (GstAviDemuxClass * klass)
174 {
175   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
176   GObjectClass *gobject_class = (GObjectClass *) klass;
177
178   GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux",
179       0, "Demuxer for AVI streams");
180   GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
181
182   parent_class = g_type_class_peek_parent (klass);
183
184   gobject_class->finalize = gst_avi_demux_finalize;
185   gstelement_class->change_state =
186       GST_DEBUG_FUNCPTR (gst_avi_demux_change_state);
187 }
188
189 static void
190 gst_avi_demux_init (GstAviDemux * avi)
191 {
192   avi->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
193   gst_pad_set_activate_function (avi->sinkpad,
194       GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate));
195   gst_pad_set_activatepull_function (avi->sinkpad,
196       GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate_pull));
197   gst_pad_set_activatepush_function (avi->sinkpad,
198       GST_DEBUG_FUNCPTR (gst_avi_demux_activate_push));
199   gst_pad_set_chain_function (avi->sinkpad,
200       GST_DEBUG_FUNCPTR (gst_avi_demux_chain));
201   gst_pad_set_event_function (avi->sinkpad,
202       GST_DEBUG_FUNCPTR (gst_avi_demux_handle_sink_event));
203   gst_element_add_pad (GST_ELEMENT (avi), avi->sinkpad);
204
205   avi->adapter = gst_adapter_new ();
206
207   gst_avi_demux_reset (avi);
208 }
209
210 static void
211 gst_avi_demux_finalize (GObject * object)
212 {
213   GstAviDemux *avi = GST_AVI_DEMUX (object);
214
215   GST_DEBUG ("AVI: finalize");
216
217   g_object_unref (avi->adapter);
218
219   G_OBJECT_CLASS (parent_class)->finalize (object);
220 }
221
222 static void
223 gst_avi_demux_reset_stream (GstAviDemux * avi, GstAviStream * stream)
224 {
225   g_free (stream->strh);
226   g_free (stream->strf.data);
227   g_free (stream->name);
228   g_free (stream->index);
229   g_free (stream->indexes);
230   if (stream->initdata)
231     gst_buffer_unref (stream->initdata);
232   if (stream->extradata)
233     gst_buffer_unref (stream->extradata);
234   if (stream->pad) {
235     gst_pad_set_active (stream->pad, FALSE);
236     gst_element_remove_pad (GST_ELEMENT (avi), stream->pad);
237   }
238   if (stream->taglist) {
239     gst_tag_list_free (stream->taglist);
240     stream->taglist = NULL;
241   }
242   memset (stream, 0, sizeof (GstAviStream));
243 }
244
245 static void
246 gst_avi_demux_reset (GstAviDemux * avi)
247 {
248   gint i;
249
250   GST_DEBUG ("AVI: reset");
251
252   for (i = 0; i < avi->num_streams; i++)
253     gst_avi_demux_reset_stream (avi, &avi->stream[i]);
254
255   avi->header_state = GST_AVI_DEMUX_HEADER_TAG_LIST;
256   avi->num_streams = 0;
257   avi->num_v_streams = 0;
258   avi->num_a_streams = 0;
259   avi->num_t_streams = 0;
260
261   avi->state = GST_AVI_DEMUX_START;
262   avi->offset = 0;
263
264   avi->index_offset = 0;
265   g_free (avi->avih);
266   avi->avih = NULL;
267
268   if (avi->seek_event) {
269     gst_event_unref (avi->seek_event);
270     avi->seek_event = NULL;
271   }
272
273   if (avi->globaltags)
274     gst_tag_list_free (avi->globaltags);
275   avi->globaltags = NULL;
276
277   avi->got_tags = TRUE;         /* we always want to push global tags */
278   avi->have_eos = FALSE;
279
280   gst_adapter_clear (avi->adapter);
281
282   gst_segment_init (&avi->segment, GST_FORMAT_TIME);
283 }
284
285
286 /* GstElement methods */
287
288 #if 0
289 static const GstFormat *
290 gst_avi_demux_get_src_formats (GstPad * pad)
291 {
292   GstAviStream *stream = gst_pad_get_element_private (pad);
293
294   static const GstFormat src_a_formats[] = {
295     GST_FORMAT_TIME,
296     GST_FORMAT_BYTES,
297     GST_FORMAT_DEFAULT,
298     0
299   };
300   static const GstFormat src_v_formats[] = {
301     GST_FORMAT_TIME,
302     GST_FORMAT_DEFAULT,
303     0
304   };
305
306   return (stream->strh->type == GST_RIFF_FCC_auds ?
307       src_a_formats : src_v_formats);
308 }
309 #endif
310
311 /* assumes stream->strf.auds->av_bps != 0 */
312 static inline GstClockTime
313 avi_stream_convert_bytes_to_time_unchecked (GstAviStream * stream,
314     guint64 bytes)
315 {
316   return gst_util_uint64_scale_int (bytes, GST_SECOND,
317       stream->strf.auds->av_bps);
318 }
319
320 static inline guint64
321 avi_stream_convert_time_to_bytes_unchecked (GstAviStream * stream,
322     GstClockTime time)
323 {
324   return gst_util_uint64_scale_int (time, stream->strf.auds->av_bps,
325       GST_SECOND);
326 }
327
328 /* assumes stream->strh->rate != 0 */
329 static inline GstClockTime
330 avi_stream_convert_frames_to_time_unchecked (GstAviStream * stream,
331     guint64 frames)
332 {
333   return gst_util_uint64_scale (frames, stream->strh->scale * GST_SECOND,
334       stream->strh->rate);
335 }
336
337 static inline guint64
338 avi_stream_convert_time_to_frames_unchecked (GstAviStream * stream,
339     GstClockTime time)
340 {
341   return gst_util_uint64_scale (time, stream->strh->rate,
342       stream->strh->scale * GST_SECOND);
343 }
344
345 static gboolean
346 gst_avi_demux_src_convert (GstPad * pad,
347     GstFormat src_format,
348     gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
349 {
350   GstAviStream *stream = gst_pad_get_element_private (pad);
351   gboolean res = TRUE;
352
353   GST_LOG_OBJECT (pad,
354       "Received  src_format:%s, src_value:%" G_GUINT64_FORMAT
355       ", dest_format:%s", gst_format_get_name (src_format), src_value,
356       gst_format_get_name (*dest_format));
357
358   if (G_UNLIKELY (src_format == *dest_format)) {
359     *dest_value = src_value;
360     goto done;
361   }
362   if (G_UNLIKELY (!stream->strh || !stream->strf.data)) {
363     res = FALSE;
364     goto done;
365   }
366   if (G_UNLIKELY (stream->strh->type == GST_RIFF_FCC_vids &&
367           (src_format == GST_FORMAT_BYTES
368               || *dest_format == GST_FORMAT_BYTES))) {
369     res = FALSE;
370     goto done;
371   }
372
373   switch (src_format) {
374     case GST_FORMAT_TIME:
375       switch (*dest_format) {
376         case GST_FORMAT_BYTES:
377           *dest_value = gst_util_uint64_scale_int (src_value,
378               stream->strf.auds->av_bps, GST_SECOND);
379           break;
380         case GST_FORMAT_DEFAULT:
381           *dest_value =
382               gst_util_uint64_scale_round (src_value, stream->strh->rate,
383               stream->strh->scale * GST_SECOND);
384           break;
385         default:
386           res = FALSE;
387           break;
388       }
389       break;
390     case GST_FORMAT_BYTES:
391       switch (*dest_format) {
392         case GST_FORMAT_TIME:
393           if (stream->strf.auds->av_bps != 0) {
394             *dest_value = avi_stream_convert_bytes_to_time_unchecked (stream,
395                 src_value);
396           } else
397             res = FALSE;
398           break;
399         default:
400           res = FALSE;
401           break;
402       }
403       break;
404     case GST_FORMAT_DEFAULT:
405       switch (*dest_format) {
406         case GST_FORMAT_TIME:
407           *dest_value =
408               avi_stream_convert_frames_to_time_unchecked (stream, src_value);
409           break;
410         default:
411           res = FALSE;
412           break;
413       }
414       break;
415     default:
416       res = FALSE;
417   }
418
419 done:
420   GST_LOG_OBJECT (pad,
421       "Returning res:%d dest_format:%s dest_value:%" G_GUINT64_FORMAT, res,
422       gst_format_get_name (*dest_format), *dest_value);
423   return res;
424 }
425
426 static const GstQueryType *
427 gst_avi_demux_get_src_query_types (GstPad * pad)
428 {
429   static const GstQueryType src_types[] = {
430     GST_QUERY_POSITION,
431     GST_QUERY_DURATION,
432     GST_QUERY_SEEKING,
433     GST_QUERY_CONVERT,
434     0
435   };
436
437   return src_types;
438 }
439
440 static gboolean
441 gst_avi_demux_handle_src_query (GstPad * pad, GstQuery * query)
442 {
443   gboolean res = TRUE;
444   GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
445
446   GstAviStream *stream = gst_pad_get_element_private (pad);
447
448   if (!stream->strh || !stream->strf.data)
449     return gst_pad_query_default (pad, query);
450
451   switch (GST_QUERY_TYPE (query)) {
452     case GST_QUERY_POSITION:{
453       gint64 pos = 0;
454
455       GST_DEBUG ("pos query for stream %d: frames %d, bytes %" G_GUINT64_FORMAT,
456           stream->num, stream->current_entry, stream->current_total);
457
458       if (stream->strh->type == GST_RIFF_FCC_auds) {
459         if (stream->is_vbr) {
460           /* VBR */
461           pos = gst_util_uint64_scale ((gint64) stream->current_entry *
462               stream->strh->scale, GST_SECOND, (guint64) stream->strh->rate);
463           GST_DEBUG_OBJECT (avi, "VBR convert frame %u, time %"
464               GST_TIME_FORMAT, stream->current_entry, GST_TIME_ARGS (pos));
465         } else if (stream->strf.auds->av_bps != 0) {
466           /* CBR */
467           pos = gst_util_uint64_scale (stream->current_total, GST_SECOND,
468               (guint64) stream->strf.auds->av_bps);
469           GST_DEBUG_OBJECT (avi,
470               "CBR convert bytes %" G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT,
471               stream->current_total, GST_TIME_ARGS (pos));
472         } else if (stream->idx_n != 0 && stream->total_bytes != 0) {
473           /* calculate timestamps based on percentage of length */
474           guint64 xlen = avi->avih->us_frame *
475               avi->avih->tot_frames * GST_USECOND;
476
477           if (stream->is_vbr) {
478             pos = gst_util_uint64_scale (xlen, stream->current_entry,
479                 stream->idx_n);
480             GST_DEBUG_OBJECT (avi, "VBR perc convert frame %u, time %"
481                 GST_TIME_FORMAT, stream->current_entry, GST_TIME_ARGS (pos));
482           } else {
483             pos = gst_util_uint64_scale (xlen, stream->current_total,
484                 stream->total_bytes);
485             GST_DEBUG_OBJECT (avi, "CBR perc convert bytes %" G_GUINT64_FORMAT
486                 ", time %" GST_TIME_FORMAT, stream->current_total,
487                 GST_TIME_ARGS (pos));
488           }
489         } else {
490           /* we don't know */
491           res = FALSE;
492         }
493       } else {
494         if (stream->strh->rate != 0) {
495           pos = gst_util_uint64_scale ((guint64) stream->current_entry *
496               stream->strh->scale, GST_SECOND, (guint64) stream->strh->rate);
497         } else {
498           pos = stream->current_entry * avi->avih->us_frame * GST_USECOND;
499         }
500       }
501       if (res) {
502         GST_DEBUG ("pos query : %" GST_TIME_FORMAT, GST_TIME_ARGS (pos));
503         gst_query_set_position (query, GST_FORMAT_TIME, pos);
504       } else
505         GST_WARNING ("pos query failed");
506       break;
507     }
508     case GST_QUERY_DURATION:
509     {
510       GstFormat fmt;
511
512       if (stream->strh->type != GST_RIFF_FCC_auds &&
513           stream->strh->type != GST_RIFF_FCC_vids) {
514         res = FALSE;
515         break;
516       }
517
518       gst_query_parse_duration (query, &fmt, NULL);
519
520       switch (fmt) {
521         case GST_FORMAT_TIME:
522           gst_query_set_duration (query, fmt, stream->duration);
523           break;
524         case GST_FORMAT_DEFAULT:
525         {
526           gint64 dur;
527           GST_DEBUG_OBJECT (query, "total frames is %" G_GUINT32_FORMAT,
528               stream->idx_n);
529
530           if (stream->idx_n >= 0)
531             gst_query_set_duration (query, fmt, stream->idx_n);
532           else if (gst_pad_query_convert (pad, GST_FORMAT_TIME,
533                   stream->duration, &fmt, &dur))
534             gst_query_set_duration (query, fmt, dur);
535           break;
536         }
537         default:
538           res = FALSE;
539           break;
540       }
541       break;
542     }
543     case GST_QUERY_SEEKING:{
544       GstFormat fmt;
545
546       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
547       if (fmt == GST_FORMAT_TIME) {
548         gboolean seekable = TRUE;
549
550         if (avi->streaming) {
551           seekable = FALSE;
552         }
553
554         gst_query_set_seeking (query, GST_FORMAT_TIME, seekable,
555             0, stream->duration);
556         res = TRUE;
557       }
558       break;
559     }
560     case GST_QUERY_CONVERT:{
561       GstFormat src_fmt, dest_fmt;
562       gint64 src_val, dest_val;
563
564       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
565       if ((res = gst_avi_demux_src_convert (pad, src_fmt, src_val, &dest_fmt,
566                   &dest_val)))
567         gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
568       else
569         res = gst_pad_query_default (pad, query);
570       break;
571     }
572     default:
573       res = gst_pad_query_default (pad, query);
574       break;
575   }
576
577   gst_object_unref (avi);
578   return res;
579 }
580
581 #if 0
582 static const GstEventMask *
583 gst_avi_demux_get_event_mask (GstPad * pad)
584 {
585   static const GstEventMask masks[] = {
586     {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT},
587     {0,}
588   };
589
590   return masks;
591 }
592 #endif
593
594 static gboolean
595 gst_avi_demux_handle_sink_event (GstPad * pad, GstEvent * event)
596 {
597   gboolean res = TRUE;
598   GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
599
600   GST_DEBUG_OBJECT (avi,
601       "have event type %s: %p on sink pad", GST_EVENT_TYPE_NAME (event), event);
602
603   switch (GST_EVENT_TYPE (event)) {
604     case GST_EVENT_NEWSEGMENT:
605       /* Drop NEWSEGMENT events, new ones are generated later */
606       gst_event_unref (event);
607       break;
608     case GST_EVENT_EOS:
609     {
610       if (avi->state != GST_AVI_DEMUX_MOVI) {
611         gst_event_unref (event);
612         GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
613             (NULL), ("got eos and didn't receive a complete header object"));
614       } else if (!gst_avi_demux_push_event (avi, event)) {
615         GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
616             (NULL), ("got eos but no streams (yet)"));
617       }
618       break;
619     }
620     default:
621       res = gst_pad_event_default (pad, event);
622       break;
623   }
624
625   gst_object_unref (avi);
626
627   return res;
628 }
629
630 static gboolean
631 gst_avi_demux_handle_src_event (GstPad * pad, GstEvent * event)
632 {
633   gboolean res = TRUE;
634   GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
635
636   GST_DEBUG_OBJECT (avi,
637       "have event type %s: %p on src pad", GST_EVENT_TYPE_NAME (event), event);
638
639   switch (GST_EVENT_TYPE (event)) {
640     case GST_EVENT_SEEK:
641       /* handle seeking only in pull mode */
642       if (!avi->streaming) {
643         res = gst_avi_demux_handle_seek (avi, pad, event);
644         gst_event_unref (event);
645       } else {
646         res = gst_pad_event_default (pad, event);
647       }
648       break;
649     case GST_EVENT_QOS:
650     case GST_EVENT_NAVIGATION:
651       res = FALSE;
652       gst_event_unref (event);
653       break;
654     default:
655       res = gst_pad_event_default (pad, event);
656       break;
657   }
658
659   gst_object_unref (avi);
660
661   return res;
662 }
663
664 /* streaming helper (push) */
665
666 /*
667  * gst_avi_demux_peek_chunk_info:
668  * @avi: Avi object
669  * @tag: holder for tag
670  * @size: holder for tag size
671  *
672  * Peek next chunk info (tag and size)
673  *
674  * Returns: TRUE when one chunk info has been got
675  */
676 static gboolean
677 gst_avi_demux_peek_chunk_info (GstAviDemux * avi, guint32 * tag, guint32 * size)
678 {
679   const guint8 *data = NULL;
680
681   if (gst_adapter_available (avi->adapter) < 8)
682     return FALSE;
683
684   data = gst_adapter_peek (avi->adapter, 8);
685   *tag = GST_READ_UINT32_LE (data);
686   *size = GST_READ_UINT32_LE (data + 4);
687
688   return TRUE;
689 }
690
691 /*
692  * gst_avi_demux_peek_chunk:
693  * @avi: Avi object
694  * @tag: holder for tag
695  * @size: holder for tag size
696  *
697  * Peek enough data for one full chunk
698  *
699  * Returns: %TRUE when one chunk has been got
700  */
701 static gboolean
702 gst_avi_demux_peek_chunk (GstAviDemux * avi, guint32 * tag, guint32 * size)
703 {
704   guint32 peek_size = 0;
705   gint available;
706
707   if (!gst_avi_demux_peek_chunk_info (avi, tag, size))
708     goto peek_failed;
709
710   /* size 0 -> empty data buffer would surprise most callers,
711    * large size -> do not bother trying to squeeze that into adapter,
712    * so we throw poor man's exception, which can be caught if caller really
713    * wants to handle 0 size chunk */
714   if (!(*size) || (*size) >= (1 << 30))
715     goto strange_size;
716
717   peek_size = (*size + 1) & ~1;
718   available = gst_adapter_available (avi->adapter);
719
720   GST_DEBUG_OBJECT (avi,
721       "Need to peek chunk of %d bytes to read chunk %" GST_FOURCC_FORMAT
722       ", %d bytes available", *size, GST_FOURCC_ARGS (*tag), available);
723
724   if (available < (8 + peek_size))
725     goto need_more;
726
727   return TRUE;
728
729   /* ERRORS */
730 peek_failed:
731   {
732     GST_INFO_OBJECT (avi, "Failed to peek");
733     return FALSE;
734   }
735 strange_size:
736   {
737     GST_INFO_OBJECT (avi,
738         "Invalid/unexpected chunk size %d for tag %" GST_FOURCC_FORMAT, *size,
739         GST_FOURCC_ARGS (*tag));
740     /* chain should give up */
741     avi->abort_buffering = TRUE;
742     return FALSE;
743   }
744 need_more:
745   {
746     GST_INFO_OBJECT (avi, "need more %d < %" G_GUINT32_FORMAT,
747         available, 8 + peek_size);
748     return FALSE;
749   }
750 }
751
752 /* AVI init */
753
754 /*
755  * gst_avi_demux_parse_file_header:
756  * @element: caller element (used for errors/debug).
757  * @buf: input data to be used for parsing.
758  *
759  * "Open" a RIFF/AVI file. The buffer should be at least 12
760  * bytes long. Takes ownership of @buf.
761  *
762  * Returns: TRUE if the file is a RIFF/AVI file, FALSE otherwise.
763  *          Throws an error, caller should error out (fatal).
764  */
765 static gboolean
766 gst_avi_demux_parse_file_header (GstElement * element, GstBuffer * buf)
767 {
768   guint32 doctype;
769   GstClockTime stamp;
770
771   stamp = gst_util_get_timestamp ();
772
773   /* riff_parse posts an error */
774   if (!gst_riff_parse_file_header (element, buf, &doctype))
775     return FALSE;
776
777   if (doctype != GST_RIFF_RIFF_AVI)
778     goto not_avi;
779
780   stamp = gst_util_get_timestamp () - stamp;
781   GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "parsing header %" GST_TIME_FORMAT,
782       GST_TIME_ARGS (stamp));
783
784   return TRUE;
785
786   /* ERRORS */
787 not_avi:
788   {
789     GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
790         ("File is not an AVI file: %" GST_FOURCC_FORMAT,
791             GST_FOURCC_ARGS (doctype)));
792     return FALSE;
793   }
794 }
795
796 /*
797  * Read AVI file tag when streaming
798  */
799 static GstFlowReturn
800 gst_avi_demux_stream_init_push (GstAviDemux * avi)
801 {
802   if (gst_adapter_available (avi->adapter) >= 12) {
803     GstBuffer *tmp;
804
805     tmp = gst_adapter_take_buffer (avi->adapter, 12);
806
807     GST_DEBUG ("Parsing avi header");
808     if (!gst_avi_demux_parse_file_header (GST_ELEMENT (avi), tmp)) {
809       return GST_FLOW_ERROR;
810     }
811     GST_DEBUG ("header ok");
812     avi->offset += 12;
813
814     avi->state = GST_AVI_DEMUX_HEADER;
815   }
816   return GST_FLOW_OK;
817 }
818
819 /*
820  * Read AVI file tag
821  */
822 static GstFlowReturn
823 gst_avi_demux_stream_init_pull (GstAviDemux * avi)
824 {
825   GstFlowReturn res;
826   GstBuffer *buf = NULL;
827
828   res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf);
829   if (res != GST_FLOW_OK)
830     return res;
831   else if (!gst_avi_demux_parse_file_header (GST_ELEMENT_CAST (avi), buf))
832     goto wrong_header;
833
834   avi->offset += 12;
835
836   return GST_FLOW_OK;
837
838   /* ERRORS */
839 wrong_header:
840   {
841     GST_DEBUG_OBJECT (avi, "error parsing file header");
842     return GST_FLOW_ERROR;
843   }
844 }
845
846 /* AVI header handling */
847
848 /*
849  * gst_avi_demux_parse_avih:
850  * @element: caller element (used for errors/debug).
851  * @buf: input data to be used for parsing.
852  * @avih: pointer to structure (filled in by function) containing
853  *        stream information (such as flags, number of streams, etc.).
854  *
855  * Read 'avih' header. Discards buffer after use.
856  *
857  * Returns: TRUE on success, FALSE otherwise. Throws an error if
858  *          the header is invalid. The caller should error out
859  *          (fatal).
860  */
861 static gboolean
862 gst_avi_demux_parse_avih (GstElement * element,
863     GstBuffer * buf, gst_riff_avih ** _avih)
864 {
865   gst_riff_avih *avih;
866
867   if (buf == NULL)
868     goto no_buffer;
869
870   if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_avih))
871     goto avih_too_small;
872
873   avih = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
874
875 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
876   avih->us_frame = GUINT32_FROM_LE (avih->us_frame);
877   avih->max_bps = GUINT32_FROM_LE (avih->max_bps);
878   avih->pad_gran = GUINT32_FROM_LE (avih->pad_gran);
879   avih->flags = GUINT32_FROM_LE (avih->flags);
880   avih->tot_frames = GUINT32_FROM_LE (avih->tot_frames);
881   avih->init_frames = GUINT32_FROM_LE (avih->init_frames);
882   avih->streams = GUINT32_FROM_LE (avih->streams);
883   avih->bufsize = GUINT32_FROM_LE (avih->bufsize);
884   avih->width = GUINT32_FROM_LE (avih->width);
885   avih->height = GUINT32_FROM_LE (avih->height);
886   avih->scale = GUINT32_FROM_LE (avih->scale);
887   avih->rate = GUINT32_FROM_LE (avih->rate);
888   avih->start = GUINT32_FROM_LE (avih->start);
889   avih->length = GUINT32_FROM_LE (avih->length);
890 #endif
891
892   /* debug stuff */
893   GST_INFO_OBJECT (element, "avih tag found:");
894   GST_INFO_OBJECT (element, " us_frame    %u", avih->us_frame);
895   GST_INFO_OBJECT (element, " max_bps     %u", avih->max_bps);
896   GST_INFO_OBJECT (element, " pad_gran    %u", avih->pad_gran);
897   GST_INFO_OBJECT (element, " flags       0x%08x", avih->flags);
898   GST_INFO_OBJECT (element, " tot_frames  %u", avih->tot_frames);
899   GST_INFO_OBJECT (element, " init_frames %u", avih->init_frames);
900   GST_INFO_OBJECT (element, " streams     %u", avih->streams);
901   GST_INFO_OBJECT (element, " bufsize     %u", avih->bufsize);
902   GST_INFO_OBJECT (element, " width       %u", avih->width);
903   GST_INFO_OBJECT (element, " height      %u", avih->height);
904   GST_INFO_OBJECT (element, " scale       %u", avih->scale);
905   GST_INFO_OBJECT (element, " rate        %u", avih->rate);
906   GST_INFO_OBJECT (element, " start       %u", avih->start);
907   GST_INFO_OBJECT (element, " length      %u", avih->length);
908
909   *_avih = avih;
910   gst_buffer_unref (buf);
911
912   return TRUE;
913
914   /* ERRORS */
915 no_buffer:
916   {
917     GST_ELEMENT_ERROR (element, STREAM, DEMUX, (NULL), ("No buffer"));
918     return FALSE;
919   }
920 avih_too_small:
921   {
922     GST_ELEMENT_ERROR (element, STREAM, DEMUX, (NULL),
923         ("Too small avih (%d available, %d needed)",
924             GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_avih)));
925     gst_buffer_unref (buf);
926     return FALSE;
927   }
928 }
929
930 /*
931  * gst_avi_demux_parse_superindex:
932  * @avi: caller element (used for debugging/errors).
933  * @buf: input data to use for parsing.
934  * @locations: locations in the file (byte-offsets) that contain
935  *             the actual indexes (see get_avi_demux_parse_subindex()).
936  *             The array ends with GST_BUFFER_OFFSET_NONE.
937  *
938  * Reads superindex (openDML-2 spec stuff) from the provided data.
939  *
940  * Returns: TRUE on success, FALSE otherwise. Indexes should be skipped
941  *          on error, but they are not fatal.
942  */
943 static gboolean
944 gst_avi_demux_parse_superindex (GstAviDemux * avi,
945     GstBuffer * buf, guint64 ** _indexes)
946 {
947   guint8 *data;
948   guint16 bpe = 16;
949   guint32 num, i;
950   guint64 *indexes;
951   guint size;
952
953   *_indexes = NULL;
954
955   size = buf ? GST_BUFFER_SIZE (buf) : 0;
956   if (size < 24)
957     goto too_small;
958
959   data = GST_BUFFER_DATA (buf);
960
961   /* check type of index. The opendml2 specs state that
962    * there should be 4 dwords per array entry. Type can be
963    * either frame or field (and we don't care). */
964   if (GST_READ_UINT16_LE (data) != 4 ||
965       (data[2] & 0xfe) != 0x0 || data[3] != 0x0) {
966     GST_WARNING_OBJECT (avi,
967         "Superindex for stream has unexpected "
968         "size_entry %d (bytes) or flags 0x%02x/0x%02x",
969         GST_READ_UINT16_LE (data), data[2], data[3]);
970     bpe = GST_READ_UINT16_LE (data) * 4;
971   }
972   num = GST_READ_UINT32_LE (&data[4]);
973
974   indexes = g_new (guint64, num + 1);
975   for (i = 0; i < num; i++) {
976     if (size < 24 + bpe * (i + 1))
977       break;
978     indexes[i] = GST_READ_UINT64_LE (&data[24 + bpe * i]);
979   }
980   indexes[i] = GST_BUFFER_OFFSET_NONE;
981   *_indexes = indexes;
982
983   gst_buffer_unref (buf);
984
985   return TRUE;
986
987   /* ERRORS */
988 too_small:
989   {
990     GST_ERROR_OBJECT (avi,
991         "Not enough data to parse superindex (%d available, 24 needed)", size);
992     if (buf)
993       gst_buffer_unref (buf);
994     return FALSE;
995   }
996 }
997
998 /* add an entry to the index of a stream. @num should be an estimate of the
999  * total amount of index entries for all streams and is used to dynamically
1000  * allocate memory for the index entries. */
1001 static inline gboolean
1002 gst_avi_demux_add_index (GstAviDemux * avi, GstAviStream * stream,
1003     guint num, GstAviIndexEntry * entry)
1004 {
1005   /* ensure index memory */
1006   if (G_UNLIKELY (stream->idx_n >= stream->idx_max)) {
1007     /* we need to make some more room */
1008     if (stream->idx_max == 0) {
1009       /* initial size guess, assume each stream has an equal amount of entries,
1010        * overshoot with at least 8K */
1011       stream->idx_max =
1012           (num / avi->num_streams) + (8192 / sizeof (GstAviIndexEntry));
1013     } else {
1014       stream->idx_max += 8192 / sizeof (GstAviIndexEntry);
1015       GST_CAT_DEBUG (GST_CAT_PERFORMANCE, "expanded index to %u",
1016           stream->idx_max);
1017     }
1018     stream->index = g_try_renew (GstAviIndexEntry, stream->index,
1019         stream->idx_max);
1020     if (G_UNLIKELY (!stream->index))
1021       return FALSE;
1022   }
1023
1024   /* update stream stats and total size */
1025   entry->total = stream->total_bytes;
1026   stream->total_bytes += entry->size;
1027   if (stream->strh->type == GST_RIFF_FCC_auds) {
1028     gint blockalign = stream->strf.auds->blockalign;
1029     if (blockalign > 0)
1030       stream->total_blocks += DIV_ROUND_UP (entry->size, blockalign);
1031     else
1032       stream->total_blocks++;
1033   }
1034   if (ENTRY_IS_KEYFRAME (entry))
1035     stream->n_keyframes++;
1036
1037   /* and add */
1038   GST_LOG_OBJECT (avi,
1039       "Adding stream %u, index entry %d, kf %d, size %u "
1040       ", offset %" G_GUINT64_FORMAT ", total %" G_GUINT64_FORMAT, stream->num,
1041       stream->idx_n, ENTRY_IS_KEYFRAME (entry), entry->size, entry->offset,
1042       entry->total);
1043   stream->index[stream->idx_n++] = *entry;
1044
1045   return TRUE;
1046 }
1047
1048 /* collect and debug stats about the indexes for all streams.
1049  * This method is also responsible for filling in the stream duration
1050  * as measured by the amount of index entries. */
1051 static void
1052 gst_avi_demux_do_index_stats (GstAviDemux * avi)
1053 {
1054   guint i;
1055 #ifndef GST_DISABLE_GST_DEBUG
1056   guint total_idx = 0, total_max = 0;
1057 #endif
1058
1059   /* get stream stats now */
1060   for (i = 0; i < avi->num_streams; i++) {
1061     GstAviIndexEntry *entry;
1062     GstAviStream *stream;
1063     guint64 total;
1064
1065     if (G_UNLIKELY (!(stream = &avi->stream[i])))
1066       continue;
1067     if (G_UNLIKELY (!stream->strh))
1068       continue;
1069     if (G_UNLIKELY (!stream->index || stream->idx_n == 0))
1070       continue;
1071
1072     entry = &stream->index[stream->idx_n - 1];
1073     total = entry->total + entry->size;
1074
1075     /* calculate duration */
1076     if (stream->is_vbr) {
1077       /* VBR stream next timestamp */
1078       if (stream->strh->type == GST_RIFF_FCC_auds) {
1079         stream->idx_duration =
1080             avi_stream_convert_frames_to_time_unchecked (stream, total);
1081       } else {
1082         stream->idx_duration =
1083             avi_stream_convert_frames_to_time_unchecked (stream, stream->idx_n);
1084       }
1085     } else {
1086       /* constant rate stream */
1087       stream->idx_duration = avi_stream_convert_bytes_to_time_unchecked (stream,
1088           total);
1089     }
1090 #ifndef GST_DISABLE_GST_DEBUG
1091     total_idx += stream->idx_n;
1092     total_max += stream->idx_max;
1093 #endif
1094     GST_INFO_OBJECT (avi, "Stream %d, dur %" GST_TIME_FORMAT ", %6u entries, "
1095         "%5u keyframes, entry size = %2u, total size = %10u, allocated %10u",
1096         i, GST_TIME_ARGS (stream->idx_duration), stream->idx_n,
1097         stream->n_keyframes, (guint) sizeof (GstAviIndexEntry),
1098         (guint) (stream->idx_n * sizeof (GstAviIndexEntry)),
1099         (guint) (stream->idx_max * sizeof (GstAviIndexEntry)));
1100   }
1101 #ifndef GST_DISABLE_GST_DEBUG
1102   total_idx *= sizeof (GstAviIndexEntry);
1103   total_max *= sizeof (GstAviIndexEntry);
1104 #endif
1105   GST_INFO_OBJECT (avi, "%u bytes for index vs %u ideally, %u wasted",
1106       total_max, total_idx, total_max - total_idx);
1107 }
1108
1109 /*
1110  * gst_avi_demux_parse_subindex:
1111  * @avi: Avi object
1112  * @buf: input data to use for parsing.
1113  * @stream: stream context.
1114  * @entries_list: a list (returned by the function) containing all the
1115  *           indexes parsed in this specific subindex. The first
1116  *           entry is also a pointer to allocated memory that needs
1117  *           to be free´ed. May be NULL if no supported indexes were
1118  *           found.
1119  *
1120  * Reads superindex (openDML-2 spec stuff) from the provided data.
1121  * The buffer should contain a GST_RIFF_TAG_ix?? chunk.
1122  *
1123  * Returns: TRUE on success, FALSE otherwise. Errors are fatal, we
1124  *          throw an error, caller should bail out asap.
1125  */
1126 static gboolean
1127 gst_avi_demux_parse_subindex (GstAviDemux * avi, GstAviStream * stream,
1128     GstBuffer * buf)
1129 {
1130   guint8 *data;
1131   guint16 bpe;
1132   guint32 num, i;
1133   guint64 baseoff;
1134   guint size;
1135
1136   if (!buf)
1137     return TRUE;
1138
1139   size = GST_BUFFER_SIZE (buf);
1140
1141   /* check size */
1142   if (size < 24)
1143     goto too_small;
1144
1145   data = GST_BUFFER_DATA (buf);
1146
1147   /* We don't support index-data yet */
1148   if (data[3] & 0x80)
1149     goto not_implemented;
1150
1151   /* check type of index. The opendml2 specs state that
1152    * there should be 4 dwords per array entry. Type can be
1153    * either frame or field (and we don't care). */
1154   bpe = (data[2] & 0x01) ? 12 : 8;
1155   if (GST_READ_UINT16_LE (data) != bpe / 4 ||
1156       (data[2] & 0xfe) != 0x0 || data[3] != 0x1) {
1157     GST_WARNING_OBJECT (avi,
1158         "Superindex for stream %d has unexpected "
1159         "size_entry %d (bytes) or flags 0x%02x/0x%02x",
1160         stream->num, GST_READ_UINT16_LE (data), data[2], data[3]);
1161     bpe = GST_READ_UINT16_LE (data) * 4;
1162   }
1163   num = GST_READ_UINT32_LE (&data[4]);
1164   baseoff = GST_READ_UINT64_LE (&data[12]);
1165
1166   /* If there's nothing, just return ! */
1167   if (num == 0)
1168     goto empty_index;
1169
1170   GST_INFO_OBJECT (avi, "Parsing subindex, nr_entries = %6d", num);
1171
1172   for (i = 0; i < num; i++) {
1173     GstAviIndexEntry entry;
1174
1175     if (size < 24 + bpe * (i + 1))
1176       break;
1177
1178     /* fill in offset and size. offset contains the keyframe flag in the
1179      * upper bit*/
1180     entry.offset = baseoff + GST_READ_UINT32_LE (&data[24 + bpe * i]);
1181     entry.size = GST_READ_UINT32_LE (&data[24 + bpe * i + 4]);
1182     /* handle flags */
1183     if (stream->strh->type == GST_RIFF_FCC_auds) {
1184       /* all audio frames are keyframes */
1185       ENTRY_SET_KEYFRAME (&entry);
1186     } else {
1187       /* else read flags */
1188       entry.flags = (entry.size & 0x80000000) ? 0 : GST_AVI_KEYFRAME;
1189     }
1190     entry.size &= ~0x80000000;
1191
1192     /* and add */
1193     if (G_UNLIKELY (!gst_avi_demux_add_index (avi, stream, num, &entry)))
1194       goto out_of_mem;
1195   }
1196   gst_buffer_unref (buf);
1197
1198   return TRUE;
1199
1200   /* ERRORS */
1201 too_small:
1202   {
1203     GST_ERROR_OBJECT (avi,
1204         "Not enough data to parse subindex (%d available, 24 needed)", size);
1205     gst_buffer_unref (buf);
1206     return TRUE;                /* continue */
1207   }
1208 not_implemented:
1209   {
1210     GST_ELEMENT_ERROR (avi, STREAM, NOT_IMPLEMENTED, (NULL),
1211         ("Subindex-is-data is not implemented"));
1212     gst_buffer_unref (buf);
1213     return FALSE;
1214   }
1215 empty_index:
1216   {
1217     GST_DEBUG_OBJECT (avi, "the index is empty");
1218     gst_buffer_unref (buf);
1219     return TRUE;
1220   }
1221 out_of_mem:
1222   {
1223     GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL),
1224         ("Cannot allocate memory for %u*%u=%u bytes",
1225             (guint) sizeof (GstAviIndexEntry), num,
1226             (guint) sizeof (GstAviIndexEntry) * num));
1227     gst_buffer_unref (buf);
1228     return FALSE;
1229   }
1230 }
1231
1232 #if 0
1233 /*
1234  * Read AVI index when streaming
1235  */
1236 static void
1237 gst_avi_demux_read_subindexes_push (GstAviDemux * avi)
1238 {
1239   guint32 tag = 0, size;
1240   GstBuffer *buf = NULL;
1241   gint i, n;
1242
1243   GST_DEBUG_OBJECT (avi, "read subindexes for %d streams", avi->num_streams);
1244
1245   for (n = 0; n < avi->num_streams; n++) {
1246     GstAviStream *stream = &avi->stream[n];
1247
1248     for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) {
1249       if (!gst_avi_demux_peek_chunk (avi, &tag, &size))
1250         continue;
1251       else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10,
1252                   '0' + stream->num % 10)) &&
1253           (tag != GST_MAKE_FOURCC ('0' + stream->num / 10,
1254                   '0' + stream->num % 10, 'i', 'x'))) {
1255         GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")",
1256             GST_FOURCC_ARGS (tag));
1257         continue;
1258       }
1259
1260       avi->offset += 8 + GST_ROUND_UP_2 (size);
1261
1262       buf = gst_buffer_new ();
1263       GST_BUFFER_DATA (buf) = gst_adapter_take (avi->adapter, size);
1264       GST_BUFFER_SIZE (buf) = size;
1265
1266       if (!gst_avi_demux_parse_subindex (avi, stream, buf))
1267         continue;
1268     }
1269
1270     g_free (stream->indexes);
1271     stream->indexes = NULL;
1272   }
1273   /* get stream stats now */
1274   gst_avi_demux_do_index_stats (avi);
1275
1276   avi->have_index = TRUE;
1277 }
1278 #endif
1279
1280 /*
1281  * Read AVI index
1282  */
1283 static void
1284 gst_avi_demux_read_subindexes_pull (GstAviDemux * avi)
1285 {
1286   guint32 tag;
1287   GstBuffer *buf;
1288   gint i, n;
1289
1290   GST_DEBUG_OBJECT (avi, "read subindexes for %d streams", avi->num_streams);
1291
1292   for (n = 0; n < avi->num_streams; n++) {
1293     GstAviStream *stream = &avi->stream[n];
1294
1295     for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) {
1296       if (gst_riff_read_chunk (GST_ELEMENT_CAST (avi), avi->sinkpad,
1297               &stream->indexes[i], &tag, &buf) != GST_FLOW_OK)
1298         continue;
1299       else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10,
1300                   '0' + stream->num % 10)) &&
1301           (tag != GST_MAKE_FOURCC ('0' + stream->num / 10,
1302                   '0' + stream->num % 10, 'i', 'x'))) {
1303         /* Some ODML files (created by god knows what muxer) have a ##ix format
1304          * instead of the 'official' ix##. They are still valid though. */
1305         GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")",
1306             GST_FOURCC_ARGS (tag));
1307         gst_buffer_unref (buf);
1308         continue;
1309       }
1310
1311       if (!gst_avi_demux_parse_subindex (avi, stream, buf))
1312         continue;
1313     }
1314
1315     g_free (stream->indexes);
1316     stream->indexes = NULL;
1317   }
1318   /* get stream stats now */
1319   gst_avi_demux_do_index_stats (avi);
1320
1321   avi->have_index = TRUE;
1322 }
1323
1324 /*
1325  * gst_avi_demux_riff_parse_vprp:
1326  * @element: caller element (used for debugging/error).
1327  * @buf: input data to be used for parsing, stripped from header.
1328  * @vprp: a pointer (returned by this function) to a filled-in vprp
1329  *        structure. Caller should free it.
1330  *
1331  * Parses a video stream´s vprp. This function takes ownership of @buf.
1332  *
1333  * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream
1334  *          should be skipped on error, but it is not fatal.
1335  */
1336 static gboolean
1337 gst_avi_demux_riff_parse_vprp (GstElement * element,
1338     GstBuffer * buf, gst_riff_vprp ** _vprp)
1339 {
1340   gst_riff_vprp *vprp;
1341   gint k;
1342
1343   g_return_val_if_fail (buf != NULL, FALSE);
1344   g_return_val_if_fail (_vprp != NULL, FALSE);
1345
1346   if (GST_BUFFER_SIZE (buf) < G_STRUCT_OFFSET (gst_riff_vprp, field_info))
1347     goto too_small;
1348
1349   vprp = g_memdup (GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
1350
1351 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
1352   vprp->format_token = GUINT32_FROM_LE (vprp->format_token);
1353   vprp->standard = GUINT32_FROM_LE (vprp->standard);
1354   vprp->vert_rate = GUINT32_FROM_LE (vprp->vert_rate);
1355   vprp->hor_t_total = GUINT32_FROM_LE (vprp->hor_t_total);
1356   vprp->vert_lines = GUINT32_FROM_LE (vprp->vert_lines);
1357   vprp->aspect = GUINT32_FROM_LE (vprp->aspect);
1358   vprp->width = GUINT32_FROM_LE (vprp->width);
1359   vprp->height = GUINT32_FROM_LE (vprp->height);
1360   vprp->fields = GUINT32_FROM_LE (vprp->fields);
1361 #endif
1362
1363   /* size checking */
1364   /* calculate fields based on size */
1365   k = (GST_BUFFER_SIZE (buf) - G_STRUCT_OFFSET (gst_riff_vprp, field_info)) /
1366       vprp->fields;
1367   if (vprp->fields > k) {
1368     GST_WARNING_OBJECT (element,
1369         "vprp header indicated %d fields, only %d available", vprp->fields, k);
1370     vprp->fields = k;
1371   }
1372   if (vprp->fields > GST_RIFF_VPRP_VIDEO_FIELDS) {
1373     GST_WARNING_OBJECT (element,
1374         "vprp header indicated %d fields, at most %d supported", vprp->fields,
1375         GST_RIFF_VPRP_VIDEO_FIELDS);
1376     vprp->fields = GST_RIFF_VPRP_VIDEO_FIELDS;
1377   }
1378 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
1379   for (k = 0; k < vprp->fields; k++) {
1380     gst_riff_vprp_video_field_desc *fd;
1381
1382     fd = &vprp->field_info[k];
1383     fd->compressed_bm_height = GUINT32_FROM_LE (fd->compressed_bm_height);
1384     fd->compressed_bm_width = GUINT32_FROM_LE (fd->compressed_bm_width);
1385     fd->valid_bm_height = GUINT32_FROM_LE (fd->valid_bm_height);
1386     fd->valid_bm_width = GUINT16_FROM_LE (fd->valid_bm_width);
1387     fd->valid_bm_x_offset = GUINT16_FROM_LE (fd->valid_bm_x_offset);
1388     fd->valid_bm_y_offset = GUINT32_FROM_LE (fd->valid_bm_y_offset);
1389     fd->video_x_t_offset = GUINT32_FROM_LE (fd->video_x_t_offset);
1390     fd->video_y_start = GUINT32_FROM_LE (fd->video_y_start);
1391   }
1392 #endif
1393
1394   /* debug */
1395   GST_INFO_OBJECT (element, "vprp tag found in context vids:");
1396   GST_INFO_OBJECT (element, " format_token  %d", vprp->format_token);
1397   GST_INFO_OBJECT (element, " standard      %d", vprp->standard);
1398   GST_INFO_OBJECT (element, " vert_rate     %d", vprp->vert_rate);
1399   GST_INFO_OBJECT (element, " hor_t_total   %d", vprp->hor_t_total);
1400   GST_INFO_OBJECT (element, " vert_lines    %d", vprp->vert_lines);
1401   GST_INFO_OBJECT (element, " aspect        %d:%d", vprp->aspect >> 16,
1402       vprp->aspect & 0xffff);
1403   GST_INFO_OBJECT (element, " width         %d", vprp->width);
1404   GST_INFO_OBJECT (element, " height        %d", vprp->height);
1405   GST_INFO_OBJECT (element, " fields        %d", vprp->fields);
1406   for (k = 0; k < vprp->fields; k++) {
1407     gst_riff_vprp_video_field_desc *fd;
1408
1409     fd = &(vprp->field_info[k]);
1410     GST_INFO_OBJECT (element, " field %u description:", k);
1411     GST_INFO_OBJECT (element, "  compressed_bm_height  %d",
1412         fd->compressed_bm_height);
1413     GST_INFO_OBJECT (element, "  compressed_bm_width  %d",
1414         fd->compressed_bm_width);
1415     GST_INFO_OBJECT (element, "  valid_bm_height       %d",
1416         fd->valid_bm_height);
1417     GST_INFO_OBJECT (element, "  valid_bm_width        %d", fd->valid_bm_width);
1418     GST_INFO_OBJECT (element, "  valid_bm_x_offset     %d",
1419         fd->valid_bm_x_offset);
1420     GST_INFO_OBJECT (element, "  valid_bm_y_offset     %d",
1421         fd->valid_bm_y_offset);
1422     GST_INFO_OBJECT (element, "  video_x_t_offset      %d",
1423         fd->video_x_t_offset);
1424     GST_INFO_OBJECT (element, "  video_y_start         %d", fd->video_y_start);
1425   }
1426
1427   gst_buffer_unref (buf);
1428
1429   *_vprp = vprp;
1430
1431   return TRUE;
1432
1433   /* ERRORS */
1434 too_small:
1435   {
1436     GST_ERROR_OBJECT (element,
1437         "Too small vprp (%d available, at least %d needed)",
1438         GST_BUFFER_SIZE (buf),
1439         (int) G_STRUCT_OFFSET (gst_riff_vprp, field_info));
1440     gst_buffer_unref (buf);
1441     return FALSE;
1442   }
1443 }
1444
1445 /*
1446  * gst_avi_demux_parse_stream:
1447  * @avi: calling element (used for debugging/errors).
1448  * @buf: input buffer used to parse the stream.
1449  *
1450  * Parses all subchunks in a strl chunk (which defines a single
1451  * stream). Discards the buffer after use. This function will
1452  * increment the stream counter internally.
1453  *
1454  * Returns: whether the stream was identified successfully.
1455  *          Errors are not fatal. It does indicate the stream
1456  *          was skipped.
1457  */
1458 static gboolean
1459 gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
1460 {
1461   GstAviStream *stream;
1462   GstElementClass *klass;
1463   GstPadTemplate *templ;
1464   GstBuffer *sub = NULL;
1465   guint offset = 4;
1466   guint32 tag = 0;
1467   gchar *codec_name = NULL, *padname = NULL;
1468   const gchar *tag_name;
1469   GstCaps *caps = NULL;
1470   GstPad *pad;
1471   GstElement *element;
1472   gboolean got_strh = FALSE, got_strf = FALSE, got_vprp = FALSE;
1473   gst_riff_vprp *vprp = NULL;
1474
1475   element = GST_ELEMENT_CAST (avi);
1476
1477   GST_DEBUG_OBJECT (avi, "Parsing stream");
1478
1479   if (avi->num_streams >= GST_AVI_DEMUX_MAX_STREAMS) {
1480     GST_WARNING_OBJECT (avi,
1481         "maximum no of streams (%d) exceeded, ignoring stream",
1482         GST_AVI_DEMUX_MAX_STREAMS);
1483     gst_buffer_unref (buf);
1484     /* not a fatal error, let's say */
1485     return TRUE;
1486   }
1487
1488   stream = &avi->stream[avi->num_streams];
1489
1490   /* initial settings */
1491   stream->idx_duration = GST_CLOCK_TIME_NONE;
1492   stream->hdr_duration = GST_CLOCK_TIME_NONE;
1493   stream->duration = GST_CLOCK_TIME_NONE;
1494
1495   while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) {
1496     /* sub can be NULL if the chunk is empty */
1497     if (sub == NULL) {
1498       GST_DEBUG_OBJECT (avi, "ignoring empty chunk %" GST_FOURCC_FORMAT,
1499           GST_FOURCC_ARGS (tag));
1500       continue;
1501     }
1502     switch (tag) {
1503       case GST_RIFF_TAG_strh:
1504       {
1505         gst_riff_strh *strh;
1506
1507         if (got_strh) {
1508           GST_WARNING_OBJECT (avi, "Ignoring additional strh chunk");
1509           break;
1510         }
1511         if (!gst_riff_parse_strh (element, sub, &stream->strh)) {
1512           /* ownership given away */
1513           sub = NULL;
1514           GST_WARNING_OBJECT (avi, "Failed to parse strh chunk");
1515           goto fail;
1516         }
1517         sub = NULL;
1518         strh = stream->strh;
1519         /* sanity check; stream header frame rate matches global header
1520          * frame duration */
1521         if (stream->strh->type == GST_RIFF_FCC_vids) {
1522           GstClockTime s_dur;
1523           GstClockTime h_dur = avi->avih->us_frame * GST_USECOND;
1524
1525           s_dur = gst_util_uint64_scale (GST_SECOND, strh->scale, strh->rate);
1526           GST_DEBUG_OBJECT (avi, "verifying stream framerate %d/%d, "
1527               "frame duration = %d ms", strh->rate, strh->scale,
1528               (gint) (s_dur / GST_MSECOND));
1529           if (h_dur > (10 * GST_MSECOND) && (s_dur > 10 * h_dur)) {
1530             strh->rate = GST_SECOND / GST_USECOND;
1531             strh->scale = h_dur / GST_USECOND;
1532             GST_DEBUG_OBJECT (avi, "correcting stream framerate to %d/%d",
1533                 strh->rate, strh->scale);
1534           }
1535         }
1536         /* determine duration as indicated by header */
1537         stream->hdr_duration = gst_util_uint64_scale ((guint64) strh->length *
1538             strh->scale, GST_SECOND, (guint64) strh->rate);
1539         GST_INFO ("Stream duration according to header: %" GST_TIME_FORMAT,
1540             GST_TIME_ARGS (stream->hdr_duration));
1541         if (stream->hdr_duration == 0)
1542           stream->hdr_duration = GST_CLOCK_TIME_NONE;
1543
1544         got_strh = TRUE;
1545         break;
1546       }
1547       case GST_RIFF_TAG_strf:
1548       {
1549         gboolean res = FALSE;
1550
1551         if (got_strf) {
1552           GST_WARNING_OBJECT (avi, "Ignoring additional strf chunk");
1553           break;
1554         }
1555         if (!got_strh) {
1556           GST_ERROR_OBJECT (avi, "Found strf chunk before strh chunk");
1557           goto fail;
1558         }
1559         switch (stream->strh->type) {
1560           case GST_RIFF_FCC_vids:
1561             stream->is_vbr = TRUE;
1562             res = gst_riff_parse_strf_vids (element, sub,
1563                 &stream->strf.vids, &stream->extradata);
1564             sub = NULL;
1565             GST_DEBUG_OBJECT (element, "marking video as VBR, res %d", res);
1566             break;
1567           case GST_RIFF_FCC_auds:
1568             stream->is_vbr = (stream->strh->samplesize == 0)
1569                 && stream->strh->scale > 1;
1570             res =
1571                 gst_riff_parse_strf_auds (element, sub, &stream->strf.auds,
1572                 &stream->extradata);
1573             sub = NULL;
1574             GST_DEBUG_OBJECT (element, "marking audio as VBR:%d, res %d",
1575                 stream->is_vbr, res);
1576             break;
1577           case GST_RIFF_FCC_iavs:
1578             stream->is_vbr = TRUE;
1579             res = gst_riff_parse_strf_iavs (element, sub,
1580                 &stream->strf.iavs, &stream->extradata);
1581             sub = NULL;
1582             GST_DEBUG_OBJECT (element, "marking iavs as VBR, res %d", res);
1583             break;
1584           case GST_RIFF_FCC_txts:
1585             /* nothing to parse here */
1586             stream->is_vbr = (stream->strh->samplesize == 0)
1587                 && (stream->strh->scale > 1);
1588             res = TRUE;
1589             break;
1590           default:
1591             GST_ERROR_OBJECT (avi,
1592                 "Don´t know how to handle stream type %" GST_FOURCC_FORMAT,
1593                 GST_FOURCC_ARGS (stream->strh->type));
1594             break;
1595         }
1596         if (sub) {
1597           gst_buffer_unref (sub);
1598           sub = NULL;
1599         }
1600         if (!res)
1601           goto fail;
1602         got_strf = TRUE;
1603         break;
1604       }
1605       case GST_RIFF_TAG_vprp:
1606       {
1607         if (got_vprp) {
1608           GST_WARNING_OBJECT (avi, "Ignoring additional vprp chunk");
1609           break;
1610         }
1611         if (!got_strh) {
1612           GST_ERROR_OBJECT (avi, "Found vprp chunk before strh chunk");
1613           goto fail;
1614         }
1615         if (!got_strf) {
1616           GST_ERROR_OBJECT (avi, "Found vprp chunk before strf chunk");
1617           goto fail;
1618         }
1619
1620         if (!gst_avi_demux_riff_parse_vprp (element, sub, &vprp)) {
1621           GST_WARNING_OBJECT (avi, "Failed to parse vprp chunk");
1622           /* not considered fatal */
1623           g_free (vprp);
1624           vprp = NULL;
1625         } else
1626           got_vprp = TRUE;
1627         sub = NULL;
1628         break;
1629       }
1630       case GST_RIFF_TAG_strd:
1631         if (stream->initdata)
1632           gst_buffer_unref (stream->initdata);
1633         stream->initdata = sub;
1634         sub = NULL;
1635         break;
1636       case GST_RIFF_TAG_strn:
1637         g_free (stream->name);
1638         if (sub != NULL) {
1639           stream->name =
1640               g_strndup ((gchar *) GST_BUFFER_DATA (sub),
1641               (gsize) GST_BUFFER_SIZE (sub));
1642           gst_buffer_unref (sub);
1643           sub = NULL;
1644         } else {
1645           stream->name = g_strdup ("");
1646         }
1647         GST_DEBUG_OBJECT (avi, "stream name: %s", stream->name);
1648         break;
1649       default:
1650         if (tag == GST_MAKE_FOURCC ('i', 'n', 'd', 'x') ||
1651             tag == GST_MAKE_FOURCC ('i', 'x', '0' + avi->num_streams / 10,
1652                 '0' + avi->num_streams % 10)) {
1653           g_free (stream->indexes);
1654           gst_avi_demux_parse_superindex (avi, sub, &stream->indexes);
1655           stream->superindex = TRUE;
1656           sub = NULL;
1657           break;
1658         }
1659         GST_WARNING_OBJECT (avi,
1660             "Unknown stream header tag %" GST_FOURCC_FORMAT ", ignoring",
1661             GST_FOURCC_ARGS (tag));
1662         /* fall-through */
1663       case GST_RIFF_TAG_JUNK:
1664         break;
1665     }
1666     if (sub != NULL) {
1667       gst_buffer_unref (sub);
1668       sub = NULL;
1669     }
1670   }
1671
1672   if (!got_strh) {
1673     GST_WARNING_OBJECT (avi, "Failed to find strh chunk");
1674     goto fail;
1675   }
1676
1677   if (!got_strf) {
1678     GST_WARNING_OBJECT (avi, "Failed to find strf chunk");
1679     goto fail;
1680   }
1681
1682   /* get class to figure out the template */
1683   klass = GST_ELEMENT_GET_CLASS (avi);
1684
1685   /* we now have all info, let´s set up a pad and a caps and be done */
1686   /* create stream name + pad */
1687   switch (stream->strh->type) {
1688     case GST_RIFF_FCC_vids:{
1689       guint32 fourcc;
1690
1691       fourcc = (stream->strf.vids->compression) ?
1692           stream->strf.vids->compression : stream->strh->fcc_handler;
1693       padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
1694       templ = gst_element_class_get_pad_template (klass, "video_%02d");
1695       caps = gst_riff_create_video_caps (fourcc, stream->strh,
1696           stream->strf.vids, stream->extradata, stream->initdata, &codec_name);
1697       if (!caps) {
1698         caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc",
1699             GST_TYPE_FOURCC, fourcc, NULL);
1700       } else if (got_vprp && vprp) {
1701         guint32 aspect_n, aspect_d;
1702         gint n, d;
1703
1704         aspect_n = vprp->aspect >> 16;
1705         aspect_d = vprp->aspect & 0xffff;
1706         /* calculate the pixel aspect ratio using w/h and aspect ratio */
1707         n = aspect_n * stream->strf.vids->height;
1708         d = aspect_d * stream->strf.vids->width;
1709         if (n && d)
1710           gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1711               n, d, NULL);
1712         /* very local, not needed elsewhere */
1713         g_free (vprp);
1714         vprp = NULL;
1715       }
1716       tag_name = GST_TAG_VIDEO_CODEC;
1717       avi->num_v_streams++;
1718       break;
1719     }
1720     case GST_RIFF_FCC_auds:{
1721       padname = g_strdup_printf ("audio_%02d", avi->num_a_streams);
1722       templ = gst_element_class_get_pad_template (klass, "audio_%02d");
1723       caps = gst_riff_create_audio_caps (stream->strf.auds->format,
1724           stream->strh, stream->strf.auds, stream->extradata,
1725           stream->initdata, &codec_name);
1726       if (!caps) {
1727         caps = gst_caps_new_simple ("audio/x-avi-unknown", "codec_id",
1728             G_TYPE_INT, stream->strf.auds->format, NULL);
1729       }
1730       tag_name = GST_TAG_AUDIO_CODEC;
1731       avi->num_a_streams++;
1732       break;
1733     }
1734     case GST_RIFF_FCC_iavs:{
1735       guint32 fourcc = stream->strh->fcc_handler;
1736
1737       padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
1738       templ = gst_element_class_get_pad_template (klass, "video_%02d");
1739       caps = gst_riff_create_iavs_caps (fourcc, stream->strh,
1740           stream->strf.iavs, stream->extradata, stream->initdata, &codec_name);
1741       if (!caps) {
1742         caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc",
1743             GST_TYPE_FOURCC, fourcc, NULL);
1744       }
1745       tag_name = GST_TAG_VIDEO_CODEC;
1746       avi->num_v_streams++;
1747       break;
1748     }
1749     case GST_RIFF_FCC_txts:{
1750       padname = g_strdup_printf ("subtitle_%02d", avi->num_t_streams);
1751       templ = gst_element_class_get_pad_template (klass, "subtitle_%02d");
1752       caps = gst_caps_new_simple ("application/x-subtitle-avi", NULL);
1753       tag_name = NULL;
1754       avi->num_t_streams++;
1755       break;
1756     }
1757     default:
1758       g_assert_not_reached ();
1759   }
1760
1761   /* no caps means no stream */
1762   if (!caps) {
1763     GST_ERROR_OBJECT (element, "Did not find caps for stream %s", padname);
1764     goto fail;
1765   }
1766
1767   GST_DEBUG_OBJECT (element, "codec-name=%s",
1768       (codec_name ? codec_name : "NULL"));
1769   GST_DEBUG_OBJECT (element, "caps=%" GST_PTR_FORMAT, caps);
1770
1771   /* set proper settings and add it */
1772   if (stream->pad)
1773     gst_object_unref (stream->pad);
1774   pad = stream->pad = gst_pad_new_from_template (templ, padname);
1775   g_free (padname);
1776
1777   gst_pad_use_fixed_caps (pad);
1778 #if 0
1779   gst_pad_set_formats_function (pad,
1780       GST_DEBUG_FUNCPTR (gst_avi_demux_get_src_formats));
1781   gst_pad_set_event_mask_function (pad,
1782       GST_DEBUG_FUNCPTR (gst_avi_demux_get_event_mask));
1783 #endif
1784   gst_pad_set_event_function (pad,
1785       GST_DEBUG_FUNCPTR (gst_avi_demux_handle_src_event));
1786   gst_pad_set_query_type_function (pad,
1787       GST_DEBUG_FUNCPTR (gst_avi_demux_get_src_query_types));
1788   gst_pad_set_query_function (pad,
1789       GST_DEBUG_FUNCPTR (gst_avi_demux_handle_src_query));
1790 #if 0
1791   gst_pad_set_convert_function (pad,
1792       GST_DEBUG_FUNCPTR (gst_avi_demux_src_convert));
1793 #endif
1794
1795   stream->num = avi->num_streams;
1796
1797   stream->start_entry = 0;
1798   stream->step_entry = 0;
1799   stream->stop_entry = 0;
1800
1801   stream->current_entry = -1;
1802   stream->current_total = 0;
1803
1804   stream->last_flow = GST_FLOW_OK;
1805   stream->discont = TRUE;
1806
1807   stream->total_bytes = 0;
1808   stream->total_blocks = 0;
1809   stream->n_keyframes = 0;
1810
1811   stream->idx_n = 0;
1812   stream->idx_max = 0;
1813
1814   gst_pad_set_element_private (pad, stream);
1815   avi->num_streams++;
1816
1817   gst_pad_set_caps (pad, caps);
1818   gst_pad_set_active (pad, TRUE);
1819   gst_element_add_pad (GST_ELEMENT (avi), pad);
1820
1821   GST_LOG_OBJECT (element, "Added pad %s with caps %" GST_PTR_FORMAT,
1822       GST_PAD_NAME (pad), caps);
1823   gst_caps_unref (caps);
1824
1825   /* make tags */
1826   if (codec_name) {
1827     if (!stream->taglist)
1828       stream->taglist = gst_tag_list_new ();
1829
1830     avi->got_tags = TRUE;
1831
1832     gst_tag_list_add (stream->taglist, GST_TAG_MERGE_APPEND, tag_name,
1833         codec_name, NULL);
1834     g_free (codec_name);
1835   }
1836
1837   gst_buffer_unref (buf);
1838
1839   return TRUE;
1840
1841   /* ERRORS */
1842 fail:
1843   {
1844     /* unref any mem that may be in use */
1845     if (buf)
1846       gst_buffer_unref (buf);
1847     if (sub)
1848       gst_buffer_unref (sub);
1849     g_free (vprp);
1850     g_free (codec_name);
1851     gst_avi_demux_reset_stream (avi, stream);
1852     avi->num_streams++;
1853     return FALSE;
1854   }
1855 }
1856
1857 /*
1858  * gst_avi_demux_parse_odml:
1859  * @avi: calling element (used for debug/error).
1860  * @buf: input buffer to be used for parsing.
1861  *
1862  * Read an openDML-2.0 extension header. Fills in the frame number
1863  * in the avi demuxer object when reading succeeds.
1864  */
1865 static void
1866 gst_avi_demux_parse_odml (GstAviDemux * avi, GstBuffer * buf)
1867 {
1868   guint32 tag = 0;
1869   guint offset = 4;
1870   GstBuffer *sub = NULL;
1871
1872   while (gst_riff_parse_chunk (GST_ELEMENT_CAST (avi), buf, &offset, &tag,
1873           &sub)) {
1874     switch (tag) {
1875       case GST_RIFF_TAG_dmlh:{
1876         gst_riff_dmlh dmlh, *_dmlh;
1877         guint size;
1878
1879         /* sub == NULL is possible and means an empty buffer */
1880         size = sub ? GST_BUFFER_SIZE (sub) : 0;
1881
1882         /* check size */
1883         if (size < sizeof (gst_riff_dmlh)) {
1884           GST_ERROR_OBJECT (avi,
1885               "DMLH entry is too small (%d bytes, %d needed)",
1886               size, (int) sizeof (gst_riff_dmlh));
1887           goto next;
1888         }
1889         _dmlh = (gst_riff_dmlh *) GST_BUFFER_DATA (sub);
1890         dmlh.totalframes = GST_READ_UINT32_LE (&_dmlh->totalframes);
1891
1892         GST_INFO_OBJECT (avi, "dmlh tag found: totalframes: %u",
1893             dmlh.totalframes);
1894
1895         avi->avih->tot_frames = dmlh.totalframes;
1896         goto next;
1897       }
1898
1899       default:
1900         GST_WARNING_OBJECT (avi,
1901             "Unknown tag %" GST_FOURCC_FORMAT " in ODML header",
1902             GST_FOURCC_ARGS (tag));
1903         /* fall-through */
1904       case GST_RIFF_TAG_JUNK:
1905       next:
1906         /* skip and move to next chunk */
1907         if (sub) {
1908           gst_buffer_unref (sub);
1909           sub = NULL;
1910         }
1911         break;
1912     }
1913   }
1914   if (buf)
1915     gst_buffer_unref (buf);
1916 }
1917
1918 /* Index helper */
1919 static guint
1920 gst_avi_demux_index_last (GstAviDemux * avi, GstAviStream * stream)
1921 {
1922   return stream->idx_n - 1;
1923 }
1924
1925 /* find a previous entry in the index with the given flags */
1926 static guint
1927 gst_avi_demux_index_prev (GstAviDemux * avi, GstAviStream * stream,
1928     guint last, gboolean keyframe)
1929 {
1930   GstAviIndexEntry *entry;
1931   guint i;
1932
1933   for (i = last; i > 0; i--) {
1934     entry = &stream->index[i - 1];
1935     if (!keyframe || ENTRY_IS_KEYFRAME (entry)) {
1936       return i - 1;
1937     }
1938   }
1939   return 0;
1940 }
1941
1942 static guint
1943 gst_avi_demux_index_next (GstAviDemux * avi, GstAviStream * stream,
1944     guint last, gboolean keyframe)
1945 {
1946   GstAviIndexEntry *entry;
1947   gint i;
1948
1949   for (i = last + 1; i < stream->idx_n; i++) {
1950     entry = &stream->index[i];
1951     if (!keyframe || ENTRY_IS_KEYFRAME (entry)) {
1952       return i;
1953     }
1954   }
1955   return stream->idx_n - 1;
1956 }
1957
1958 static guint
1959 gst_avi_demux_index_entry_search (GstAviIndexEntry * entry, guint64 * total)
1960 {
1961   if (entry->total < *total)
1962     return -1;
1963   else if (entry->total > *total)
1964     return 1;
1965   return 0;
1966 }
1967
1968 /*
1969  * gst_avi_demux_index_for_time:
1970  * @avi: Avi object
1971  * @stream: the stream
1972  * @time: a time position
1973  *
1974  * Finds the index entry which time is less or equal than the requested time.
1975  * Try to avoid binary search when we can convert the time to an index
1976  * position directly (for example for video frames with a fixed duration).
1977  *
1978  * Returns: the found position in the index.
1979  */
1980 static guint
1981 gst_avi_demux_index_for_time (GstAviDemux * avi,
1982     GstAviStream * stream, guint64 time)
1983 {
1984   guint index = -1;
1985   guint64 total;
1986
1987   GST_LOG_OBJECT (avi, "search time:%" GST_TIME_FORMAT, GST_TIME_ARGS (time));
1988
1989   /* easy (and common) cases */
1990   if (time == 0 || stream->idx_n == 0)
1991     return 0;
1992   if (time >= stream->idx_duration)
1993     return stream->idx_n - 1;
1994
1995   /* figure out where we need to go. For that we convert the time to an
1996    * index entry or we convert it to a total and then do a binary search. */
1997   if (stream->is_vbr) {
1998     /* VBR stream next timestamp */
1999     if (stream->strh->type == GST_RIFF_FCC_auds) {
2000       total = avi_stream_convert_time_to_frames_unchecked (stream, time);
2001     } else {
2002       index = avi_stream_convert_time_to_frames_unchecked (stream, time);
2003     }
2004   } else {
2005     /* constant rate stream */
2006     total = avi_stream_convert_time_to_bytes_unchecked (stream, time);
2007   }
2008
2009   if (index == -1) {
2010     GstAviIndexEntry *entry;
2011
2012     /* no index, find index with binary search on total */
2013     GST_LOG_OBJECT (avi, "binary search for entry with total %"
2014         G_GUINT64_FORMAT, total);
2015
2016     entry = gst_util_array_binary_search (stream->index,
2017         stream->idx_n, sizeof (GstAviIndexEntry),
2018         (GCompareDataFunc) gst_avi_demux_index_entry_search,
2019         GST_SEARCH_MODE_BEFORE, &total, NULL);
2020
2021     if (entry == NULL) {
2022       GST_LOG_OBJECT (avi, "not found, assume index 0");
2023       index = 0;
2024     } else {
2025       index = entry - stream->index;
2026       GST_LOG_OBJECT (avi, "found at %u", index);
2027     }
2028   } else {
2029     GST_LOG_OBJECT (avi, "converted time to index %u", index);
2030   }
2031
2032   return index;
2033 }
2034
2035 /* given @entry_n in @stream, calculate info such as timestamps and
2036  * offsets for the entry. */
2037 static void
2038 gst_avi_demux_get_buffer_info (GstAviDemux * avi, GstAviStream * stream,
2039     guint entry_n, GstClockTime * timestamp, GstClockTime * ts_end,
2040     guint64 * offset, guint64 * offset_end)
2041 {
2042   GstAviIndexEntry *entry;
2043
2044   entry = &stream->index[entry_n];
2045
2046   if (stream->is_vbr) {
2047     /* VBR stream next timestamp */
2048     if (stream->strh->type == GST_RIFF_FCC_auds) {
2049       if (timestamp)
2050         *timestamp =
2051             avi_stream_convert_frames_to_time_unchecked (stream, entry->total);
2052       if (ts_end)
2053         *ts_end = avi_stream_convert_frames_to_time_unchecked (stream,
2054             entry->total + entry->size);
2055     } else {
2056       if (timestamp)
2057         *timestamp =
2058             avi_stream_convert_frames_to_time_unchecked (stream, entry_n);
2059       if (ts_end)
2060         *ts_end = avi_stream_convert_frames_to_time_unchecked (stream,
2061             entry_n + 1);
2062     }
2063   } else {
2064     /* constant rate stream */
2065     if (timestamp)
2066       *timestamp =
2067           avi_stream_convert_bytes_to_time_unchecked (stream, entry->total);
2068     if (ts_end)
2069       *ts_end = avi_stream_convert_bytes_to_time_unchecked (stream,
2070           entry->total + entry->size);
2071   }
2072   if (stream->strh->type == GST_RIFF_FCC_vids) {
2073     /* video offsets are the frame number */
2074     if (offset)
2075       *offset = entry_n;
2076     if (offset_end)
2077       *offset_end = entry_n + 1;
2078   } else {
2079     /* no offsets for audio */
2080     if (offset)
2081       *offset = -1;
2082     if (offset_end)
2083       *offset_end = -1;
2084   }
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_CAT_DEBUG (GST_CAT_PERFORMANCE, "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 %d 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 %d 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_CAT_DEBUG (GST_CAT_PERFORMANCE, "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 return %s", gst_flow_get_name (ret));
3529   return ret;
3530 }
3531
3532 /* move @stream to the next position in its index */
3533 static GstFlowReturn
3534 gst_avi_demux_advance (GstAviDemux * avi, GstAviStream * stream,
3535     GstFlowReturn ret)
3536 {
3537   guint old_entry, new_entry;
3538
3539   old_entry = stream->current_entry;
3540   /* move forwards */
3541   new_entry = old_entry + 1;
3542
3543   /* see if we reached the end */
3544   if (new_entry >= stream->stop_entry) {
3545     if (avi->segment.rate < 0.0) {
3546       if (stream->step_entry == stream->start_entry) {
3547         /* we stepped all the way to the start, eos */
3548         GST_DEBUG_OBJECT (avi, "reverse reached start %u", stream->start_entry);
3549         goto eos;
3550       }
3551       /* backwards, stop becomes step, find a new step */
3552       stream->stop_entry = stream->step_entry;
3553       stream->step_entry = gst_avi_demux_index_prev (avi, stream,
3554           stream->stop_entry, TRUE);
3555
3556       GST_DEBUG_OBJECT (avi,
3557           "reverse playback jump: start %u, step %u, stop %u",
3558           stream->start_entry, stream->step_entry, stream->stop_entry);
3559
3560       /* and start from the previous keyframe now */
3561       new_entry = stream->step_entry;
3562     } else {
3563       /* EOS */
3564       GST_DEBUG_OBJECT (avi, "forward reached stop %u", stream->stop_entry);
3565       goto eos;
3566     }
3567   }
3568
3569   if (new_entry != old_entry) {
3570     stream->current_entry = new_entry;
3571     stream->current_total = stream->index[new_entry].total;
3572
3573     if (new_entry == old_entry + 1) {
3574       GST_DEBUG_OBJECT (avi, "moved forwards from %u to %u",
3575           old_entry, new_entry);
3576       /* we simply moved one step forwards, reuse current info */
3577       stream->current_timestamp = stream->current_ts_end;
3578       stream->current_offset = stream->current_offset_end;
3579       gst_avi_demux_get_buffer_info (avi, stream, new_entry,
3580           NULL, &stream->current_ts_end, NULL, &stream->current_offset_end);
3581     } else {
3582       /* we moved DISCONT, full update */
3583       gst_avi_demux_get_buffer_info (avi, stream, new_entry,
3584           &stream->current_timestamp, &stream->current_ts_end,
3585           &stream->current_offset, &stream->current_offset_end);
3586       /* and MARK discont for this stream */
3587       stream->last_flow = GST_FLOW_OK;
3588       stream->discont = TRUE;
3589       GST_DEBUG_OBJECT (avi, "Moved from %u to %u, ts %" GST_TIME_FORMAT
3590           ", ts_end %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
3591           ", off_end %" G_GUINT64_FORMAT, old_entry, new_entry,
3592           GST_TIME_ARGS (stream->current_timestamp),
3593           GST_TIME_ARGS (stream->current_ts_end), stream->current_offset,
3594           stream->current_offset_end);
3595     }
3596   }
3597   return ret;
3598
3599   /* ERROR */
3600 eos:
3601   {
3602     GST_DEBUG_OBJECT (avi, "we are EOS");
3603     /* setting current_timestamp to -1 marks EOS */
3604     stream->current_timestamp = -1;
3605     return GST_FLOW_UNEXPECTED;
3606   }
3607 }
3608
3609 /* find the stream with the lowest current position when going forwards or with
3610  * the highest position when going backwards, this is the stream
3611  * we should push from next */
3612 static gint
3613 gst_avi_demux_find_next (GstAviDemux * avi, gfloat rate)
3614 {
3615   guint64 min_time, max_time;
3616   guint stream_num, i;
3617
3618   max_time = 0;
3619   min_time = G_MAXUINT64;
3620   stream_num = -1;
3621
3622   for (i = 0; i < avi->num_streams; i++) {
3623     guint64 position;
3624     GstAviStream *stream;
3625
3626     stream = &avi->stream[i];
3627     position = stream->current_timestamp;
3628
3629     /* position of -1 is EOS */
3630     if (position != -1) {
3631       if (rate > 0.0 && position < min_time) {
3632         min_time = position;
3633         stream_num = i;
3634       } else if (rate < 0.0 && position >= max_time) {
3635         max_time = position;
3636         stream_num = i;
3637       }
3638     }
3639   }
3640   return stream_num;
3641 }
3642
3643 static GstFlowReturn
3644 gst_avi_demux_loop_data (GstAviDemux * avi)
3645 {
3646   GstFlowReturn ret = GST_FLOW_OK;
3647   guint stream_num;
3648   GstAviStream *stream;
3649   gboolean processed = FALSE;
3650   GstBuffer *buf;
3651   guint64 offset, size;
3652   GstClockTime timestamp, duration;
3653   guint64 out_offset, out_offset_end;
3654   gboolean keyframe;
3655   GstAviIndexEntry *entry;
3656
3657   do {
3658     stream_num = gst_avi_demux_find_next (avi, avi->segment.rate);
3659
3660     /* all are EOS */
3661     if (G_UNLIKELY (stream_num == -1)) {
3662       GST_DEBUG_OBJECT (avi, "all streams are EOS");
3663       goto eos;
3664     }
3665
3666     /* we have the stream now */
3667     stream = &avi->stream[stream_num];
3668
3669     /* skip streams without pads */
3670     if (!stream->pad) {
3671       GST_DEBUG_OBJECT (avi, "skipping entry from stream %d without pad",
3672           stream_num);
3673       goto next;
3674     }
3675
3676     /* get the timing info for the entry */
3677     timestamp = stream->current_timestamp;
3678     duration = stream->current_ts_end - timestamp;
3679     out_offset = stream->current_offset;
3680     out_offset_end = stream->current_offset_end;
3681
3682     /* get the entry data info */
3683     entry = &stream->index[stream->current_entry];
3684     offset = entry->offset;
3685     size = entry->size;
3686     keyframe = ENTRY_IS_KEYFRAME (entry);
3687
3688     /* skip empty entries */
3689     if (size == 0) {
3690       GST_DEBUG_OBJECT (avi, "Skipping entry %u (%u, %p)",
3691           stream->current_entry, size, stream->pad);
3692       goto next;
3693     }
3694
3695     if (avi->segment.rate > 0.0) {
3696       /* only check this for fowards playback for now */
3697       if (keyframe && GST_CLOCK_TIME_IS_VALID (avi->segment.stop)
3698           && (timestamp > avi->segment.stop)) {
3699         goto eos_stop;
3700       }
3701     }
3702
3703     GST_LOG ("reading buffer (size=%d), stream %d, pos %"
3704         G_GUINT64_FORMAT " (%llx), kf %d", size, stream_num, offset,
3705         offset, keyframe);
3706
3707     /* FIXME, check large chunks and cut them up */
3708
3709     /* pull in the data */
3710     ret = gst_pad_pull_range (avi->sinkpad, offset, size, &buf);
3711     if (ret != GST_FLOW_OK)
3712       goto pull_failed;
3713
3714     /* check for short buffers, this is EOS as well */
3715     if (GST_BUFFER_SIZE (buf) < size)
3716       goto short_buffer;
3717
3718     /* invert the picture if needed */
3719     buf = gst_avi_demux_invert (stream, buf);
3720
3721     /* mark non-keyframes */
3722     if (keyframe)
3723       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3724     else
3725       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
3726
3727     GST_BUFFER_TIMESTAMP (buf) = timestamp;
3728     GST_BUFFER_DURATION (buf) = duration;
3729     GST_BUFFER_OFFSET (buf) = out_offset;
3730     GST_BUFFER_OFFSET_END (buf) = out_offset_end;
3731
3732     /* mark discont when pending */
3733     if (stream->discont) {
3734       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3735       stream->discont = FALSE;
3736     }
3737
3738     gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad));
3739
3740     GST_DEBUG_OBJECT (avi, "Pushing buffer of size %u, ts %"
3741         GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
3742         ", off_end %" G_GUINT64_FORMAT " on pad %s",
3743         GST_BUFFER_SIZE (buf), GST_TIME_ARGS (timestamp),
3744         GST_TIME_ARGS (duration), GST_BUFFER_OFFSET (buf),
3745         GST_BUFFER_OFFSET_END (buf), GST_PAD_NAME (stream->pad));
3746
3747     /* update current position in the segment */
3748     gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, timestamp);
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     GST_DEBUG_OBJECT (avi, "Processed buffer %u: %s", stream->current_entry,
3756         gst_flow_get_name (ret));
3757
3758     if (avi->segment.rate < 0) {
3759       if (timestamp > avi->segment.stop && ret == GST_FLOW_UNEXPECTED) {
3760         /* In reverse playback we can get a GST_FLOW_UNEXPECTED when
3761          * we are at the end of the segment, so we just need to jump
3762          * back to the previous section. */
3763         GST_DEBUG_OBJECT (avi, "downstream has reached end of segment");
3764         ret = GST_FLOW_OK;
3765       }
3766     }
3767   next:
3768     /* move to next item */
3769     ret = gst_avi_demux_advance (avi, stream, ret);
3770
3771     /* combine flows */
3772     ret = gst_avi_demux_combine_flows (avi, stream, ret);
3773   } while (!processed);
3774
3775 beach:
3776   return ret;
3777
3778   /* special cases */
3779 eos:
3780   {
3781     GST_DEBUG_OBJECT (avi, "No samples left for any streams - EOS");
3782     ret = GST_FLOW_UNEXPECTED;
3783     goto beach;
3784   }
3785 eos_stop:
3786   {
3787     GST_LOG_OBJECT (avi, "Found keyframe after segment,"
3788         " setting EOS (%" GST_TIME_FORMAT " > %" GST_TIME_FORMAT ")",
3789         GST_TIME_ARGS (timestamp), GST_TIME_ARGS (avi->segment.stop));
3790     ret = GST_FLOW_UNEXPECTED;
3791     goto beach;
3792   }
3793 pull_failed:
3794   {
3795     GST_DEBUG_OBJECT (avi, "pull range failed: pos=%" G_GUINT64_FORMAT
3796         " size=%d", offset, size);
3797     goto beach;
3798   }
3799 short_buffer:
3800   {
3801     GST_WARNING_OBJECT (avi, "Short read at offset %" G_GUINT64_FORMAT
3802         ", only got %d/%d bytes (truncated file?)", offset,
3803         GST_BUFFER_SIZE (buf), size);
3804     gst_buffer_unref (buf);
3805     ret = GST_FLOW_UNEXPECTED;
3806     goto beach;
3807   }
3808 }
3809
3810 /*
3811  * Read data. If we have an index it delegates to
3812  * gst_avi_demux_process_next_entry().
3813  */
3814 static GstFlowReturn
3815 gst_avi_demux_stream_data (GstAviDemux * avi)
3816 {
3817   guint32 tag = 0;
3818   guint32 size = 0;
3819   gint stream_nr = 0;
3820   GstFlowReturn res = GST_FLOW_OK;
3821   GstFormat format = GST_FORMAT_TIME;
3822
3823   if (G_UNLIKELY (avi->have_eos)) {
3824     /* Clean adapter, we're done */
3825     gst_adapter_clear (avi->adapter);
3826     return res;
3827   }
3828
3829   /* Iterate until need more data, so adapter won't grow too much */
3830   while (1) {
3831     if (G_UNLIKELY (!gst_avi_demux_peek_chunk_info (avi, &tag, &size))) {
3832       return GST_FLOW_OK;
3833     }
3834
3835     GST_DEBUG ("Trying chunk (%" GST_FOURCC_FORMAT "), size %d",
3836         GST_FOURCC_ARGS (tag), size);
3837
3838     if (G_LIKELY ((tag & 0xff) >= '0' && (tag & 0xff) <= '9' &&
3839             ((tag >> 8) & 0xff) >= '0' && ((tag >> 8) & 0xff) <= '9')) {
3840       GST_LOG ("Chunk ok");
3841     } else if ((tag & 0xffff) == (('x' << 8) | 'i')) {
3842       GST_DEBUG ("Found sub-index tag");
3843       if (gst_avi_demux_peek_chunk (avi, &tag, &size) || size == 0) {
3844         /* accept 0 size buffer here */
3845         avi->abort_buffering = FALSE;
3846         GST_DEBUG ("  skipping %d bytes for now", size);
3847         gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
3848       }
3849       return GST_FLOW_OK;
3850     } else if (tag == GST_RIFF_TAG_idx1) {
3851       GST_DEBUG ("Found index tag, stream done");
3852       avi->have_eos = TRUE;
3853       return GST_FLOW_UNEXPECTED;
3854     } else if (tag == GST_RIFF_TAG_LIST) {
3855       /* movi chunks might be grouped in rec list */
3856       if (gst_adapter_available (avi->adapter) >= 12) {
3857         GST_DEBUG ("Found LIST tag, skipping LIST header");
3858         gst_adapter_flush (avi->adapter, 12);
3859         continue;
3860       }
3861       return GST_FLOW_OK;
3862     } else if (tag == GST_RIFF_TAG_JUNK) {
3863       /* rec list might contain JUNK chunks */
3864       GST_DEBUG ("Found JUNK tag");
3865       if (gst_avi_demux_peek_chunk (avi, &tag, &size) || size == 0) {
3866         /* accept 0 size buffer here */
3867         avi->abort_buffering = FALSE;
3868         GST_DEBUG ("  skipping %d bytes for now", size);
3869         gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
3870       }
3871       return GST_FLOW_OK;
3872     } else {
3873       GST_DEBUG ("No more stream chunks, send EOS");
3874       avi->have_eos = TRUE;
3875       return GST_FLOW_UNEXPECTED;
3876     }
3877
3878     if (G_UNLIKELY (!gst_avi_demux_peek_chunk (avi, &tag, &size))) {
3879       /* supposedly one hopes to catch a nicer chunk later on ... */
3880       /* FIXME ?? give up here rather than possibly ending up going
3881        * through the whole file */
3882       if (avi->abort_buffering) {
3883         avi->abort_buffering = FALSE;
3884         gst_adapter_flush (avi->adapter, 8);
3885       }
3886       return GST_FLOW_OK;
3887     }
3888     GST_DEBUG ("chunk ID %" GST_FOURCC_FORMAT ", size %u",
3889         GST_FOURCC_ARGS (tag), size);
3890
3891     stream_nr = CHUNKID_TO_STREAMNR (tag);
3892
3893     if (G_UNLIKELY (stream_nr < 0 || stream_nr >= avi->num_streams)) {
3894       /* recoverable */
3895       GST_WARNING ("Invalid stream ID %d (%" GST_FOURCC_FORMAT ")",
3896           stream_nr, GST_FOURCC_ARGS (tag));
3897       avi->offset += 8 + GST_ROUND_UP_2 (size);
3898       gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
3899     } else {
3900       GstAviStream *stream;
3901       GstClockTime next_ts = 0;
3902       GstBuffer *buf;
3903
3904       gst_adapter_flush (avi->adapter, 8);
3905
3906       /* get buffer */
3907       buf = gst_adapter_take_buffer (avi->adapter, GST_ROUND_UP_2 (size));
3908       /* patch the size */
3909       GST_BUFFER_SIZE (buf) = size;
3910       avi->offset += 8 + GST_ROUND_UP_2 (size);
3911
3912       stream = &avi->stream[stream_nr];
3913
3914       /* set delay (if any)
3915          if (stream->strh->init_frames == stream->current_frame &&
3916          stream->delay == 0)
3917          stream->delay = next_ts;
3918        */
3919
3920       /* parsing of corresponding header may have failed */
3921       if (G_UNLIKELY (!stream->pad)) {
3922         GST_WARNING_OBJECT (avi, "no pad for stream ID %" GST_FOURCC_FORMAT,
3923             GST_FOURCC_ARGS (tag));
3924         gst_buffer_unref (buf);
3925       } else {
3926         GstClockTime dur_ts = 0;
3927
3928         /* get time of this buffer */
3929         gst_pad_query_position (stream->pad, &format, (gint64 *) & next_ts);
3930         if (G_UNLIKELY (format != GST_FORMAT_TIME))
3931           goto wrong_format;
3932
3933         /* increment our positions */
3934         stream->current_entry++;
3935         stream->current_total += size;
3936
3937         /* invert the picture if needed */
3938         buf = gst_avi_demux_invert (stream, buf);
3939
3940         gst_pad_query_position (stream->pad, &format, (gint64 *) & dur_ts);
3941         if (G_UNLIKELY (format != GST_FORMAT_TIME))
3942           goto wrong_format;
3943
3944         GST_BUFFER_TIMESTAMP (buf) = next_ts;
3945         GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
3946         if (stream->strh->type == GST_RIFF_FCC_vids) {
3947           GST_BUFFER_OFFSET (buf) = stream->current_entry - 1;
3948           GST_BUFFER_OFFSET_END (buf) = stream->current_entry;
3949         } else {
3950           GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
3951           GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
3952         }
3953
3954         gst_buffer_set_caps (buf, GST_PAD_CAPS (stream->pad));
3955         GST_DEBUG_OBJECT (avi,
3956             "Pushing buffer with time=%" GST_TIME_FORMAT ", duration %"
3957             GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
3958             " and size %d over pad %s", GST_TIME_ARGS (next_ts),
3959             GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_BUFFER_OFFSET (buf),
3960             size, GST_PAD_NAME (stream->pad));
3961
3962         /* update current position in the segment */
3963         gst_segment_set_last_stop (&avi->segment, GST_FORMAT_TIME, next_ts);
3964
3965         /* mark discont when pending */
3966         if (G_UNLIKELY (stream->discont)) {
3967           GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
3968           stream->discont = FALSE;
3969         }
3970         res = gst_pad_push (stream->pad, buf);
3971
3972         /* combine flows */
3973         res = gst_avi_demux_combine_flows (avi, stream, res);
3974         if (G_UNLIKELY (res != GST_FLOW_OK)) {
3975           GST_DEBUG ("Push failed; %s", gst_flow_get_name (res));
3976           return res;
3977         }
3978       }
3979     }
3980   }
3981
3982 done:
3983   return res;
3984
3985   /* ERRORS */
3986 wrong_format:
3987   {
3988     GST_DEBUG_OBJECT (avi, "format %s != GST_FORMAT_TIME",
3989         gst_format_get_name (format));
3990     res = GST_FLOW_ERROR;
3991     goto done;
3992   }
3993 }
3994
3995 /*
3996  * Send pending tags.
3997  */
3998 static void
3999 push_tag_lists (GstAviDemux * avi)
4000 {
4001   guint i;
4002
4003   if (!avi->got_tags)
4004     return;
4005
4006   GST_DEBUG_OBJECT (avi, "Pushing pending tag lists");
4007
4008   for (i = 0; i < avi->num_streams; i++)
4009     if (avi->stream[i].pad && avi->stream[i].taglist) {
4010       GST_DEBUG_OBJECT (avi->stream[i].pad, "Tags: %" GST_PTR_FORMAT,
4011           avi->stream[i].taglist);
4012       gst_element_found_tags_for_pad (GST_ELEMENT (avi), avi->stream[i].pad,
4013           avi->stream[i].taglist);
4014       avi->stream[i].taglist = NULL;
4015     }
4016
4017   if (avi->globaltags == NULL)
4018     avi->globaltags = gst_tag_list_new ();
4019
4020   gst_tag_list_add (avi->globaltags, GST_TAG_MERGE_REPLACE,
4021       GST_TAG_CONTAINER_FORMAT, "AVI", NULL);
4022
4023   GST_DEBUG_OBJECT (avi, "Global tags: %" GST_PTR_FORMAT, avi->globaltags);
4024   gst_element_found_tags (GST_ELEMENT (avi), avi->globaltags);
4025   avi->globaltags = NULL;
4026   avi->got_tags = FALSE;
4027 }
4028
4029 static void
4030 gst_avi_demux_loop (GstPad * pad)
4031 {
4032   GstFlowReturn res;
4033   GstAviDemux *avi = GST_AVI_DEMUX (GST_PAD_PARENT (pad));
4034
4035   switch (avi->state) {
4036     case GST_AVI_DEMUX_START:
4037       if (G_UNLIKELY ((res =
4038                   gst_avi_demux_stream_init_pull (avi)) != GST_FLOW_OK)) {
4039         GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res));
4040         goto pause;
4041       }
4042       avi->state = GST_AVI_DEMUX_HEADER;
4043       /* fall-through */
4044     case GST_AVI_DEMUX_HEADER:
4045       if (G_UNLIKELY ((res =
4046                   gst_avi_demux_stream_header_pull (avi)) != GST_FLOW_OK)) {
4047         GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res));
4048         goto pause;
4049       }
4050       avi->state = GST_AVI_DEMUX_MOVI;
4051       break;
4052     case GST_AVI_DEMUX_MOVI:
4053       if (G_UNLIKELY (avi->seek_event)) {
4054         gst_avi_demux_push_event (avi, avi->seek_event);
4055         avi->seek_event = NULL;
4056       }
4057       if (G_UNLIKELY (avi->got_tags)) {
4058         push_tag_lists (avi);
4059       }
4060       /* process each index entry in turn */
4061       res = gst_avi_demux_loop_data (avi);
4062
4063       /* pause when error */
4064       if (G_UNLIKELY (res != GST_FLOW_OK)) {
4065         GST_INFO ("stream_movi flow: %s", gst_flow_get_name (res));
4066         goto pause;
4067       }
4068       break;
4069     default:
4070       GST_ERROR_OBJECT (avi, "unknown state %d", avi->state);
4071       res = GST_FLOW_ERROR;
4072       goto pause;
4073   }
4074
4075   GST_LOG_OBJECT (avi, "state: %d res:%s", avi->state, gst_flow_get_name (res));
4076
4077   return;
4078
4079   /* ERRORS */
4080 pause:
4081   GST_LOG_OBJECT (avi, "pausing task, reason %s", gst_flow_get_name (res));
4082   avi->segment_running = FALSE;
4083   gst_pad_pause_task (avi->sinkpad);
4084
4085   if (GST_FLOW_IS_FATAL (res) || (res == GST_FLOW_NOT_LINKED)) {
4086     gboolean push_eos = TRUE;
4087
4088     if (res == GST_FLOW_UNEXPECTED) {
4089       /* handle end-of-stream/segment */
4090       if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4091         gint64 stop;
4092
4093         if ((stop = avi->segment.stop) == -1)
4094           stop = avi->segment.duration;
4095
4096         GST_INFO_OBJECT (avi, "sending segment_done");
4097
4098         gst_element_post_message
4099             (GST_ELEMENT (avi),
4100             gst_message_new_segment_done (GST_OBJECT (avi), GST_FORMAT_TIME,
4101                 stop));
4102         push_eos = FALSE;
4103       }
4104     } else {
4105       /* for fatal errors we post an error message */
4106       GST_ELEMENT_ERROR (avi, STREAM, FAILED,
4107           (_("Internal data stream error.")),
4108           ("streaming stopped, reason %s", gst_flow_get_name (res)));
4109     }
4110     if (push_eos) {
4111       GST_INFO_OBJECT (avi, "sending eos");
4112       if (!gst_avi_demux_push_event (avi, gst_event_new_eos ()) &&
4113           (res == GST_FLOW_UNEXPECTED)) {
4114         GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
4115             (NULL), ("got eos but no streams (yet)"));
4116       }
4117     }
4118   }
4119 }
4120
4121
4122 static GstFlowReturn
4123 gst_avi_demux_chain (GstPad * pad, GstBuffer * buf)
4124 {
4125   GstFlowReturn res;
4126   GstAviDemux *avi = GST_AVI_DEMUX (GST_PAD_PARENT (pad));
4127
4128   GST_DEBUG ("Store %d bytes in adapter", GST_BUFFER_SIZE (buf));
4129   gst_adapter_push (avi->adapter, buf);
4130
4131   switch (avi->state) {
4132     case GST_AVI_DEMUX_START:
4133       if ((res = gst_avi_demux_stream_init_push (avi)) != GST_FLOW_OK) {
4134         GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res));
4135         break;
4136       }
4137       break;
4138     case GST_AVI_DEMUX_HEADER:
4139       if ((res = gst_avi_demux_stream_header_push (avi)) != GST_FLOW_OK) {
4140         GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res));
4141         break;
4142       }
4143       break;
4144     case GST_AVI_DEMUX_MOVI:
4145       if (G_UNLIKELY (avi->seek_event)) {
4146         gst_avi_demux_push_event (avi, avi->seek_event);
4147         avi->seek_event = NULL;
4148       }
4149       if (G_UNLIKELY (avi->got_tags)) {
4150         push_tag_lists (avi);
4151       }
4152       res = gst_avi_demux_stream_data (avi);
4153       break;
4154     default:
4155       GST_ELEMENT_ERROR (avi, STREAM, FAILED, (NULL),
4156           ("Illegal internal state"));
4157       res = GST_FLOW_ERROR;
4158       break;
4159   }
4160
4161   GST_DEBUG_OBJECT (avi, "state: %d res:%s", avi->state,
4162       gst_flow_get_name (res));
4163
4164   if (G_UNLIKELY (avi->abort_buffering)) {
4165     avi->abort_buffering = FALSE;
4166     res = GST_FLOW_ERROR;
4167     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, NULL, ("unhandled buffer size"));
4168   }
4169
4170   return res;
4171 }
4172
4173 static gboolean
4174 gst_avi_demux_sink_activate (GstPad * sinkpad)
4175 {
4176   if (gst_pad_check_pull_range (sinkpad)) {
4177     GST_DEBUG ("going to pull mode");
4178     return gst_pad_activate_pull (sinkpad, TRUE);
4179   } else {
4180     GST_DEBUG ("going to push (streaming) mode");
4181     return gst_pad_activate_push (sinkpad, TRUE);
4182   }
4183 }
4184
4185 static gboolean
4186 gst_avi_demux_sink_activate_pull (GstPad * sinkpad, gboolean active)
4187 {
4188   GstAviDemux *avi = GST_AVI_DEMUX (GST_OBJECT_PARENT (sinkpad));
4189
4190   if (active) {
4191     avi->segment_running = TRUE;
4192     avi->streaming = FALSE;
4193     return gst_pad_start_task (sinkpad, (GstTaskFunction) gst_avi_demux_loop,
4194         sinkpad);
4195   } else {
4196     avi->segment_running = FALSE;
4197     return gst_pad_stop_task (sinkpad);
4198   }
4199 }
4200
4201 static gboolean
4202 gst_avi_demux_activate_push (GstPad * pad, gboolean active)
4203 {
4204   GstAviDemux *avi = GST_AVI_DEMUX (GST_OBJECT_PARENT (pad));
4205
4206   if (active) {
4207     GST_DEBUG ("avi: activating push/chain function");
4208     avi->streaming = TRUE;
4209   } else {
4210     GST_DEBUG ("avi: deactivating push/chain function");
4211   }
4212
4213   return TRUE;
4214 }
4215
4216 static GstStateChangeReturn
4217 gst_avi_demux_change_state (GstElement * element, GstStateChange transition)
4218 {
4219   GstStateChangeReturn ret;
4220   GstAviDemux *avi = GST_AVI_DEMUX (element);
4221
4222   switch (transition) {
4223     case GST_STATE_CHANGE_READY_TO_PAUSED:
4224       avi->streaming = FALSE;
4225       gst_segment_init (&avi->segment, GST_FORMAT_TIME);
4226       break;
4227     default:
4228       break;
4229   }
4230
4231   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
4232   if (ret == GST_STATE_CHANGE_FAILURE)
4233     goto done;
4234
4235   switch (transition) {
4236     case GST_STATE_CHANGE_PAUSED_TO_READY:
4237       gst_avi_demux_reset (avi);
4238       break;
4239     default:
4240       break;
4241   }
4242
4243 done:
4244   return ret;
4245 }