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