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