39641634e1a2b98160f60ac7b6c4d63fdd8d0661
[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     GstSeekFlags flags);
103 static gboolean gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad,
104     GstEvent * event);
105 static gboolean gst_avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad,
106     GstEvent * event);
107 static void gst_avi_demux_loop (GstPad * pad);
108 static gboolean gst_avi_demux_sink_activate (GstPad * sinkpad,
109     GstObject * parent);
110 static gboolean gst_avi_demux_sink_activate_mode (GstPad * sinkpad,
111     GstObject * parent, GstPadMode mode, gboolean active);
112 static GstFlowReturn gst_avi_demux_chain (GstPad * pad, GstObject * parent,
113     GstBuffer * buf);
114 #if 0
115 static void gst_avi_demux_set_index (GstElement * element, GstIndex * index);
116 static GstIndex *gst_avi_demux_get_index (GstElement * element);
117 #endif
118 static GstStateChangeReturn gst_avi_demux_change_state (GstElement * element,
119     GstStateChange transition);
120 static void gst_avi_demux_calculate_durations_from_index (GstAviDemux * avi);
121 static void gst_avi_demux_get_buffer_info (GstAviDemux * avi,
122     GstAviStream * stream, guint entry_n, GstClockTime * timestamp,
123     GstClockTime * ts_end, guint64 * offset, guint64 * offset_end);
124
125 static void gst_avi_demux_parse_idit (GstAviDemux * avi, GstBuffer * buf);
126 static void gst_avi_demux_parse_strd (GstAviDemux * avi, GstBuffer * buf);
127
128 static void parse_tag_value (GstAviDemux * avi, GstTagList * taglist,
129     const gchar * type, guint8 * ptr, guint tsize);
130
131 /* GObject methods */
132
133 #define gst_avi_demux_parent_class parent_class
134 G_DEFINE_TYPE (GstAviDemux, gst_avi_demux, GST_TYPE_ELEMENT);
135
136 static void
137 gst_avi_demux_class_init (GstAviDemuxClass * klass)
138 {
139   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
140   GObjectClass *gobject_class = (GObjectClass *) klass;
141   GstPadTemplate *videosrctempl, *audiosrctempl, *subsrctempl, *subpicsrctempl;
142   GstCaps *audcaps, *vidcaps, *subcaps, *subpiccaps;
143
144   GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux",
145       0, "Demuxer for AVI streams");
146
147   gobject_class->finalize = gst_avi_demux_finalize;
148
149   gstelement_class->change_state =
150       GST_DEBUG_FUNCPTR (gst_avi_demux_change_state);
151 #if 0
152   gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_avi_demux_set_index);
153   gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_avi_demux_get_index);
154 #endif
155
156   audcaps = gst_riff_create_audio_template_caps ();
157   gst_caps_append (audcaps, gst_caps_new_empty_simple ("audio/x-avi-unknown"));
158   audiosrctempl = gst_pad_template_new ("audio_%u",
159       GST_PAD_SRC, GST_PAD_SOMETIMES, audcaps);
160
161   vidcaps = gst_riff_create_video_template_caps ();
162   gst_caps_append (vidcaps, gst_riff_create_iavs_template_caps ());
163   gst_caps_append (vidcaps, gst_caps_new_empty_simple ("video/x-avi-unknown"));
164   videosrctempl = gst_pad_template_new ("video_%u",
165       GST_PAD_SRC, GST_PAD_SOMETIMES, vidcaps);
166
167   subcaps = gst_caps_new_empty_simple ("application/x-subtitle-avi");
168   subsrctempl = gst_pad_template_new ("subtitle_%u",
169       GST_PAD_SRC, GST_PAD_SOMETIMES, subcaps);
170   subpiccaps = gst_caps_new_empty_simple ("subpicture/x-xsub");
171   subpicsrctempl = gst_pad_template_new ("subpicture_%u",
172       GST_PAD_SRC, GST_PAD_SOMETIMES, subpiccaps);
173   gst_element_class_add_pad_template (gstelement_class, audiosrctempl);
174   gst_element_class_add_pad_template (gstelement_class, videosrctempl);
175   gst_element_class_add_pad_template (gstelement_class, subsrctempl);
176   gst_element_class_add_pad_template (gstelement_class, subpicsrctempl);
177   gst_element_class_add_static_pad_template (gstelement_class, &sink_templ);
178
179   gst_element_class_set_static_metadata (gstelement_class, "Avi demuxer",
180       "Codec/Demuxer",
181       "Demultiplex an avi file into audio and video",
182       "Erik Walthinsen <omega@cse.ogi.edu>, "
183       "Wim Taymans <wim.taymans@chello.be>, "
184       "Thijs Vermeir <thijsvermeir@gmail.com>");
185 }
186
187 static void
188 gst_avi_demux_init (GstAviDemux * avi)
189 {
190   avi->sinkpad = gst_pad_new_from_static_template (&sink_templ, "sink");
191   gst_pad_set_activate_function (avi->sinkpad,
192       GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate));
193   gst_pad_set_activatemode_function (avi->sinkpad,
194       GST_DEBUG_FUNCPTR (gst_avi_demux_sink_activate_mode));
195   gst_pad_set_chain_function (avi->sinkpad,
196       GST_DEBUG_FUNCPTR (gst_avi_demux_chain));
197   gst_pad_set_event_function (avi->sinkpad,
198       GST_DEBUG_FUNCPTR (gst_avi_demux_handle_sink_event));
199   gst_element_add_pad (GST_ELEMENT_CAST (avi), avi->sinkpad);
200
201   avi->adapter = gst_adapter_new ();
202   avi->flowcombiner = gst_flow_combiner_new ();
203
204   gst_avi_demux_reset (avi);
205
206   GST_OBJECT_FLAG_SET (avi, GST_ELEMENT_FLAG_INDEXABLE);
207 }
208
209 static void
210 gst_avi_demux_finalize (GObject * object)
211 {
212   GstAviDemux *avi = GST_AVI_DEMUX (object);
213
214   GST_DEBUG ("AVI: finalize");
215
216   g_object_unref (avi->adapter);
217   gst_flow_combiner_free (avi->flowcombiner);
218
219   G_OBJECT_CLASS (parent_class)->finalize (object);
220 }
221
222 static void
223 gst_avi_demux_reset_stream (GstAviDemux * avi, GstAviStream * stream)
224 {
225   g_free (stream->strh);
226   g_free (stream->strf.data);
227   g_free (stream->name);
228   g_free (stream->index);
229   g_free (stream->indexes);
230   if (stream->initdata)
231     gst_buffer_unref (stream->initdata);
232   if (stream->extradata)
233     gst_buffer_unref (stream->extradata);
234   if (stream->rgb8_palette)
235     gst_buffer_unref (stream->rgb8_palette);
236   if (stream->pad) {
237     if (stream->exposed) {
238       gst_pad_set_active (stream->pad, FALSE);
239       gst_element_remove_pad (GST_ELEMENT_CAST (avi), stream->pad);
240       gst_flow_combiner_remove_pad (avi->flowcombiner, stream->pad);
241     } else
242       gst_object_unref (stream->pad);
243   }
244   if (stream->taglist) {
245     gst_tag_list_unref (stream->taglist);
246     stream->taglist = NULL;
247   }
248   memset (stream, 0, sizeof (GstAviStream));
249 }
250
251 static void
252 gst_avi_demux_reset (GstAviDemux * avi)
253 {
254   gint i;
255
256   GST_DEBUG ("AVI: reset");
257
258   for (i = 0; i < avi->num_streams; i++)
259     gst_avi_demux_reset_stream (avi, &avi->stream[i]);
260
261   avi->header_state = GST_AVI_DEMUX_HEADER_TAG_LIST;
262   avi->num_streams = 0;
263   avi->num_v_streams = 0;
264   avi->num_a_streams = 0;
265   avi->num_t_streams = 0;
266   avi->num_sp_streams = 0;
267   avi->main_stream = -1;
268
269   avi->have_group_id = FALSE;
270   avi->group_id = G_MAXUINT;
271
272   avi->state = GST_AVI_DEMUX_START;
273   avi->offset = 0;
274   avi->building_index = FALSE;
275
276   avi->index_offset = 0;
277   g_free (avi->avih);
278   avi->avih = NULL;
279
280 #if 0
281   if (avi->element_index)
282     gst_object_unref (avi->element_index);
283   avi->element_index = NULL;
284 #endif
285
286   if (avi->seg_event) {
287     gst_event_unref (avi->seg_event);
288     avi->seg_event = NULL;
289   }
290   if (avi->seek_event) {
291     gst_event_unref (avi->seek_event);
292     avi->seek_event = NULL;
293   }
294
295   if (avi->globaltags)
296     gst_tag_list_unref (avi->globaltags);
297   avi->globaltags = NULL;
298
299   avi->got_tags = TRUE;         /* we always want to push global tags */
300   avi->have_eos = FALSE;
301   avi->seekable = TRUE;
302
303   gst_adapter_clear (avi->adapter);
304
305   gst_segment_init (&avi->segment, GST_FORMAT_TIME);
306   avi->segment_seqnum = 0;
307 }
308
309
310 /* GstElement methods */
311
312 #if 0
313 static const GstFormat *
314 gst_avi_demux_get_src_formats (GstPad * pad)
315 {
316   GstAviStream *stream = gst_pad_get_element_private (pad);
317
318   static const GstFormat src_a_formats[] = {
319     GST_FORMAT_TIME,
320     GST_FORMAT_BYTES,
321     GST_FORMAT_DEFAULT,
322     0
323   };
324   static const GstFormat src_v_formats[] = {
325     GST_FORMAT_TIME,
326     GST_FORMAT_DEFAULT,
327     0
328   };
329
330   return (stream->strh->type == GST_RIFF_FCC_auds ?
331       src_a_formats : src_v_formats);
332 }
333 #endif
334
335 /* assumes stream->strf.auds->av_bps != 0 */
336 static inline GstClockTime
337 avi_stream_convert_bytes_to_time_unchecked (GstAviStream * stream,
338     guint64 bytes)
339 {
340   return gst_util_uint64_scale_int (bytes, GST_SECOND,
341       stream->strf.auds->av_bps);
342 }
343
344 static inline guint64
345 avi_stream_convert_time_to_bytes_unchecked (GstAviStream * stream,
346     GstClockTime time)
347 {
348   return gst_util_uint64_scale_int (time, stream->strf.auds->av_bps,
349       GST_SECOND);
350 }
351
352 /* assumes stream->strh->rate != 0 */
353 static inline GstClockTime
354 avi_stream_convert_frames_to_time_unchecked (GstAviStream * stream,
355     guint64 frames)
356 {
357   return gst_util_uint64_scale (frames, stream->strh->scale * GST_SECOND,
358       stream->strh->rate);
359 }
360
361 static inline guint64
362 avi_stream_convert_time_to_frames_unchecked (GstAviStream * stream,
363     GstClockTime time)
364 {
365   return gst_util_uint64_scale (time, stream->strh->rate,
366       stream->strh->scale * GST_SECOND);
367 }
368
369 static gboolean
370 gst_avi_demux_src_convert (GstPad * pad,
371     GstFormat src_format,
372     gint64 src_value, GstFormat * dest_format, gint64 * dest_value)
373 {
374   GstAviStream *stream = gst_pad_get_element_private (pad);
375   gboolean res = TRUE;
376
377   GST_LOG_OBJECT (pad,
378       "Received  src_format:%s, src_value:%" G_GUINT64_FORMAT
379       ", dest_format:%s", gst_format_get_name (src_format), src_value,
380       gst_format_get_name (*dest_format));
381
382   if (G_UNLIKELY (src_format == *dest_format)) {
383     *dest_value = src_value;
384     goto done;
385   }
386   if (G_UNLIKELY (!stream->strh || !stream->strf.data)) {
387     res = FALSE;
388     goto done;
389   }
390   if (G_UNLIKELY (stream->strh->type == GST_RIFF_FCC_vids &&
391           (src_format == GST_FORMAT_BYTES
392               || *dest_format == GST_FORMAT_BYTES))) {
393     res = FALSE;
394     goto done;
395   }
396
397   switch (src_format) {
398     case GST_FORMAT_TIME:
399       switch (*dest_format) {
400         case GST_FORMAT_BYTES:
401           *dest_value = gst_util_uint64_scale_int (src_value,
402               stream->strf.auds->av_bps, GST_SECOND);
403           break;
404         case GST_FORMAT_DEFAULT:
405           *dest_value =
406               gst_util_uint64_scale_round (src_value, stream->strh->rate,
407               stream->strh->scale * GST_SECOND);
408           break;
409         default:
410           res = FALSE;
411           break;
412       }
413       break;
414     case GST_FORMAT_BYTES:
415       switch (*dest_format) {
416         case GST_FORMAT_TIME:
417           if (stream->strf.auds->av_bps != 0) {
418             *dest_value = avi_stream_convert_bytes_to_time_unchecked (stream,
419                 src_value);
420           } else
421             res = FALSE;
422           break;
423         default:
424           res = FALSE;
425           break;
426       }
427       break;
428     case GST_FORMAT_DEFAULT:
429       switch (*dest_format) {
430         case GST_FORMAT_TIME:
431           *dest_value =
432               avi_stream_convert_frames_to_time_unchecked (stream, src_value);
433           break;
434         default:
435           res = FALSE;
436           break;
437       }
438       break;
439     default:
440       res = FALSE;
441   }
442
443 done:
444   GST_LOG_OBJECT (pad,
445       "Returning res:%d dest_format:%s dest_value:%" G_GUINT64_FORMAT, res,
446       gst_format_get_name (*dest_format), *dest_value);
447   return res;
448 }
449
450 static gboolean
451 gst_avi_demux_handle_src_query (GstPad * pad, GstObject * parent,
452     GstQuery * query)
453 {
454   gboolean res = TRUE;
455   GstAviDemux *avi = GST_AVI_DEMUX (parent);
456
457   GstAviStream *stream = gst_pad_get_element_private (pad);
458
459   if (!stream->strh || !stream->strf.data)
460     return gst_pad_query_default (pad, parent, query);
461
462   switch (GST_QUERY_TYPE (query)) {
463     case GST_QUERY_POSITION:{
464       gint64 pos = 0;
465
466       GST_DEBUG ("pos query for stream %u: frames %u, bytes %u",
467           stream->num, stream->current_entry, stream->current_total);
468
469       /* FIXME, this looks clumsy */
470       if (stream->strh->type == GST_RIFF_FCC_auds) {
471         if (stream->is_vbr) {
472           /* VBR */
473           pos = avi_stream_convert_frames_to_time_unchecked (stream,
474               stream->current_entry);
475           GST_DEBUG_OBJECT (avi, "VBR convert frame %u, time %"
476               GST_TIME_FORMAT, stream->current_entry, GST_TIME_ARGS (pos));
477         } else if (stream->strf.auds->av_bps != 0) {
478           /* CBR */
479           pos = avi_stream_convert_bytes_to_time_unchecked (stream,
480               stream->current_total);
481           GST_DEBUG_OBJECT (avi,
482               "CBR convert bytes %u, time %" GST_TIME_FORMAT,
483               stream->current_total, GST_TIME_ARGS (pos));
484         } else if (stream->idx_n != 0 && stream->total_bytes != 0) {
485           /* calculate timestamps based on percentage of length */
486           guint64 xlen = avi->avih->us_frame *
487               avi->avih->tot_frames * GST_USECOND;
488
489           pos = gst_util_uint64_scale (xlen, stream->current_total,
490               stream->total_bytes);
491           GST_DEBUG_OBJECT (avi,
492               "CBR perc convert bytes %u, time %" GST_TIME_FORMAT,
493               stream->current_total, GST_TIME_ARGS (pos));
494         } else {
495           /* we don't know */
496           res = FALSE;
497         }
498       } else {
499         if (stream->strh->rate != 0) {
500           pos = gst_util_uint64_scale ((guint64) stream->current_entry *
501               stream->strh->scale, GST_SECOND, (guint64) stream->strh->rate);
502         } else {
503           pos = stream->current_entry * avi->avih->us_frame * GST_USECOND;
504         }
505       }
506       if (res) {
507         GST_DEBUG ("pos query : %" GST_TIME_FORMAT, GST_TIME_ARGS (pos));
508         gst_query_set_position (query, GST_FORMAT_TIME, pos);
509       } else
510         GST_WARNING ("pos query failed");
511       break;
512     }
513     case GST_QUERY_DURATION:
514     {
515       GstFormat fmt;
516       GstClockTime duration;
517
518       /* only act on audio or video streams */
519       if (stream->strh->type != GST_RIFF_FCC_auds &&
520           stream->strh->type != GST_RIFF_FCC_vids &&
521           stream->strh->type != GST_RIFF_FCC_iavs) {
522         res = FALSE;
523         break;
524       }
525
526       /* take stream duration, fall back to avih duration */
527       if ((duration = stream->duration) == -1)
528         if ((duration = stream->hdr_duration) == -1)
529           duration = avi->duration;
530
531       gst_query_parse_duration (query, &fmt, NULL);
532
533       switch (fmt) {
534         case GST_FORMAT_TIME:
535           gst_query_set_duration (query, fmt, duration);
536           break;
537         case GST_FORMAT_DEFAULT:
538         {
539           gint64 dur;
540           GST_DEBUG_OBJECT (query, "total frames is %" G_GUINT32_FORMAT,
541               stream->idx_n);
542
543           if (stream->idx_n > 0)
544             gst_query_set_duration (query, fmt, stream->idx_n);
545           else if (gst_pad_query_convert (pad, GST_FORMAT_TIME,
546                   duration, fmt, &dur))
547             gst_query_set_duration (query, fmt, dur);
548           break;
549         }
550         default:
551           res = FALSE;
552           break;
553       }
554       break;
555     }
556     case GST_QUERY_SEEKING:{
557       GstFormat fmt;
558
559       gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
560       if (fmt == GST_FORMAT_TIME) {
561         gboolean seekable = TRUE;
562
563         if (avi->streaming) {
564           seekable = avi->seekable;
565         }
566
567         gst_query_set_seeking (query, GST_FORMAT_TIME, seekable,
568             0, stream->duration);
569         res = TRUE;
570       }
571       break;
572     }
573     case GST_QUERY_CONVERT:{
574       GstFormat src_fmt, dest_fmt;
575       gint64 src_val, dest_val;
576
577       gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
578       if ((res = gst_avi_demux_src_convert (pad, src_fmt, src_val, &dest_fmt,
579                   &dest_val)))
580         gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
581       else
582         res = gst_pad_query_default (pad, parent, query);
583       break;
584     }
585     case GST_QUERY_SEGMENT:
586     {
587       GstFormat format;
588       gint64 start, stop;
589
590       format = avi->segment.format;
591
592       start =
593           gst_segment_to_stream_time (&avi->segment, format,
594           avi->segment.start);
595       if ((stop = avi->segment.stop) == -1)
596         stop = avi->segment.duration;
597       else
598         stop = gst_segment_to_stream_time (&avi->segment, format, stop);
599
600       gst_query_set_segment (query, avi->segment.rate, format, start, stop);
601       res = TRUE;
602       break;
603     }
604     default:
605       res = gst_pad_query_default (pad, parent, query);
606       break;
607   }
608
609   return res;
610 }
611
612 #if 0
613 static const GstEventMask *
614 gst_avi_demux_get_event_mask (GstPad * pad)
615 {
616   static const GstEventMask masks[] = {
617     {GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT},
618     {0,}
619   };
620
621   return masks;
622 }
623 #endif
624
625 #if 0
626 static guint64
627 gst_avi_demux_seek_streams (GstAviDemux * avi, guint64 offset, gboolean before)
628 {
629   GstAviStream *stream;
630   GstIndexEntry *entry;
631   gint i;
632   gint64 val, min = offset;
633
634   for (i = 0; i < avi->num_streams; i++) {
635     stream = &avi->stream[i];
636
637     entry = gst_index_get_assoc_entry (avi->element_index, stream->index_id,
638         before ? GST_INDEX_LOOKUP_BEFORE : GST_INDEX_LOOKUP_AFTER,
639         GST_ASSOCIATION_FLAG_NONE, GST_FORMAT_BYTES, offset);
640
641     if (before) {
642       if (entry) {
643         gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &val);
644         GST_DEBUG_OBJECT (avi, "stream %d, previous entry at %"
645             G_GUINT64_FORMAT, i, val);
646         if (val < min)
647           min = val;
648       }
649       continue;
650     }
651
652     if (!entry) {
653       GST_DEBUG_OBJECT (avi, "no position for stream %d, assuming at start", i);
654       stream->current_entry = 0;
655       stream->current_total = 0;
656       continue;
657     }
658
659     gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &val);
660     GST_DEBUG_OBJECT (avi, "stream %d, next entry at %" G_GUINT64_FORMAT,
661         i, val);
662
663     gst_index_entry_assoc_map (entry, GST_FORMAT_TIME, &val);
664     stream->current_total = val;
665     gst_index_entry_assoc_map (entry, GST_FORMAT_DEFAULT, &val);
666     stream->current_entry = val;
667   }
668
669   return min;
670 }
671 #endif
672
673 static gint
674 gst_avi_demux_index_entry_offset_search (GstAviIndexEntry * entry,
675     guint64 * offset)
676 {
677   if (entry->offset < *offset)
678     return -1;
679   else if (entry->offset > *offset)
680     return 1;
681   return 0;
682 }
683
684 static guint64
685 gst_avi_demux_seek_streams_index (GstAviDemux * avi, guint64 offset,
686     gboolean before)
687 {
688   GstAviStream *stream;
689   GstAviIndexEntry *entry;
690   gint i;
691   gint64 val, min = offset;
692   guint index = 0;
693
694   for (i = 0; i < avi->num_streams; i++) {
695     stream = &avi->stream[i];
696
697     /* compensate for chunk header */
698     offset += 8;
699     entry =
700         gst_util_array_binary_search (stream->index, stream->idx_n,
701         sizeof (GstAviIndexEntry),
702         (GCompareDataFunc) gst_avi_demux_index_entry_offset_search,
703         before ? GST_SEARCH_MODE_BEFORE : GST_SEARCH_MODE_AFTER, &offset, NULL);
704     offset -= 8;
705
706     if (entry)
707       index = entry - stream->index;
708
709     if (before) {
710       if (entry) {
711         val = stream->index[index].offset;
712         GST_DEBUG_OBJECT (avi,
713             "stream %d, previous entry at %" G_GUINT64_FORMAT, i, val);
714         if (val < min)
715           min = val;
716       }
717       continue;
718     }
719
720     if (!entry) {
721       GST_DEBUG_OBJECT (avi, "no position for stream %d, assuming at start", i);
722       stream->current_entry = 0;
723       stream->current_total = 0;
724       continue;
725     }
726
727     val = stream->index[index].offset - 8;
728     GST_DEBUG_OBJECT (avi, "stream %d, next entry at %" G_GUINT64_FORMAT, i,
729         val);
730
731     stream->current_total = stream->index[index].total;
732     stream->current_entry = index;
733   }
734
735   return min;
736 }
737
738 #define GST_AVI_SEEK_PUSH_DISPLACE     (4 * GST_SECOND)
739
740 static gboolean
741 gst_avi_demux_handle_sink_event (GstPad * pad, GstObject * parent,
742     GstEvent * event)
743 {
744   gboolean res = TRUE;
745   GstAviDemux *avi = GST_AVI_DEMUX (parent);
746
747   GST_DEBUG_OBJECT (avi,
748       "have event type %s: %p on sink pad", GST_EVENT_TYPE_NAME (event), event);
749
750   switch (GST_EVENT_TYPE (event)) {
751     case GST_EVENT_SEGMENT:
752     {
753       gint64 boffset, offset = 0;
754       GstSegment segment;
755       GstEvent *segment_event;
756
757       /* some debug output */
758       gst_event_copy_segment (event, &segment);
759       GST_DEBUG_OBJECT (avi, "received newsegment %" GST_SEGMENT_FORMAT,
760           &segment);
761
762       /* chain will send initial newsegment after pads have been added */
763       if (avi->state != GST_AVI_DEMUX_MOVI) {
764         GST_DEBUG_OBJECT (avi, "still starting, eating event");
765         goto exit;
766       }
767
768       /* we only expect a BYTE segment, e.g. following a seek */
769       if (segment.format != GST_FORMAT_BYTES) {
770         GST_DEBUG_OBJECT (avi, "unsupported segment format, ignoring");
771         goto exit;
772       }
773
774       if (avi->have_index) {
775         GstAviIndexEntry *entry;
776         guint i = 0, index = 0, k = 0;
777         GstAviStream *stream;
778
779         /* compensate chunk header, stored index offset points after header */
780         boffset = segment.start + 8;
781         /* find which stream we're on */
782         do {
783           stream = &avi->stream[i];
784
785           /* find the index for start bytes offset */
786           entry = gst_util_array_binary_search (stream->index,
787               stream->idx_n, sizeof (GstAviIndexEntry),
788               (GCompareDataFunc) gst_avi_demux_index_entry_offset_search,
789               GST_SEARCH_MODE_AFTER, &boffset, NULL);
790
791           if (entry == NULL)
792             continue;
793           index = entry - stream->index;
794
795           /* we are on the stream with a chunk start offset closest to start */
796           if (!offset || stream->index[index].offset < offset) {
797             offset = stream->index[index].offset;
798             k = i;
799           }
800           /* exact match needs no further searching */
801           if (stream->index[index].offset == boffset)
802             break;
803         } while (++i < avi->num_streams);
804         boffset -= 8;
805         offset -= 8;
806         stream = &avi->stream[k];
807
808         /* so we have no idea what is to come, or where we are */
809         if (!offset) {
810           GST_WARNING_OBJECT (avi, "insufficient index data, forcing EOS");
811           goto eos;
812         }
813
814         /* get the ts corresponding to start offset bytes for the stream */
815         gst_avi_demux_get_buffer_info (avi, stream, index,
816             (GstClockTime *) & segment.time, NULL, NULL, NULL);
817 #if 0
818       } else if (avi->element_index) {
819         GstIndexEntry *entry;
820
821         /* Let's check if we have an index entry for this position */
822         entry = gst_index_get_assoc_entry (avi->element_index, avi->index_id,
823             GST_INDEX_LOOKUP_AFTER, GST_ASSOCIATION_FLAG_NONE,
824             GST_FORMAT_BYTES, segment.start);
825
826         /* we can not go where we have not yet been before ... */
827         if (!entry) {
828           GST_WARNING_OBJECT (avi, "insufficient index data, forcing EOS");
829           goto eos;
830         }
831
832         gst_index_entry_assoc_map (entry, GST_FORMAT_TIME,
833             (gint64 *) & segment.time);
834         gst_index_entry_assoc_map (entry, GST_FORMAT_BYTES, &offset);
835 #endif
836       } else {
837         GST_WARNING_OBJECT (avi, "no index data, forcing EOS");
838         goto eos;
839       }
840
841       segment.format = GST_FORMAT_TIME;
842       segment.start = segment.time;
843       segment.stop = GST_CLOCK_TIME_NONE;
844       segment.position = segment.start;
845
846       /* rescue duration */
847       segment.duration = avi->segment.duration;
848
849       /* set up segment and send downstream */
850       gst_segment_copy_into (&segment, &avi->segment);
851
852       GST_DEBUG_OBJECT (avi, "Pushing newseg %" GST_SEGMENT_FORMAT, &segment);
853       avi->segment_seqnum = gst_event_get_seqnum (event);
854       segment_event = gst_event_new_segment (&segment);
855       gst_event_set_seqnum (segment_event, gst_event_get_seqnum (event));
856       gst_avi_demux_push_event (avi, segment_event);
857
858       GST_DEBUG_OBJECT (avi, "next chunk expected at %" G_GINT64_FORMAT,
859           boffset);
860
861       /* adjust state for streaming thread accordingly */
862       if (avi->have_index)
863         gst_avi_demux_seek_streams_index (avi, offset, FALSE);
864 #if 0
865       else
866         gst_avi_demux_seek_streams (avi, offset, FALSE);
867 #endif
868
869       /* set up streaming thread */
870       g_assert (offset >= boffset);
871       avi->offset = boffset;
872       avi->todrop = offset - boffset;
873
874     exit:
875       gst_event_unref (event);
876       res = TRUE;
877       break;
878     eos:
879       /* set up for EOS */
880       avi->have_eos = TRUE;
881       goto exit;
882     }
883     case GST_EVENT_EOS:
884     {
885       if (avi->state != GST_AVI_DEMUX_MOVI) {
886         gst_event_unref (event);
887         GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
888             (NULL), ("got eos and didn't receive a complete header object"));
889       } else if (!gst_avi_demux_push_event (avi, event)) {
890         GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
891             (NULL), ("got eos but no streams (yet)"));
892       }
893       break;
894     }
895     case GST_EVENT_FLUSH_STOP:
896     {
897       gint i;
898
899       gst_adapter_clear (avi->adapter);
900       avi->have_eos = FALSE;
901       for (i = 0; i < avi->num_streams; i++) {
902         avi->stream[i].discont = TRUE;
903       }
904       /* fall through to default case so that the event gets passed downstream */
905     }
906     default:
907       res = gst_pad_event_default (pad, parent, event);
908       break;
909   }
910
911   return res;
912 }
913
914 static gboolean
915 gst_avi_demux_handle_src_event (GstPad * pad, GstObject * parent,
916     GstEvent * event)
917 {
918   gboolean res = TRUE;
919   GstAviDemux *avi = GST_AVI_DEMUX (parent);
920
921   GST_DEBUG_OBJECT (avi,
922       "have event type %s: %p on src pad", GST_EVENT_TYPE_NAME (event), event);
923
924   switch (GST_EVENT_TYPE (event)) {
925     case GST_EVENT_SEEK:
926       if (!avi->streaming) {
927         res = gst_avi_demux_handle_seek (avi, pad, event);
928       } else {
929         res = gst_avi_demux_handle_seek_push (avi, pad, event);
930       }
931       gst_event_unref (event);
932       break;
933     default:
934       res = gst_pad_event_default (pad, parent, event);
935       break;
936   }
937
938   return res;
939 }
940
941 /* streaming helper (push) */
942
943 /*
944  * gst_avi_demux_peek_chunk_info:
945  * @avi: Avi object
946  * @tag: holder for tag
947  * @size: holder for tag size
948  *
949  * Peek next chunk info (tag and size)
950  *
951  * Returns: TRUE when one chunk info has been got
952  */
953 static gboolean
954 gst_avi_demux_peek_chunk_info (GstAviDemux * avi, guint32 * tag, guint32 * size)
955 {
956   const guint8 *data = NULL;
957
958   if (gst_adapter_available (avi->adapter) < 8)
959     return FALSE;
960
961   data = gst_adapter_map (avi->adapter, 8);
962   *tag = GST_READ_UINT32_LE (data);
963   *size = GST_READ_UINT32_LE (data + 4);
964   gst_adapter_unmap (avi->adapter);
965
966   return TRUE;
967 }
968
969 /*
970  * gst_avi_demux_peek_chunk:
971  * @avi: Avi object
972  * @tag: holder for tag
973  * @size: holder for tag size
974  *
975  * Peek enough data for one full chunk
976  *
977  * Returns: %TRUE when one chunk has been got
978  */
979 static gboolean
980 gst_avi_demux_peek_chunk (GstAviDemux * avi, guint32 * tag, guint32 * size)
981 {
982   guint32 peek_size = 0;
983   gint available;
984
985   if (!gst_avi_demux_peek_chunk_info (avi, tag, size))
986     goto peek_failed;
987
988   /* size 0 -> empty data buffer would surprise most callers,
989    * large size -> do not bother trying to squeeze that into adapter,
990    * so we throw poor man's exception, which can be caught if caller really
991    * wants to handle 0 size chunk */
992   if (!(*size) || (*size) >= (1 << 30))
993     goto strange_size;
994
995   peek_size = (*size + 1) & ~1;
996   available = gst_adapter_available (avi->adapter);
997
998   GST_DEBUG_OBJECT (avi,
999       "Need to peek chunk of %d bytes to read chunk %" GST_FOURCC_FORMAT
1000       ", %d bytes available", *size, GST_FOURCC_ARGS (*tag), available);
1001
1002   if (available < (8 + peek_size))
1003     goto need_more;
1004
1005   return TRUE;
1006
1007   /* ERRORS */
1008 peek_failed:
1009   {
1010     GST_INFO_OBJECT (avi, "Failed to peek");
1011     return FALSE;
1012   }
1013 strange_size:
1014   {
1015     GST_INFO_OBJECT (avi,
1016         "Invalid/unexpected chunk size %d for tag %" GST_FOURCC_FORMAT, *size,
1017         GST_FOURCC_ARGS (*tag));
1018     /* chain should give up */
1019     avi->abort_buffering = TRUE;
1020     return FALSE;
1021   }
1022 need_more:
1023   {
1024     GST_INFO_OBJECT (avi, "need more %d < %" G_GUINT32_FORMAT,
1025         available, 8 + peek_size);
1026     return FALSE;
1027   }
1028 }
1029
1030 /* AVI init */
1031
1032 /*
1033  * gst_avi_demux_parse_file_header:
1034  * @element: caller element (used for errors/debug).
1035  * @buf: input data to be used for parsing.
1036  *
1037  * "Open" a RIFF/AVI file. The buffer should be at least 12
1038  * bytes long. Takes ownership of @buf.
1039  *
1040  * Returns: TRUE if the file is a RIFF/AVI file, FALSE otherwise.
1041  *          Throws an error, caller should error out (fatal).
1042  */
1043 static gboolean
1044 gst_avi_demux_parse_file_header (GstElement * element, GstBuffer * buf)
1045 {
1046   guint32 doctype;
1047   GstClockTime stamp;
1048
1049   stamp = gst_util_get_timestamp ();
1050
1051   /* riff_parse posts an error */
1052   if (!gst_riff_parse_file_header (element, buf, &doctype))
1053     return FALSE;
1054
1055   if (doctype != GST_RIFF_RIFF_AVI)
1056     goto not_avi;
1057
1058   stamp = gst_util_get_timestamp () - stamp;
1059   GST_DEBUG_OBJECT (element, "header parsing took %" GST_TIME_FORMAT,
1060       GST_TIME_ARGS (stamp));
1061
1062   return TRUE;
1063
1064   /* ERRORS */
1065 not_avi:
1066   {
1067     GST_ELEMENT_ERROR (element, STREAM, WRONG_TYPE, (NULL),
1068         ("File is not an AVI file: 0x%" G_GINT32_MODIFIER "x", doctype));
1069     return FALSE;
1070   }
1071 }
1072
1073 /*
1074  * Read AVI file tag when streaming
1075  */
1076 static GstFlowReturn
1077 gst_avi_demux_stream_init_push (GstAviDemux * avi)
1078 {
1079   if (gst_adapter_available (avi->adapter) >= 12) {
1080     GstBuffer *tmp;
1081
1082     tmp = gst_adapter_take_buffer (avi->adapter, 12);
1083
1084     GST_DEBUG ("Parsing avi header");
1085     if (!gst_avi_demux_parse_file_header (GST_ELEMENT_CAST (avi), tmp)) {
1086       return GST_FLOW_ERROR;
1087     }
1088     GST_DEBUG ("header ok");
1089     avi->offset += 12;
1090
1091     avi->state = GST_AVI_DEMUX_HEADER;
1092   }
1093   return GST_FLOW_OK;
1094 }
1095
1096 /*
1097  * Read AVI file tag
1098  */
1099 static GstFlowReturn
1100 gst_avi_demux_stream_init_pull (GstAviDemux * avi)
1101 {
1102   GstFlowReturn res;
1103   GstBuffer *buf = NULL;
1104
1105   res = gst_pad_pull_range (avi->sinkpad, avi->offset, 12, &buf);
1106   if (res != GST_FLOW_OK)
1107     return res;
1108   else if (!gst_avi_demux_parse_file_header (GST_ELEMENT_CAST (avi), buf))
1109     goto wrong_header;
1110
1111   avi->offset += 12;
1112
1113   return GST_FLOW_OK;
1114
1115   /* ERRORS */
1116 wrong_header:
1117   {
1118     GST_DEBUG_OBJECT (avi, "error parsing file header");
1119     return GST_FLOW_ERROR;
1120   }
1121 }
1122
1123 /* AVI header handling */
1124 /*
1125  * gst_avi_demux_parse_avih:
1126  * @avi: caller element (used for errors/debug).
1127  * @buf: input data to be used for parsing.
1128  * @avih: pointer to structure (filled in by function) containing
1129  *        stream information (such as flags, number of streams, etc.).
1130  *
1131  * Read 'avih' header. Discards buffer after use.
1132  *
1133  * Returns: TRUE on success, FALSE otherwise. Throws an error if
1134  *          the header is invalid. The caller should error out
1135  *          (fatal).
1136  */
1137 static gboolean
1138 gst_avi_demux_parse_avih (GstAviDemux * avi,
1139     GstBuffer * buf, gst_riff_avih ** _avih)
1140 {
1141   gst_riff_avih *avih;
1142   gsize size;
1143
1144   if (buf == NULL)
1145     goto no_buffer;
1146
1147   size = gst_buffer_get_size (buf);
1148   if (size < sizeof (gst_riff_avih))
1149     goto avih_too_small;
1150
1151   avih = g_malloc (size);
1152   gst_buffer_extract (buf, 0, avih, size);
1153
1154 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
1155   avih->us_frame = GUINT32_FROM_LE (avih->us_frame);
1156   avih->max_bps = GUINT32_FROM_LE (avih->max_bps);
1157   avih->pad_gran = GUINT32_FROM_LE (avih->pad_gran);
1158   avih->flags = GUINT32_FROM_LE (avih->flags);
1159   avih->tot_frames = GUINT32_FROM_LE (avih->tot_frames);
1160   avih->init_frames = GUINT32_FROM_LE (avih->init_frames);
1161   avih->streams = GUINT32_FROM_LE (avih->streams);
1162   avih->bufsize = GUINT32_FROM_LE (avih->bufsize);
1163   avih->width = GUINT32_FROM_LE (avih->width);
1164   avih->height = GUINT32_FROM_LE (avih->height);
1165   avih->scale = GUINT32_FROM_LE (avih->scale);
1166   avih->rate = GUINT32_FROM_LE (avih->rate);
1167   avih->start = GUINT32_FROM_LE (avih->start);
1168   avih->length = GUINT32_FROM_LE (avih->length);
1169 #endif
1170
1171   /* debug stuff */
1172   GST_INFO_OBJECT (avi, "avih tag found:");
1173   GST_INFO_OBJECT (avi, " us_frame    %u", avih->us_frame);
1174   GST_INFO_OBJECT (avi, " max_bps     %u", avih->max_bps);
1175   GST_INFO_OBJECT (avi, " pad_gran    %u", avih->pad_gran);
1176   GST_INFO_OBJECT (avi, " flags       0x%08x", avih->flags);
1177   GST_INFO_OBJECT (avi, " tot_frames  %u", avih->tot_frames);
1178   GST_INFO_OBJECT (avi, " init_frames %u", avih->init_frames);
1179   GST_INFO_OBJECT (avi, " streams     %u", avih->streams);
1180   GST_INFO_OBJECT (avi, " bufsize     %u", avih->bufsize);
1181   GST_INFO_OBJECT (avi, " width       %u", avih->width);
1182   GST_INFO_OBJECT (avi, " height      %u", avih->height);
1183   GST_INFO_OBJECT (avi, " scale       %u", avih->scale);
1184   GST_INFO_OBJECT (avi, " rate        %u", avih->rate);
1185   GST_INFO_OBJECT (avi, " start       %u", avih->start);
1186   GST_INFO_OBJECT (avi, " length      %u", avih->length);
1187
1188   *_avih = avih;
1189   gst_buffer_unref (buf);
1190
1191   if (avih->us_frame != 0 && avih->tot_frames != 0)
1192     avi->duration =
1193         (guint64) avih->us_frame * (guint64) avih->tot_frames * 1000;
1194   else
1195     avi->duration = GST_CLOCK_TIME_NONE;
1196
1197   GST_INFO_OBJECT (avi, " header duration  %" GST_TIME_FORMAT,
1198       GST_TIME_ARGS (avi->duration));
1199
1200   return TRUE;
1201
1202   /* ERRORS */
1203 no_buffer:
1204   {
1205     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("No buffer"));
1206     return FALSE;
1207   }
1208 avih_too_small:
1209   {
1210     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1211         ("Too small avih (%" G_GSIZE_FORMAT " available, %d needed)",
1212             size, (int) sizeof (gst_riff_avih)));
1213     gst_buffer_unref (buf);
1214     return FALSE;
1215   }
1216 }
1217
1218 /*
1219  * gst_avi_demux_parse_superindex:
1220  * @avi: caller element (used for debugging/errors).
1221  * @buf: input data to use for parsing.
1222  * @locations: locations in the file (byte-offsets) that contain
1223  *             the actual indexes (see get_avi_demux_parse_subindex()).
1224  *             The array ends with GST_BUFFER_OFFSET_NONE.
1225  *
1226  * Reads superindex (openDML-2 spec stuff) from the provided data.
1227  *
1228  * Returns: TRUE on success, FALSE otherwise. Indexes should be skipped
1229  *          on error, but they are not fatal.
1230  */
1231 static gboolean
1232 gst_avi_demux_parse_superindex (GstAviDemux * avi,
1233     GstBuffer * buf, guint64 ** _indexes)
1234 {
1235   GstMapInfo map;
1236   guint8 *data;
1237   guint16 bpe = 16;
1238   guint32 num, i;
1239   guint64 *indexes;
1240   gsize size;
1241
1242   *_indexes = NULL;
1243
1244   if (buf) {
1245     gst_buffer_map (buf, &map, GST_MAP_READ);
1246     data = map.data;
1247     size = map.size;
1248   } else {
1249     data = NULL;
1250     size = 0;
1251   }
1252
1253   if (size < 24)
1254     goto too_small;
1255
1256   /* check type of index. The opendml2 specs state that
1257    * there should be 4 dwords per array entry. Type can be
1258    * either frame or field (and we don't care). */
1259   if (GST_READ_UINT16_LE (data) != 4 ||
1260       (data[2] & 0xfe) != 0x0 || data[3] != 0x0) {
1261     GST_WARNING_OBJECT (avi,
1262         "Superindex for stream has unexpected "
1263         "size_entry %d (bytes) or flags 0x%02x/0x%02x",
1264         GST_READ_UINT16_LE (data), data[2], data[3]);
1265     bpe = GST_READ_UINT16_LE (data) * 4;
1266   }
1267   num = GST_READ_UINT32_LE (&data[4]);
1268
1269   GST_DEBUG_OBJECT (avi, "got %d indexes", num);
1270
1271   /* this can't work out well ... */
1272   if (num > G_MAXUINT32 >> 1 || bpe < 8) {
1273     goto invalid_params;
1274   }
1275
1276   indexes = g_new (guint64, num + 1);
1277   for (i = 0; i < num; i++) {
1278     if (size < 24 + bpe * (i + 1))
1279       break;
1280     indexes[i] = GST_READ_UINT64_LE (&data[24 + bpe * i]);
1281     GST_DEBUG_OBJECT (avi, "index %d at %" G_GUINT64_FORMAT, i, indexes[i]);
1282   }
1283   indexes[i] = GST_BUFFER_OFFSET_NONE;
1284   *_indexes = indexes;
1285
1286   gst_buffer_unmap (buf, &map);
1287   gst_buffer_unref (buf);
1288
1289   return TRUE;
1290
1291   /* ERRORS */
1292 too_small:
1293   {
1294     GST_ERROR_OBJECT (avi,
1295         "Not enough data to parse superindex (%" G_GSIZE_FORMAT
1296         " available, 24 needed)", size);
1297     if (buf) {
1298       gst_buffer_unmap (buf, &map);
1299       gst_buffer_unref (buf);
1300     }
1301     return FALSE;
1302   }
1303 invalid_params:
1304   {
1305     GST_ERROR_OBJECT (avi, "invalid index parameters (num = %d, bpe = %d)",
1306         num, bpe);
1307     gst_buffer_unmap (buf, &map);
1308     gst_buffer_unref (buf);
1309     return FALSE;
1310   }
1311 }
1312
1313 /* add an entry to the index of a stream. @num should be an estimate of the
1314  * total amount of index entries for all streams and is used to dynamically
1315  * allocate memory for the index entries. */
1316 static inline gboolean
1317 gst_avi_demux_add_index (GstAviDemux * avi, GstAviStream * stream,
1318     guint num, GstAviIndexEntry * entry)
1319 {
1320   /* ensure index memory */
1321   if (G_UNLIKELY (stream->idx_n >= stream->idx_max)) {
1322     guint idx_max = stream->idx_max;
1323     GstAviIndexEntry *new_idx;
1324
1325     /* we need to make some more room */
1326     if (idx_max == 0) {
1327       /* initial size guess, assume each stream has an equal amount of entries,
1328        * overshoot with at least 8K */
1329       idx_max = (num / avi->num_streams) + (8192 / sizeof (GstAviIndexEntry));
1330     } else {
1331       idx_max += 8192 / sizeof (GstAviIndexEntry);
1332       GST_DEBUG_OBJECT (avi, "expanded index from %u to %u",
1333           stream->idx_max, idx_max);
1334     }
1335     new_idx = g_try_renew (GstAviIndexEntry, stream->index, idx_max);
1336     /* out of memory, if this fails stream->index is untouched. */
1337     if (G_UNLIKELY (!new_idx))
1338       return FALSE;
1339     /* use new index */
1340     stream->index = new_idx;
1341     stream->idx_max = idx_max;
1342   }
1343
1344   /* update entry total and stream stats. The entry total can be converted to
1345    * the timestamp of the entry easily. */
1346   if (stream->strh->type == GST_RIFF_FCC_auds) {
1347     gint blockalign;
1348
1349     if (stream->is_vbr) {
1350       entry->total = stream->total_blocks;
1351     } else {
1352       entry->total = stream->total_bytes;
1353     }
1354     blockalign = stream->strf.auds->blockalign;
1355     if (blockalign > 0)
1356       stream->total_blocks += DIV_ROUND_UP (entry->size, blockalign);
1357     else
1358       stream->total_blocks++;
1359   } else {
1360     if (stream->is_vbr) {
1361       entry->total = stream->idx_n;
1362     } else {
1363       entry->total = stream->total_bytes;
1364     }
1365   }
1366   stream->total_bytes += entry->size;
1367   if (ENTRY_IS_KEYFRAME (entry))
1368     stream->n_keyframes++;
1369
1370   /* and add */
1371   GST_LOG_OBJECT (avi,
1372       "Adding stream %u, index entry %d, kf %d, size %u "
1373       ", offset %" G_GUINT64_FORMAT ", total %" G_GUINT64_FORMAT, stream->num,
1374       stream->idx_n, ENTRY_IS_KEYFRAME (entry), entry->size, entry->offset,
1375       entry->total);
1376   stream->index[stream->idx_n++] = *entry;
1377
1378   return TRUE;
1379 }
1380
1381 /* given @entry_n in @stream, calculate info such as timestamps and
1382  * offsets for the entry. */
1383 static void
1384 gst_avi_demux_get_buffer_info (GstAviDemux * avi, GstAviStream * stream,
1385     guint entry_n, GstClockTime * timestamp, GstClockTime * ts_end,
1386     guint64 * offset, guint64 * offset_end)
1387 {
1388   GstAviIndexEntry *entry;
1389
1390   entry = &stream->index[entry_n];
1391
1392   if (stream->is_vbr) {
1393     /* VBR stream next timestamp */
1394     if (stream->strh->type == GST_RIFF_FCC_auds) {
1395       if (timestamp)
1396         *timestamp =
1397             avi_stream_convert_frames_to_time_unchecked (stream, entry->total);
1398       if (ts_end) {
1399         gint size = 1;
1400         if (G_LIKELY (entry_n + 1 < stream->idx_n))
1401           size = stream->index[entry_n + 1].total - entry->total;
1402         *ts_end = avi_stream_convert_frames_to_time_unchecked (stream,
1403             entry->total + size);
1404       }
1405     } else {
1406       if (timestamp)
1407         *timestamp =
1408             avi_stream_convert_frames_to_time_unchecked (stream, entry_n);
1409       if (ts_end)
1410         *ts_end = avi_stream_convert_frames_to_time_unchecked (stream,
1411             entry_n + 1);
1412     }
1413   } else if (stream->strh->type == GST_RIFF_FCC_auds) {
1414     /* constant rate stream */
1415     if (timestamp)
1416       *timestamp =
1417           avi_stream_convert_bytes_to_time_unchecked (stream, entry->total);
1418     if (ts_end)
1419       *ts_end = avi_stream_convert_bytes_to_time_unchecked (stream,
1420           entry->total + entry->size);
1421   }
1422   if (stream->strh->type == GST_RIFF_FCC_vids) {
1423     /* video offsets are the frame number */
1424     if (offset)
1425       *offset = entry_n;
1426     if (offset_end)
1427       *offset_end = entry_n + 1;
1428   } else {
1429     /* no offsets for audio */
1430     if (offset)
1431       *offset = -1;
1432     if (offset_end)
1433       *offset_end = -1;
1434   }
1435 }
1436
1437 /* collect and debug stats about the indexes for all streams.
1438  * This method is also responsible for filling in the stream duration
1439  * as measured by the amount of index entries.
1440  *
1441  * Returns TRUE if the index is not empty, else FALSE */
1442 static gboolean
1443 gst_avi_demux_do_index_stats (GstAviDemux * avi)
1444 {
1445   guint total_idx = 0;
1446   guint i;
1447 #ifndef GST_DISABLE_GST_DEBUG
1448   guint total_max = 0;
1449 #endif
1450
1451   /* get stream stats now */
1452   for (i = 0; i < avi->num_streams; i++) {
1453     GstAviStream *stream;
1454
1455     if (G_UNLIKELY (!(stream = &avi->stream[i])))
1456       continue;
1457     if (G_UNLIKELY (!stream->strh))
1458       continue;
1459     if (G_UNLIKELY (!stream->index || stream->idx_n == 0))
1460       continue;
1461
1462     /* we interested in the end_ts of the last entry, which is the total
1463      * duration of this stream */
1464     gst_avi_demux_get_buffer_info (avi, stream, stream->idx_n - 1,
1465         NULL, &stream->idx_duration, NULL, NULL);
1466
1467     total_idx += stream->idx_n;
1468 #ifndef GST_DISABLE_GST_DEBUG
1469     total_max += stream->idx_max;
1470 #endif
1471     GST_INFO_OBJECT (avi, "Stream %d, dur %" GST_TIME_FORMAT ", %6u entries, "
1472         "%5u keyframes, entry size = %2u, total size = %10u, allocated %10u",
1473         i, GST_TIME_ARGS (stream->idx_duration), stream->idx_n,
1474         stream->n_keyframes, (guint) sizeof (GstAviIndexEntry),
1475         (guint) (stream->idx_n * sizeof (GstAviIndexEntry)),
1476         (guint) (stream->idx_max * sizeof (GstAviIndexEntry)));
1477   }
1478   total_idx *= sizeof (GstAviIndexEntry);
1479 #ifndef GST_DISABLE_GST_DEBUG
1480   total_max *= sizeof (GstAviIndexEntry);
1481 #endif
1482   GST_INFO_OBJECT (avi, "%u bytes for index vs %u ideally, %u wasted",
1483       total_max, total_idx, total_max - total_idx);
1484
1485   if (total_idx == 0) {
1486     GST_WARNING_OBJECT (avi, "Index is empty !");
1487     return FALSE;
1488   }
1489   return TRUE;
1490 }
1491
1492 /*
1493  * gst_avi_demux_parse_subindex:
1494  * @avi: Avi object
1495  * @buf: input data to use for parsing.
1496  * @stream: stream context.
1497  * @entries_list: a list (returned by the function) containing all the
1498  *           indexes parsed in this specific subindex. The first
1499  *           entry is also a pointer to allocated memory that needs
1500  *           to be free´ed. May be NULL if no supported indexes were
1501  *           found.
1502  *
1503  * Reads superindex (openDML-2 spec stuff) from the provided data.
1504  * The buffer should contain a GST_RIFF_TAG_ix?? chunk.
1505  *
1506  * Returns: TRUE on success, FALSE otherwise. Errors are fatal, we
1507  *          throw an error, caller should bail out asap.
1508  */
1509 static gboolean
1510 gst_avi_demux_parse_subindex (GstAviDemux * avi, GstAviStream * stream,
1511     GstBuffer * buf)
1512 {
1513   GstMapInfo map;
1514   guint8 *data;
1515   guint16 bpe;
1516   guint32 num, i;
1517   guint64 baseoff;
1518
1519   if (buf == NULL)
1520     return TRUE;
1521
1522   gst_buffer_map (buf, &map, GST_MAP_READ);
1523   data = map.data;
1524
1525   /* check size */
1526   if (map.size < 24)
1527     goto too_small;
1528
1529   /* We don't support index-data yet */
1530   if (data[3] & 0x80)
1531     goto not_implemented;
1532
1533   /* check type of index. The opendml2 specs state that
1534    * there should be 4 dwords per array entry. Type can be
1535    * either frame or field (and we don't care). */
1536   bpe = (data[2] & 0x01) ? 12 : 8;
1537   if (GST_READ_UINT16_LE (data) != bpe / 4 ||
1538       (data[2] & 0xfe) != 0x0 || data[3] != 0x1) {
1539     GST_WARNING_OBJECT (avi,
1540         "Superindex for stream %d has unexpected "
1541         "size_entry %d (bytes) or flags 0x%02x/0x%02x",
1542         stream->num, GST_READ_UINT16_LE (data), data[2], data[3]);
1543     bpe = GST_READ_UINT16_LE (data) * 4;
1544   }
1545   num = GST_READ_UINT32_LE (&data[4]);
1546   baseoff = GST_READ_UINT64_LE (&data[12]);
1547
1548   /* If there's nothing, just return ! */
1549   if (num == 0)
1550     goto empty_index;
1551
1552   GST_INFO_OBJECT (avi, "Parsing subindex, nr_entries = %6d", num);
1553
1554   for (i = 0; i < num; i++) {
1555     GstAviIndexEntry entry;
1556
1557     if (map.size < 24 + bpe * (i + 1))
1558       break;
1559
1560     /* fill in offset and size. offset contains the keyframe flag in the
1561      * upper bit*/
1562     entry.offset = baseoff + GST_READ_UINT32_LE (&data[24 + bpe * i]);
1563     entry.size = GST_READ_UINT32_LE (&data[24 + bpe * i + 4]);
1564     /* handle flags */
1565     if (stream->strh->type == GST_RIFF_FCC_auds) {
1566       /* all audio frames are keyframes */
1567       ENTRY_SET_KEYFRAME (&entry);
1568     } else {
1569       /* else read flags */
1570       entry.flags = (entry.size & 0x80000000) ? 0 : GST_AVI_KEYFRAME;
1571     }
1572     entry.size &= ~0x80000000;
1573
1574     /* and add */
1575     if (G_UNLIKELY (!gst_avi_demux_add_index (avi, stream, num, &entry)))
1576       goto out_of_mem;
1577   }
1578 done:
1579   gst_buffer_unmap (buf, &map);
1580   gst_buffer_unref (buf);
1581
1582   return TRUE;
1583
1584   /* ERRORS */
1585 too_small:
1586   {
1587     GST_ERROR_OBJECT (avi,
1588         "Not enough data to parse subindex (%" G_GSIZE_FORMAT
1589         " available, 24 needed)", map.size);
1590     goto done;                  /* continue */
1591   }
1592 not_implemented:
1593   {
1594     GST_ELEMENT_ERROR (avi, STREAM, NOT_IMPLEMENTED, (NULL),
1595         ("Subindex-is-data is not implemented"));
1596     gst_buffer_unmap (buf, &map);
1597     gst_buffer_unref (buf);
1598     return FALSE;
1599   }
1600 empty_index:
1601   {
1602     GST_DEBUG_OBJECT (avi, "the index is empty");
1603     goto done;                  /* continue */
1604   }
1605 out_of_mem:
1606   {
1607     GST_ELEMENT_ERROR (avi, RESOURCE, NO_SPACE_LEFT, (NULL),
1608         ("Cannot allocate memory for %u*%u=%u bytes",
1609             (guint) sizeof (GstAviIndexEntry), num,
1610             (guint) sizeof (GstAviIndexEntry) * num));
1611     gst_buffer_unmap (buf, &map);
1612     gst_buffer_unref (buf);
1613     return FALSE;
1614   }
1615 }
1616
1617 /*
1618  * Create and push a flushing seek event upstream
1619  */
1620 static gboolean
1621 perform_seek_to_offset (GstAviDemux * demux, guint64 offset, guint32 seqnum)
1622 {
1623   GstEvent *event;
1624   gboolean res = 0;
1625
1626   GST_DEBUG_OBJECT (demux, "Seeking to %" G_GUINT64_FORMAT, offset);
1627
1628   event =
1629       gst_event_new_seek (1.0, GST_FORMAT_BYTES,
1630       GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
1631       GST_SEEK_TYPE_NONE, -1);
1632   gst_event_set_seqnum (event, seqnum);
1633   res = gst_pad_push_event (demux->sinkpad, event);
1634
1635   if (res)
1636     demux->offset = offset;
1637   return res;
1638 }
1639
1640 /*
1641  * Read AVI index when streaming
1642  */
1643 static gboolean
1644 gst_avi_demux_read_subindexes_push (GstAviDemux * avi)
1645 {
1646   guint32 tag = 0, size;
1647   GstBuffer *buf = NULL;
1648   guint odml_stream;
1649
1650   GST_DEBUG_OBJECT (avi, "read subindexes for %d streams", avi->num_streams);
1651
1652   if (avi->odml_subidxs[avi->odml_subidx] != avi->offset)
1653     return FALSE;
1654
1655   if (!gst_avi_demux_peek_chunk (avi, &tag, &size))
1656     return TRUE;
1657
1658   /* this is the ODML chunk we expect */
1659   odml_stream = avi->odml_stream;
1660
1661   if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + odml_stream / 10,
1662               '0' + odml_stream % 10)) &&
1663       (tag != GST_MAKE_FOURCC ('0' + odml_stream / 10,
1664               '0' + odml_stream % 10, 'i', 'x'))) {
1665     GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")",
1666         GST_FOURCC_ARGS (tag));
1667     return FALSE;
1668   }
1669
1670   avi->offset += 8 + GST_ROUND_UP_2 (size);
1671   /* flush chunk header so we get just the 'size' payload data */
1672   gst_adapter_flush (avi->adapter, 8);
1673   buf = gst_adapter_take_buffer (avi->adapter, size);
1674
1675   if (!gst_avi_demux_parse_subindex (avi, &avi->stream[odml_stream], buf))
1676     return FALSE;
1677
1678   /* we parsed the index, go to next subindex */
1679   avi->odml_subidx++;
1680
1681   if (avi->odml_subidxs[avi->odml_subidx] == GST_BUFFER_OFFSET_NONE) {
1682     /* we reached the end of the indexes for this stream, move to the next
1683      * stream to handle the first index */
1684     avi->odml_stream++;
1685     avi->odml_subidx = 0;
1686
1687     if (avi->odml_stream < avi->num_streams) {
1688       /* there are more indexes */
1689       avi->odml_subidxs = avi->stream[avi->odml_stream].indexes;
1690     } else {
1691       /* we're done, get stream stats now */
1692       avi->have_index = gst_avi_demux_do_index_stats (avi);
1693
1694       return TRUE;
1695     }
1696   }
1697
1698   /* seek to next index */
1699   return perform_seek_to_offset (avi, avi->odml_subidxs[avi->odml_subidx],
1700       avi->segment_seqnum);
1701 }
1702
1703 /*
1704  * Read AVI index
1705  */
1706 static void
1707 gst_avi_demux_read_subindexes_pull (GstAviDemux * avi)
1708 {
1709   guint32 tag;
1710   GstBuffer *buf;
1711   gint i, n;
1712
1713   GST_DEBUG_OBJECT (avi, "read subindexes for %d streams", avi->num_streams);
1714
1715   for (n = 0; n < avi->num_streams; n++) {
1716     GstAviStream *stream = &avi->stream[n];
1717
1718     if (stream->indexes == NULL)
1719       continue;
1720
1721     for (i = 0; stream->indexes[i] != GST_BUFFER_OFFSET_NONE; i++) {
1722       if (gst_riff_read_chunk (GST_ELEMENT_CAST (avi), avi->sinkpad,
1723               &stream->indexes[i], &tag, &buf) != GST_FLOW_OK)
1724         continue;
1725       else if ((tag != GST_MAKE_FOURCC ('i', 'x', '0' + stream->num / 10,
1726                   '0' + stream->num % 10)) &&
1727           (tag != GST_MAKE_FOURCC ('0' + stream->num / 10,
1728                   '0' + stream->num % 10, 'i', 'x'))) {
1729         /* Some ODML files (created by god knows what muxer) have a ##ix format
1730          * instead of the 'official' ix##. They are still valid though. */
1731         GST_WARNING_OBJECT (avi, "Not an ix## chunk (%" GST_FOURCC_FORMAT ")",
1732             GST_FOURCC_ARGS (tag));
1733         gst_buffer_unref (buf);
1734         continue;
1735       }
1736
1737       if (!gst_avi_demux_parse_subindex (avi, stream, buf))
1738         continue;
1739     }
1740
1741     g_free (stream->indexes);
1742     stream->indexes = NULL;
1743   }
1744   /* get stream stats now */
1745   avi->have_index = gst_avi_demux_do_index_stats (avi);
1746 }
1747
1748 /*
1749  * gst_avi_demux_riff_parse_vprp:
1750  * @element: caller element (used for debugging/error).
1751  * @buf: input data to be used for parsing, stripped from header.
1752  * @vprp: a pointer (returned by this function) to a filled-in vprp
1753  *        structure. Caller should free it.
1754  *
1755  * Parses a video stream´s vprp. This function takes ownership of @buf.
1756  *
1757  * Returns: TRUE if parsing succeeded, otherwise FALSE. The stream
1758  *          should be skipped on error, but it is not fatal.
1759  */
1760 static gboolean
1761 gst_avi_demux_riff_parse_vprp (GstElement * element,
1762     GstBuffer * buf, gst_riff_vprp ** _vprp)
1763 {
1764   gst_riff_vprp *vprp;
1765   gint k;
1766   gsize size;
1767
1768   g_return_val_if_fail (buf != NULL, FALSE);
1769   g_return_val_if_fail (_vprp != NULL, FALSE);
1770
1771   size = gst_buffer_get_size (buf);
1772
1773   if (size < G_STRUCT_OFFSET (gst_riff_vprp, field_info))
1774     goto too_small;
1775
1776   vprp = g_malloc (size);
1777   gst_buffer_extract (buf, 0, vprp, size);
1778
1779 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
1780   vprp->format_token = GUINT32_FROM_LE (vprp->format_token);
1781   vprp->standard = GUINT32_FROM_LE (vprp->standard);
1782   vprp->vert_rate = GUINT32_FROM_LE (vprp->vert_rate);
1783   vprp->hor_t_total = GUINT32_FROM_LE (vprp->hor_t_total);
1784   vprp->vert_lines = GUINT32_FROM_LE (vprp->vert_lines);
1785   vprp->aspect = GUINT32_FROM_LE (vprp->aspect);
1786   vprp->width = GUINT32_FROM_LE (vprp->width);
1787   vprp->height = GUINT32_FROM_LE (vprp->height);
1788   vprp->fields = GUINT32_FROM_LE (vprp->fields);
1789 #endif
1790
1791   /* size checking */
1792   /* calculate fields based on size */
1793   k = (size - G_STRUCT_OFFSET (gst_riff_vprp, field_info)) / vprp->fields;
1794   if (vprp->fields > k) {
1795     GST_WARNING_OBJECT (element,
1796         "vprp header indicated %d fields, only %d available", vprp->fields, k);
1797     vprp->fields = k;
1798   }
1799   if (vprp->fields > GST_RIFF_VPRP_VIDEO_FIELDS) {
1800     GST_WARNING_OBJECT (element,
1801         "vprp header indicated %d fields, at most %d supported", vprp->fields,
1802         GST_RIFF_VPRP_VIDEO_FIELDS);
1803     vprp->fields = GST_RIFF_VPRP_VIDEO_FIELDS;
1804   }
1805 #if (G_BYTE_ORDER == G_BIG_ENDIAN)
1806   for (k = 0; k < vprp->fields; k++) {
1807     gst_riff_vprp_video_field_desc *fd;
1808
1809     fd = &vprp->field_info[k];
1810     fd->compressed_bm_height = GUINT32_FROM_LE (fd->compressed_bm_height);
1811     fd->compressed_bm_width = GUINT32_FROM_LE (fd->compressed_bm_width);
1812     fd->valid_bm_height = GUINT32_FROM_LE (fd->valid_bm_height);
1813     fd->valid_bm_width = GUINT16_FROM_LE (fd->valid_bm_width);
1814     fd->valid_bm_x_offset = GUINT16_FROM_LE (fd->valid_bm_x_offset);
1815     fd->valid_bm_y_offset = GUINT32_FROM_LE (fd->valid_bm_y_offset);
1816     fd->video_x_t_offset = GUINT32_FROM_LE (fd->video_x_t_offset);
1817     fd->video_y_start = GUINT32_FROM_LE (fd->video_y_start);
1818   }
1819 #endif
1820
1821   /* debug */
1822   GST_INFO_OBJECT (element, "vprp tag found in context vids:");
1823   GST_INFO_OBJECT (element, " format_token  %d", vprp->format_token);
1824   GST_INFO_OBJECT (element, " standard      %d", vprp->standard);
1825   GST_INFO_OBJECT (element, " vert_rate     %d", vprp->vert_rate);
1826   GST_INFO_OBJECT (element, " hor_t_total   %d", vprp->hor_t_total);
1827   GST_INFO_OBJECT (element, " vert_lines    %d", vprp->vert_lines);
1828   GST_INFO_OBJECT (element, " aspect        %d:%d", vprp->aspect >> 16,
1829       vprp->aspect & 0xffff);
1830   GST_INFO_OBJECT (element, " width         %d", vprp->width);
1831   GST_INFO_OBJECT (element, " height        %d", vprp->height);
1832   GST_INFO_OBJECT (element, " fields        %d", vprp->fields);
1833   for (k = 0; k < vprp->fields; k++) {
1834     gst_riff_vprp_video_field_desc *fd;
1835
1836     fd = &(vprp->field_info[k]);
1837     GST_INFO_OBJECT (element, " field %u description:", k);
1838     GST_INFO_OBJECT (element, "  compressed_bm_height  %d",
1839         fd->compressed_bm_height);
1840     GST_INFO_OBJECT (element, "  compressed_bm_width  %d",
1841         fd->compressed_bm_width);
1842     GST_INFO_OBJECT (element, "  valid_bm_height       %d",
1843         fd->valid_bm_height);
1844     GST_INFO_OBJECT (element, "  valid_bm_width        %d", fd->valid_bm_width);
1845     GST_INFO_OBJECT (element, "  valid_bm_x_offset     %d",
1846         fd->valid_bm_x_offset);
1847     GST_INFO_OBJECT (element, "  valid_bm_y_offset     %d",
1848         fd->valid_bm_y_offset);
1849     GST_INFO_OBJECT (element, "  video_x_t_offset      %d",
1850         fd->video_x_t_offset);
1851     GST_INFO_OBJECT (element, "  video_y_start         %d", fd->video_y_start);
1852   }
1853
1854   gst_buffer_unref (buf);
1855
1856   *_vprp = vprp;
1857
1858   return TRUE;
1859
1860   /* ERRORS */
1861 too_small:
1862   {
1863     GST_ERROR_OBJECT (element,
1864         "Too small vprp (%" G_GSIZE_FORMAT " available, at least %d needed)",
1865         size, (int) G_STRUCT_OFFSET (gst_riff_vprp, field_info));
1866     gst_buffer_unref (buf);
1867     return FALSE;
1868   }
1869 }
1870
1871 static void
1872 gst_avi_demux_expose_streams (GstAviDemux * avi, gboolean force)
1873 {
1874   guint i;
1875
1876   GST_DEBUG_OBJECT (avi, "force : %d", force);
1877
1878   for (i = 0; i < avi->num_streams; i++) {
1879     GstAviStream *stream = &avi->stream[i];
1880
1881     if (force || stream->idx_n != 0) {
1882       GST_LOG_OBJECT (avi, "Adding pad %s", GST_PAD_NAME (stream->pad));
1883       gst_element_add_pad ((GstElement *) avi, stream->pad);
1884       gst_flow_combiner_add_pad (avi->flowcombiner, stream->pad);
1885
1886 #if 0
1887       if (avi->element_index)
1888         gst_index_get_writer_id (avi->element_index,
1889             GST_OBJECT_CAST (stream->pad), &stream->index_id);
1890 #endif
1891
1892       stream->exposed = TRUE;
1893       if (avi->main_stream == -1)
1894         avi->main_stream = i;
1895     } else {
1896       GST_WARNING_OBJECT (avi, "Stream #%d doesn't have any entry, removing it",
1897           i);
1898       gst_avi_demux_reset_stream (avi, stream);
1899     }
1900   }
1901 }
1902
1903 /* buf contains LIST chunk data, and will be padded to even size,
1904  * since some buggy files do not account for the padding of chunks
1905  * within a LIST in the size of the LIST */
1906 static inline void
1907 gst_avi_demux_roundup_list (GstAviDemux * avi, GstBuffer ** buf)
1908 {
1909   gsize size;
1910
1911   size = gst_buffer_get_size (*buf);
1912
1913   if (G_UNLIKELY (size & 1)) {
1914     GstBuffer *obuf;
1915     GstMapInfo map;
1916
1917     GST_DEBUG_OBJECT (avi, "rounding up dubious list size %" G_GSIZE_FORMAT,
1918         size);
1919     obuf = gst_buffer_new_and_alloc (size + 1);
1920
1921     gst_buffer_map (obuf, &map, GST_MAP_WRITE);
1922     gst_buffer_extract (*buf, 0, map.data, size);
1923     /* assume 0 padding, at least makes outcome deterministic */
1924     map.data[size] = 0;
1925     gst_buffer_unmap (obuf, &map);
1926     gst_buffer_replace (buf, obuf);
1927   }
1928 }
1929
1930 static GstCaps *
1931 gst_avi_demux_check_caps (GstAviDemux * avi, GstAviStream * stream,
1932     GstCaps * caps)
1933 {
1934   GstStructure *s;
1935   const GValue *val;
1936   GstBuffer *buf;
1937
1938   caps = gst_caps_make_writable (caps);
1939
1940   s = gst_caps_get_structure (caps, 0);
1941   if (gst_structure_has_name (s, "video/x-raw")) {
1942     stream->is_raw = TRUE;
1943     stream->alignment = 32;
1944     if (!gst_structure_has_field (s, "pixel-aspect-ratio"))
1945       gst_structure_set (s, "pixel-aspect-ratio", GST_TYPE_FRACTION,
1946           1, 1, NULL);
1947     if (gst_structure_has_field_typed (s, "palette_data", GST_TYPE_BUFFER)) {
1948       gst_structure_get (s, "palette_data", GST_TYPE_BUFFER,
1949           &stream->rgb8_palette, NULL);
1950       gst_structure_remove_field (s, "palette_data");
1951       return caps;
1952     }
1953   } else if (!gst_structure_has_name (s, "video/x-h264")) {
1954     return caps;
1955   }
1956
1957   GST_DEBUG_OBJECT (avi, "checking caps %" GST_PTR_FORMAT, caps);
1958
1959   /* some muxers put invalid bytestream stuff in h264 extra data */
1960   val = gst_structure_get_value (s, "codec_data");
1961   if (val && (buf = gst_value_get_buffer (val))) {
1962     guint8 *data;
1963     gint size;
1964     GstMapInfo map;
1965
1966     gst_buffer_map (buf, &map, GST_MAP_READ);
1967     data = map.data;
1968     size = map.size;
1969     if (size >= 4) {
1970       guint32 h = GST_READ_UINT32_BE (data);
1971       gst_buffer_unmap (buf, &map);
1972       if (h == 0x01) {
1973         /* can hardly be valid AVC codec data */
1974         GST_DEBUG_OBJECT (avi,
1975             "discarding invalid codec_data containing byte-stream");
1976         /* so do not pretend to downstream that it is packetized avc */
1977         gst_structure_remove_field (s, "codec_data");
1978         /* ... but rather properly parsed bytestream */
1979         gst_structure_set (s, "stream-format", G_TYPE_STRING, "byte-stream",
1980             "alignment", G_TYPE_STRING, "au", NULL);
1981       }
1982     } else {
1983       gst_buffer_unmap (buf, &map);
1984     }
1985   }
1986
1987   return caps;
1988 }
1989
1990 /*
1991  * gst_avi_demux_parse_stream:
1992  * @avi: calling element (used for debugging/errors).
1993  * @buf: input buffer used to parse the stream.
1994  *
1995  * Parses all subchunks in a strl chunk (which defines a single
1996  * stream). Discards the buffer after use. This function will
1997  * increment the stream counter internally.
1998  *
1999  * Returns: whether the stream was identified successfully.
2000  *          Errors are not fatal. It does indicate the stream
2001  *          was skipped.
2002  */
2003 static gboolean
2004 gst_avi_demux_parse_stream (GstAviDemux * avi, GstBuffer * buf)
2005 {
2006   GstAviStream *stream;
2007   GstElementClass *klass;
2008   GstPadTemplate *templ;
2009   GstBuffer *sub = NULL;
2010   guint offset = 4;
2011   guint32 tag = 0;
2012   gchar *codec_name = NULL, *padname = NULL;
2013   const gchar *tag_name;
2014   GstCaps *caps = NULL;
2015   GstPad *pad;
2016   GstElement *element;
2017   gboolean got_strh = FALSE, got_strf = FALSE, got_vprp = FALSE;
2018   gst_riff_vprp *vprp = NULL;
2019   GstEvent *event;
2020   gchar *stream_id;
2021   GstMapInfo map;
2022   gboolean sparse = FALSE;
2023
2024   element = GST_ELEMENT_CAST (avi);
2025
2026   GST_DEBUG_OBJECT (avi, "Parsing stream");
2027
2028   gst_avi_demux_roundup_list (avi, &buf);
2029
2030   if (avi->num_streams >= GST_AVI_DEMUX_MAX_STREAMS) {
2031     GST_WARNING_OBJECT (avi,
2032         "maximum no of streams (%d) exceeded, ignoring stream",
2033         GST_AVI_DEMUX_MAX_STREAMS);
2034     gst_buffer_unref (buf);
2035     /* not a fatal error, let's say */
2036     return TRUE;
2037   }
2038
2039   stream = &avi->stream[avi->num_streams];
2040
2041   /* initial settings */
2042   stream->idx_duration = GST_CLOCK_TIME_NONE;
2043   stream->hdr_duration = GST_CLOCK_TIME_NONE;
2044   stream->duration = GST_CLOCK_TIME_NONE;
2045
2046   while (gst_riff_parse_chunk (element, buf, &offset, &tag, &sub)) {
2047     /* sub can be NULL if the chunk is empty */
2048     if (sub == NULL) {
2049       GST_DEBUG_OBJECT (avi, "ignoring empty chunk %" GST_FOURCC_FORMAT,
2050           GST_FOURCC_ARGS (tag));
2051       continue;
2052     }
2053     switch (tag) {
2054       case GST_RIFF_TAG_strh:
2055       {
2056         gst_riff_strh *strh;
2057
2058         if (got_strh) {
2059           GST_WARNING_OBJECT (avi, "Ignoring additional strh chunk");
2060           break;
2061         }
2062         if (!gst_riff_parse_strh (element, sub, &stream->strh)) {
2063           /* ownership given away */
2064           sub = NULL;
2065           GST_WARNING_OBJECT (avi, "Failed to parse strh chunk");
2066           goto fail;
2067         }
2068         sub = NULL;
2069         strh = stream->strh;
2070         /* sanity check; stream header frame rate matches global header
2071          * frame duration */
2072         if (stream->strh->type == GST_RIFF_FCC_vids) {
2073           GstClockTime s_dur;
2074           GstClockTime h_dur = avi->avih->us_frame * GST_USECOND;
2075
2076           s_dur = gst_util_uint64_scale (GST_SECOND, strh->scale, strh->rate);
2077           GST_DEBUG_OBJECT (avi, "verifying stream framerate %d/%d, "
2078               "frame duration = %d ms", strh->rate, strh->scale,
2079               (gint) (s_dur / GST_MSECOND));
2080           if (h_dur > (10 * GST_MSECOND) && (s_dur > 10 * h_dur)) {
2081             strh->rate = GST_SECOND / GST_USECOND;
2082             strh->scale = h_dur / GST_USECOND;
2083             GST_DEBUG_OBJECT (avi, "correcting stream framerate to %d/%d",
2084                 strh->rate, strh->scale);
2085           }
2086         }
2087         /* determine duration as indicated by header */
2088         stream->hdr_duration = gst_util_uint64_scale ((guint64) strh->length *
2089             strh->scale, GST_SECOND, (guint64) strh->rate);
2090         GST_INFO ("Stream duration according to header: %" GST_TIME_FORMAT,
2091             GST_TIME_ARGS (stream->hdr_duration));
2092         if (stream->hdr_duration == 0)
2093           stream->hdr_duration = GST_CLOCK_TIME_NONE;
2094
2095         got_strh = TRUE;
2096         break;
2097       }
2098       case GST_RIFF_TAG_strf:
2099       {
2100         gboolean res = FALSE;
2101
2102         if (got_strf) {
2103           GST_WARNING_OBJECT (avi, "Ignoring additional strf chunk");
2104           break;
2105         }
2106         if (!got_strh) {
2107           GST_ERROR_OBJECT (avi, "Found strf chunk before strh chunk");
2108           goto fail;
2109         }
2110         switch (stream->strh->type) {
2111           case GST_RIFF_FCC_vids:
2112             stream->is_vbr = TRUE;
2113             res = gst_riff_parse_strf_vids (element, sub,
2114                 &stream->strf.vids, &stream->extradata);
2115             sub = NULL;
2116             GST_DEBUG_OBJECT (element, "marking video as VBR, res %d", res);
2117             break;
2118           case GST_RIFF_FCC_auds:
2119             res =
2120                 gst_riff_parse_strf_auds (element, sub, &stream->strf.auds,
2121                 &stream->extradata);
2122             sub = NULL;
2123             if (!res)
2124               break;
2125             stream->is_vbr = (stream->strh->samplesize == 0)
2126                 && stream->strh->scale > 1
2127                 && stream->strf.auds->blockalign != 1;
2128             GST_DEBUG_OBJECT (element, "marking audio as VBR:%d, res %d",
2129                 stream->is_vbr, res);
2130             /* we need these or we have no way to come up with timestamps */
2131             if ((!stream->is_vbr && !stream->strf.auds->av_bps) ||
2132                 (stream->is_vbr && (!stream->strh->scale ||
2133                         !stream->strh->rate))) {
2134               GST_WARNING_OBJECT (element,
2135                   "invalid audio header, ignoring stream");
2136               goto fail;
2137             }
2138             /* some more sanity checks */
2139             if (stream->is_vbr) {
2140               if (stream->strf.auds->blockalign <= 4) {
2141                 /* that would mean (too) many frames per chunk,
2142                  * so not likely set as expected */
2143                 GST_DEBUG_OBJECT (element,
2144                     "suspicious blockalign %d for VBR audio; "
2145                     "overriding to 1 frame per chunk",
2146                     stream->strf.auds->blockalign);
2147                 /* this should top any likely value */
2148                 stream->strf.auds->blockalign = (1 << 12);
2149               }
2150             }
2151             break;
2152           case GST_RIFF_FCC_iavs:
2153             stream->is_vbr = TRUE;
2154             res = gst_riff_parse_strf_iavs (element, sub,
2155                 &stream->strf.iavs, &stream->extradata);
2156             sub = NULL;
2157             GST_DEBUG_OBJECT (element, "marking iavs as VBR, res %d", res);
2158             break;
2159           case GST_RIFF_FCC_txts:
2160             /* nothing to parse here */
2161             stream->is_vbr = (stream->strh->samplesize == 0)
2162                 && (stream->strh->scale > 1);
2163             res = TRUE;
2164             break;
2165           default:
2166             GST_ERROR_OBJECT (avi,
2167                 "Don´t know how to handle stream type %" GST_FOURCC_FORMAT,
2168                 GST_FOURCC_ARGS (stream->strh->type));
2169             break;
2170         }
2171         if (sub) {
2172           gst_buffer_unref (sub);
2173           sub = NULL;
2174         }
2175         if (!res)
2176           goto fail;
2177         got_strf = TRUE;
2178         break;
2179       }
2180       case GST_RIFF_TAG_vprp:
2181       {
2182         if (got_vprp) {
2183           GST_WARNING_OBJECT (avi, "Ignoring additional vprp chunk");
2184           break;
2185         }
2186         if (!got_strh) {
2187           GST_ERROR_OBJECT (avi, "Found vprp chunk before strh chunk");
2188           goto fail;
2189         }
2190         if (!got_strf) {
2191           GST_ERROR_OBJECT (avi, "Found vprp chunk before strf chunk");
2192           goto fail;
2193         }
2194
2195         if (!gst_avi_demux_riff_parse_vprp (element, sub, &vprp)) {
2196           GST_WARNING_OBJECT (avi, "Failed to parse vprp chunk");
2197           /* not considered fatal */
2198           g_free (vprp);
2199           vprp = NULL;
2200         } else
2201           got_vprp = TRUE;
2202         sub = NULL;
2203         break;
2204       }
2205       case GST_RIFF_TAG_strd:
2206         if (stream->initdata)
2207           gst_buffer_unref (stream->initdata);
2208         stream->initdata = sub;
2209         if (sub != NULL) {
2210           gst_avi_demux_parse_strd (avi, sub);
2211           sub = NULL;
2212         }
2213         break;
2214       case GST_RIFF_TAG_strn:
2215         g_free (stream->name);
2216
2217         gst_buffer_map (sub, &map, GST_MAP_READ);
2218
2219         if (avi->globaltags == NULL)
2220           avi->globaltags = gst_tag_list_new_empty ();
2221         parse_tag_value (avi, avi->globaltags, GST_TAG_TITLE,
2222             map.data, map.size);
2223
2224         if (gst_tag_list_get_string (avi->globaltags, GST_TAG_TITLE,
2225                 &stream->name))
2226           GST_DEBUG_OBJECT (avi, "stream name: %s", stream->name);
2227
2228         gst_buffer_unmap (sub, &map);
2229         gst_buffer_unref (sub);
2230         sub = NULL;
2231         break;
2232       case GST_RIFF_IDIT:
2233         gst_avi_demux_parse_idit (avi, sub);
2234         break;
2235       default:
2236         if (tag == GST_MAKE_FOURCC ('i', 'n', 'd', 'x') ||
2237             tag == GST_MAKE_FOURCC ('i', 'x', '0' + avi->num_streams / 10,
2238                 '0' + avi->num_streams % 10)) {
2239           g_free (stream->indexes);
2240           gst_avi_demux_parse_superindex (avi, sub, &stream->indexes);
2241           stream->superindex = TRUE;
2242           sub = NULL;
2243           break;
2244         }
2245         GST_WARNING_OBJECT (avi,
2246             "Unknown stream header tag %" GST_FOURCC_FORMAT ", ignoring",
2247             GST_FOURCC_ARGS (tag));
2248         /* Only get buffer for debugging if the memdump is needed  */
2249         if (gst_debug_category_get_threshold (GST_CAT_DEFAULT) >= 9) {
2250           GstMapInfo map;
2251
2252           gst_buffer_map (sub, &map, GST_MAP_READ);
2253           GST_MEMDUMP_OBJECT (avi, "Unknown stream header tag", map.data,
2254               map.size);
2255           gst_buffer_unmap (sub, &map);
2256         }
2257         /* fall-through */
2258       case GST_RIFF_TAG_JUNQ:
2259       case GST_RIFF_TAG_JUNK:
2260         break;
2261     }
2262     if (sub != NULL) {
2263       gst_buffer_unref (sub);
2264       sub = NULL;
2265     }
2266   }
2267
2268   if (!got_strh) {
2269     GST_WARNING_OBJECT (avi, "Failed to find strh chunk");
2270     goto fail;
2271   }
2272
2273   if (!got_strf) {
2274     GST_WARNING_OBJECT (avi, "Failed to find strf chunk");
2275     goto fail;
2276   }
2277
2278   /* get class to figure out the template */
2279   klass = GST_ELEMENT_GET_CLASS (avi);
2280
2281   /* we now have all info, let´s set up a pad and a caps and be done */
2282   /* create stream name + pad */
2283   switch (stream->strh->type) {
2284     case GST_RIFF_FCC_vids:{
2285       guint32 fourcc;
2286
2287       fourcc = (stream->strf.vids->compression) ?
2288           stream->strf.vids->compression : stream->strh->fcc_handler;
2289       caps = gst_riff_create_video_caps (fourcc, stream->strh,
2290           stream->strf.vids, stream->extradata, stream->initdata, &codec_name);
2291
2292       /* DXSB is XSUB, and it is placed inside a vids */
2293       if (!caps || (fourcc != GST_MAKE_FOURCC ('D', 'X', 'S', 'B') &&
2294               fourcc != GST_MAKE_FOURCC ('D', 'X', 'S', 'A'))) {
2295         padname = g_strdup_printf ("video_%u", avi->num_v_streams);
2296         templ = gst_element_class_get_pad_template (klass, "video_%u");
2297         if (!caps) {
2298           caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc",
2299               G_TYPE_INT, fourcc, NULL);
2300         } else if (got_vprp && vprp) {
2301           guint32 aspect_n, aspect_d;
2302           gint n, d;
2303
2304           aspect_n = vprp->aspect >> 16;
2305           aspect_d = vprp->aspect & 0xffff;
2306           /* calculate the pixel aspect ratio using w/h and aspect ratio */
2307           n = aspect_n * stream->strf.vids->height;
2308           d = aspect_d * stream->strf.vids->width;
2309           if (n && d)
2310             gst_caps_set_simple (caps, "pixel-aspect-ratio", GST_TYPE_FRACTION,
2311                 n, d, NULL);
2312         }
2313         caps = gst_avi_demux_check_caps (avi, stream, caps);
2314         tag_name = GST_TAG_VIDEO_CODEC;
2315         avi->num_v_streams++;
2316       } else {
2317         padname = g_strdup_printf ("subpicture_%u", avi->num_sp_streams);
2318         templ = gst_element_class_get_pad_template (klass, "subpicture_%u");
2319         tag_name = NULL;
2320         avi->num_sp_streams++;
2321         sparse = TRUE;
2322       }
2323       break;
2324     }
2325     case GST_RIFF_FCC_auds:{
2326       /* FIXME: Do something with the channel reorder map */
2327       padname = g_strdup_printf ("audio_%u", avi->num_a_streams);
2328       templ = gst_element_class_get_pad_template (klass, "audio_%u");
2329       caps = gst_riff_create_audio_caps (stream->strf.auds->format,
2330           stream->strh, stream->strf.auds, stream->extradata,
2331           stream->initdata, &codec_name, NULL);
2332       if (!caps) {
2333         caps = gst_caps_new_simple ("audio/x-avi-unknown", "codec_id",
2334             G_TYPE_INT, stream->strf.auds->format, NULL);
2335       }
2336       tag_name = GST_TAG_AUDIO_CODEC;
2337       avi->num_a_streams++;
2338       break;
2339     }
2340     case GST_RIFF_FCC_iavs:{
2341       guint32 fourcc = stream->strh->fcc_handler;
2342
2343       padname = g_strdup_printf ("video_%u", avi->num_v_streams);
2344       templ = gst_element_class_get_pad_template (klass, "video_%u");
2345       caps = gst_riff_create_iavs_caps (fourcc, stream->strh,
2346           stream->strf.iavs, stream->extradata, stream->initdata, &codec_name);
2347       if (!caps) {
2348         caps = gst_caps_new_simple ("video/x-avi-unknown", "fourcc",
2349             G_TYPE_INT, fourcc, NULL);
2350       }
2351       tag_name = GST_TAG_VIDEO_CODEC;
2352       avi->num_v_streams++;
2353       break;
2354     }
2355     case GST_RIFF_FCC_txts:{
2356       padname = g_strdup_printf ("subtitle_%u", avi->num_t_streams);
2357       templ = gst_element_class_get_pad_template (klass, "subtitle_%u");
2358       caps = gst_caps_new_empty_simple ("application/x-subtitle-avi");
2359       tag_name = NULL;
2360       avi->num_t_streams++;
2361       sparse = TRUE;
2362       break;
2363     }
2364     default:
2365       g_return_val_if_reached (FALSE);
2366   }
2367
2368   /* no caps means no stream */
2369   if (!caps) {
2370     GST_ERROR_OBJECT (element, "Did not find caps for stream %s", padname);
2371     goto fail;
2372   }
2373
2374   GST_DEBUG_OBJECT (element, "codec-name=%s", codec_name ? codec_name : "NULL");
2375   GST_DEBUG_OBJECT (element, "caps=%" GST_PTR_FORMAT, caps);
2376
2377   /* set proper settings and add it */
2378   if (stream->pad)
2379     gst_object_unref (stream->pad);
2380   pad = stream->pad = gst_pad_new_from_template (templ, padname);
2381   g_free (padname);
2382
2383   gst_pad_use_fixed_caps (pad);
2384 #if 0
2385   gst_pad_set_formats_function (pad,
2386       GST_DEBUG_FUNCPTR (gst_avi_demux_get_src_formats));
2387   gst_pad_set_event_mask_function (pad,
2388       GST_DEBUG_FUNCPTR (gst_avi_demux_get_event_mask));
2389 #endif
2390   gst_pad_set_event_function (pad,
2391       GST_DEBUG_FUNCPTR (gst_avi_demux_handle_src_event));
2392   gst_pad_set_query_function (pad,
2393       GST_DEBUG_FUNCPTR (gst_avi_demux_handle_src_query));
2394 #if 0
2395   gst_pad_set_convert_function (pad,
2396       GST_DEBUG_FUNCPTR (gst_avi_demux_src_convert));
2397 #endif
2398
2399   stream->num = avi->num_streams;
2400
2401   stream->start_entry = 0;
2402   stream->step_entry = 0;
2403   stream->stop_entry = 0;
2404
2405   stream->current_entry = -1;
2406   stream->current_total = 0;
2407
2408   stream->discont = TRUE;
2409
2410   stream->total_bytes = 0;
2411   stream->total_blocks = 0;
2412   stream->n_keyframes = 0;
2413
2414   stream->idx_n = 0;
2415   stream->idx_max = 0;
2416
2417   gst_pad_set_element_private (pad, stream);
2418   avi->num_streams++;
2419
2420   gst_pad_set_active (pad, TRUE);
2421   stream_id =
2422       gst_pad_create_stream_id_printf (pad, GST_ELEMENT_CAST (avi), "%03u",
2423       avi->num_streams);
2424
2425   event = gst_pad_get_sticky_event (avi->sinkpad, GST_EVENT_STREAM_START, 0);
2426   if (event) {
2427     if (gst_event_parse_group_id (event, &avi->group_id))
2428       avi->have_group_id = TRUE;
2429     else
2430       avi->have_group_id = FALSE;
2431     gst_event_unref (event);
2432   } else if (!avi->have_group_id) {
2433     avi->have_group_id = TRUE;
2434     avi->group_id = gst_util_group_id_next ();
2435   }
2436
2437   event = gst_event_new_stream_start (stream_id);
2438   if (avi->have_group_id)
2439     gst_event_set_group_id (event, avi->group_id);
2440   if (sparse)
2441     gst_event_set_stream_flags (event, GST_STREAM_FLAG_SPARSE);
2442
2443   gst_pad_push_event (pad, event);
2444   g_free (stream_id);
2445   gst_pad_set_caps (pad, caps);
2446   gst_caps_unref (caps);
2447
2448   /* make tags */
2449   if (codec_name && tag_name) {
2450     if (!stream->taglist)
2451       stream->taglist = gst_tag_list_new_empty ();
2452
2453     avi->got_tags = TRUE;
2454
2455     gst_tag_list_add (stream->taglist, GST_TAG_MERGE_APPEND, tag_name,
2456         codec_name, NULL);
2457   }
2458
2459   g_free (vprp);
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, 0);
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     GstSeekFlags flags)
4445 {
4446   GstClockTime seek_time;
4447   gboolean keyframe, before, after;
4448   guint i, index;
4449   GstAviStream *stream;
4450
4451   seek_time = segment->position;
4452   keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
4453   before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
4454   after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
4455
4456   GST_DEBUG_OBJECT (avi, "seek to: %" GST_TIME_FORMAT
4457       " keyframe seeking:%d, %s", GST_TIME_ARGS (seek_time), keyframe,
4458       snap_types[before ? 1 : 0][after ? 1 : 0]);
4459
4460   /* FIXME, this code assumes the main stream with keyframes is stream 0,
4461    * which is mostly correct... */
4462   stream = &avi->stream[avi->main_stream];
4463
4464   /* get the entry index for the requested position */
4465   index = gst_avi_demux_index_for_time (avi, stream, seek_time);
4466   GST_DEBUG_OBJECT (avi, "Got entry %u", index);
4467   if (index == -1)
4468     return FALSE;
4469
4470   /* check if we are already on a keyframe */
4471   if (!ENTRY_IS_KEYFRAME (&stream->index[index])) {
4472     gboolean next;
4473
4474     next = after && !before;
4475     if (segment->rate < 0)
4476       next = !next;
4477
4478     if (next) {
4479       GST_DEBUG_OBJECT (avi, "not keyframe, searching forward");
4480       /* now go to the next keyframe, this is where we should start
4481        * decoding from. */
4482       index = gst_avi_demux_index_next (avi, stream, index, TRUE);
4483       GST_DEBUG_OBJECT (avi, "next keyframe at %u", index);
4484     } else {
4485       GST_DEBUG_OBJECT (avi, "not keyframe, searching back");
4486       /* now go to the previous keyframe, this is where we should start
4487        * decoding from. */
4488       index = gst_avi_demux_index_prev (avi, stream, index, TRUE);
4489       GST_DEBUG_OBJECT (avi, "previous keyframe at %u", index);
4490     }
4491   }
4492
4493   /* move the main stream to this position */
4494   gst_avi_demux_move_stream (avi, stream, segment, index);
4495
4496   if (keyframe) {
4497     /* when seeking to a keyframe, we update the result seek time
4498      * to the time of the keyframe. */
4499     seek_time = stream->current_timestamp;
4500     GST_DEBUG_OBJECT (avi, "keyframe adjusted to %" GST_TIME_FORMAT,
4501         GST_TIME_ARGS (seek_time));
4502     /* the seek time is always the position ... */
4503     segment->position = seek_time;
4504     /* ... and start and stream time when going forwards,
4505      * otherwise only stop time */
4506     if (segment->rate > 0.0)
4507       segment->start = segment->time = seek_time;
4508     else
4509       segment->stop = seek_time;
4510   }
4511
4512   /* now set DISCONT and align the other streams */
4513   for (i = 0; i < avi->num_streams; i++) {
4514     GstAviStream *ostream;
4515
4516     ostream = &avi->stream[i];
4517     if ((ostream == stream) || (ostream->index == NULL))
4518       continue;
4519
4520     /* get the entry index for the requested position */
4521     index = gst_avi_demux_index_for_time (avi, ostream, seek_time);
4522     if (index == -1)
4523       continue;
4524
4525     /* move to previous keyframe */
4526     if (!ENTRY_IS_KEYFRAME (&ostream->index[index]))
4527       index = gst_avi_demux_index_prev (avi, ostream, index, TRUE);
4528
4529     gst_avi_demux_move_stream (avi, ostream, segment, index);
4530   }
4531   GST_DEBUG_OBJECT (avi, "done seek to: %" GST_TIME_FORMAT,
4532       GST_TIME_ARGS (seek_time));
4533
4534   return TRUE;
4535 }
4536
4537 /*
4538  * Handle seek event in pull mode.
4539  */
4540 static gboolean
4541 gst_avi_demux_handle_seek (GstAviDemux * avi, GstPad * pad, GstEvent * event)
4542 {
4543   gdouble rate;
4544   GstFormat format;
4545   GstSeekFlags flags;
4546   GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
4547   gint64 cur, stop;
4548   gboolean flush;
4549   gboolean update;
4550   GstSegment seeksegment = { 0, };
4551   gint i;
4552   guint32 seqnum = 0;
4553
4554   if (event) {
4555     GST_DEBUG_OBJECT (avi, "doing seek with event");
4556
4557     gst_event_parse_seek (event, &rate, &format, &flags,
4558         &cur_type, &cur, &stop_type, &stop);
4559     seqnum = gst_event_get_seqnum (event);
4560
4561     /* we have to have a format as the segment format. Try to convert
4562      * if not. */
4563     if (format != GST_FORMAT_TIME) {
4564       gboolean res = TRUE;
4565
4566       if (cur_type != GST_SEEK_TYPE_NONE)
4567         res = gst_pad_query_convert (pad, format, cur, GST_FORMAT_TIME, &cur);
4568       if (res && stop_type != GST_SEEK_TYPE_NONE)
4569         res = gst_pad_query_convert (pad, format, stop, GST_FORMAT_TIME, &stop);
4570       if (!res)
4571         goto no_format;
4572
4573       format = GST_FORMAT_TIME;
4574     }
4575     GST_DEBUG_OBJECT (avi,
4576         "seek requested: rate %g cur %" GST_TIME_FORMAT " stop %"
4577         GST_TIME_FORMAT, rate, GST_TIME_ARGS (cur), GST_TIME_ARGS (stop));
4578     /* FIXME: can we do anything with rate!=1.0 */
4579   } else {
4580     GST_DEBUG_OBJECT (avi, "doing seek without event");
4581     flags = 0;
4582     rate = 1.0;
4583   }
4584
4585   /* save flush flag */
4586   flush = flags & GST_SEEK_FLAG_FLUSH;
4587
4588   if (flush) {
4589     GstEvent *fevent = gst_event_new_flush_start ();
4590
4591     if (seqnum)
4592       gst_event_set_seqnum (fevent, seqnum);
4593     /* for a flushing seek, we send a flush_start on all pads. This will
4594      * eventually stop streaming with a WRONG_STATE. We can thus eventually
4595      * take the STREAM_LOCK. */
4596     GST_DEBUG_OBJECT (avi, "sending flush start");
4597     gst_avi_demux_push_event (avi, gst_event_ref (fevent));
4598     gst_pad_push_event (avi->sinkpad, fevent);
4599   } else {
4600     /* a non-flushing seek, we PAUSE the task so that we can take the
4601      * STREAM_LOCK */
4602     GST_DEBUG_OBJECT (avi, "non flushing seek, pausing task");
4603     gst_pad_pause_task (avi->sinkpad);
4604   }
4605
4606   /* wait for streaming to stop */
4607   GST_DEBUG_OBJECT (avi, "wait for streaming to stop");
4608   GST_PAD_STREAM_LOCK (avi->sinkpad);
4609
4610   /* copy segment, we need this because we still need the old
4611    * segment when we close the current segment. */
4612   memcpy (&seeksegment, &avi->segment, sizeof (GstSegment));
4613
4614   if (event) {
4615     GST_DEBUG_OBJECT (avi, "configuring seek");
4616     gst_segment_do_seek (&seeksegment, rate, format, flags,
4617         cur_type, cur, stop_type, stop, &update);
4618   }
4619   /* do the seek, seeksegment.position contains the new position, this
4620    * actually never fails. */
4621   gst_avi_demux_do_seek (avi, &seeksegment, flags);
4622
4623   if (flush) {
4624     GstEvent *fevent = gst_event_new_flush_stop (TRUE);
4625
4626     if (seqnum)
4627       gst_event_set_seqnum (fevent, seqnum);
4628
4629     GST_DEBUG_OBJECT (avi, "sending flush stop");
4630     gst_avi_demux_push_event (avi, gst_event_ref (fevent));
4631     gst_pad_push_event (avi->sinkpad, fevent);
4632   }
4633
4634   /* now update the real segment info */
4635   memcpy (&avi->segment, &seeksegment, sizeof (GstSegment));
4636
4637   /* post the SEGMENT_START message when we do segmented playback */
4638   if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) {
4639     GstMessage *segment_start_msg =
4640         gst_message_new_segment_start (GST_OBJECT_CAST (avi),
4641         avi->segment.format, avi->segment.position);
4642     if (seqnum)
4643       gst_message_set_seqnum (segment_start_msg, seqnum);
4644     gst_element_post_message (GST_ELEMENT_CAST (avi), segment_start_msg);
4645   }
4646
4647   /* queue the segment event for the streaming thread. */
4648   if (avi->seg_event)
4649     gst_event_unref (avi->seg_event);
4650   avi->seg_event = gst_event_new_segment (&avi->segment);
4651   if (seqnum)
4652     gst_event_set_seqnum (avi->seg_event, seqnum);
4653   avi->segment_seqnum = seqnum;
4654
4655   if (!avi->streaming) {
4656     gst_pad_start_task (avi->sinkpad, (GstTaskFunction) gst_avi_demux_loop,
4657         avi->sinkpad, NULL);
4658   }
4659   /* reset the last flow and mark discont, seek is always DISCONT */
4660   for (i = 0; i < avi->num_streams; i++) {
4661     GST_DEBUG_OBJECT (avi, "marking DISCONT");
4662     avi->stream[i].discont = TRUE;
4663   }
4664   /* likewise for the whole new segment */
4665   gst_flow_combiner_reset (avi->flowcombiner);
4666   GST_PAD_STREAM_UNLOCK (avi->sinkpad);
4667
4668   return TRUE;
4669
4670   /* ERRORS */
4671 no_format:
4672   {
4673     GST_DEBUG_OBJECT (avi, "unsupported format given, seek aborted.");
4674     return FALSE;
4675   }
4676 }
4677
4678 /*
4679  * Handle seek event in push mode.
4680  */
4681 static gboolean
4682 avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad, GstEvent * event)
4683 {
4684   gdouble rate;
4685   GstFormat format;
4686   GstSeekFlags flags;
4687   GstSeekType cur_type = GST_SEEK_TYPE_NONE, stop_type;
4688   gint64 cur, stop;
4689   gboolean keyframe, before, after;
4690   GstAviStream *stream;
4691   guint index;
4692   guint n, str_num;
4693   guint64 min_offset;
4694   GstSegment seeksegment;
4695   gboolean update;
4696
4697   /* check we have the index */
4698   if (!avi->have_index) {
4699     GST_DEBUG_OBJECT (avi, "no seek index built, seek aborted.");
4700     return FALSE;
4701   } else {
4702     GST_DEBUG_OBJECT (avi, "doing push-based seek with event");
4703   }
4704
4705   gst_event_parse_seek (event, &rate, &format, &flags,
4706       &cur_type, &cur, &stop_type, &stop);
4707
4708   if (format != GST_FORMAT_TIME) {
4709     gboolean res = TRUE;
4710
4711     if (cur_type != GST_SEEK_TYPE_NONE)
4712       res = gst_pad_query_convert (pad, format, cur, GST_FORMAT_TIME, &cur);
4713     if (res && stop_type != GST_SEEK_TYPE_NONE)
4714       res = gst_pad_query_convert (pad, format, stop, GST_FORMAT_TIME, &stop);
4715     if (!res) {
4716       GST_DEBUG_OBJECT (avi, "unsupported format given, seek aborted.");
4717       return FALSE;
4718     }
4719
4720     format = GST_FORMAT_TIME;
4721   }
4722
4723   /* let gst_segment handle any tricky stuff */
4724   GST_DEBUG_OBJECT (avi, "configuring seek");
4725   memcpy (&seeksegment, &avi->segment, sizeof (GstSegment));
4726   gst_segment_do_seek (&seeksegment, rate, format, flags,
4727       cur_type, cur, stop_type, stop, &update);
4728
4729   keyframe = ! !(flags & GST_SEEK_FLAG_KEY_UNIT);
4730   cur = seeksegment.position;
4731   before = ! !(flags & GST_SEEK_FLAG_SNAP_BEFORE);
4732   after = ! !(flags & GST_SEEK_FLAG_SNAP_AFTER);
4733
4734   GST_DEBUG_OBJECT (avi,
4735       "Seek requested: ts %" GST_TIME_FORMAT " stop %" GST_TIME_FORMAT
4736       ", kf %u, %s, rate %lf", GST_TIME_ARGS (cur), GST_TIME_ARGS (stop),
4737       keyframe, snap_types[before ? 1 : 0][after ? 1 : 0], rate);
4738
4739   if (rate < 0) {
4740     GST_DEBUG_OBJECT (avi, "negative rate seek not supported in push mode");
4741     return FALSE;
4742   }
4743
4744   /* FIXME, this code assumes the main stream with keyframes is stream 0,
4745    * which is mostly correct... */
4746   str_num = avi->main_stream;
4747   stream = &avi->stream[str_num];
4748
4749   /* get the entry index for the requested position */
4750   index = gst_avi_demux_index_for_time (avi, stream, cur);
4751   GST_DEBUG_OBJECT (avi, "str %u: Found entry %u for %" GST_TIME_FORMAT,
4752       str_num, index, GST_TIME_ARGS (cur));
4753   if (index == -1)
4754     return -1;
4755
4756   /* check if we are already on a keyframe */
4757   if (!ENTRY_IS_KEYFRAME (&stream->index[index])) {
4758     gboolean next;
4759
4760     next = after && !before;
4761     if (seeksegment.rate < 0)
4762       next = !next;
4763
4764     if (next) {
4765       GST_DEBUG_OBJECT (avi, "Entry is not a keyframe - searching forward");
4766       /* now go to the next keyframe, this is where we should start
4767        * decoding from. */
4768       index = gst_avi_demux_index_next (avi, stream, index, TRUE);
4769       GST_DEBUG_OBJECT (avi, "Found previous keyframe at %u", index);
4770     } else {
4771       GST_DEBUG_OBJECT (avi, "Entry is not a keyframe - searching back");
4772       /* now go to the previous keyframe, this is where we should start
4773        * decoding from. */
4774       index = gst_avi_demux_index_prev (avi, stream, index, TRUE);
4775       GST_DEBUG_OBJECT (avi, "Found previous keyframe at %u", index);
4776     }
4777   }
4778
4779   gst_avi_demux_get_buffer_info (avi, stream, index,
4780       &stream->current_timestamp, &stream->current_ts_end,
4781       &stream->current_offset, &stream->current_offset_end);
4782
4783   /* re-use cur to be the timestamp of the seek as it _will_ be */
4784   cur = stream->current_timestamp;
4785
4786   min_offset = stream->index[index].offset;
4787   avi->seek_kf_offset = min_offset - 8;
4788
4789   GST_DEBUG_OBJECT (avi,
4790       "Seek to: ts %" GST_TIME_FORMAT " (on str %u, idx %u, offset %"
4791       G_GUINT64_FORMAT ")", GST_TIME_ARGS (stream->current_timestamp), str_num,
4792       index, min_offset);
4793
4794   for (n = 0; n < avi->num_streams; n++) {
4795     GstAviStream *str = &avi->stream[n];
4796     guint idx;
4797
4798     if (n == avi->main_stream)
4799       continue;
4800
4801     /* get the entry index for the requested position */
4802     idx = gst_avi_demux_index_for_time (avi, str, cur);
4803     GST_DEBUG_OBJECT (avi, "str %u: Found entry %u for %" GST_TIME_FORMAT, n,
4804         idx, GST_TIME_ARGS (cur));
4805     if (idx == -1)
4806       continue;
4807
4808     /* check if we are already on a keyframe */
4809     if (!ENTRY_IS_KEYFRAME (&str->index[idx])) {
4810       if (after && !before) {
4811         GST_DEBUG_OBJECT (avi, "Entry is not a keyframe - searching forward");
4812         /* now go to the next keyframe, this is where we should start
4813          * decoding from. */
4814         idx = gst_avi_demux_index_next (avi, str, idx, TRUE);
4815         GST_DEBUG_OBJECT (avi, "Found next keyframe at %u", idx);
4816       } else {
4817         GST_DEBUG_OBJECT (avi, "Entry is not a keyframe - searching back");
4818         /* now go to the previous keyframe, this is where we should start
4819          * decoding from. */
4820         idx = gst_avi_demux_index_prev (avi, str, idx, TRUE);
4821         GST_DEBUG_OBJECT (avi, "Found previous keyframe at %u", idx);
4822       }
4823     }
4824
4825     gst_avi_demux_get_buffer_info (avi, str, idx,
4826         &str->current_timestamp, &str->current_ts_end,
4827         &str->current_offset, &str->current_offset_end);
4828
4829     if (str->index[idx].offset < min_offset) {
4830       min_offset = str->index[idx].offset;
4831       GST_DEBUG_OBJECT (avi,
4832           "Found an earlier offset at %" G_GUINT64_FORMAT ", str %u",
4833           min_offset, n);
4834       str_num = n;
4835       stream = str;
4836       index = idx;
4837     }
4838   }
4839
4840   GST_DEBUG_OBJECT (avi,
4841       "Seek performed: str %u, offset %" G_GUINT64_FORMAT ", idx %u, ts %"
4842       GST_TIME_FORMAT ", ts_end %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
4843       ", off_end %" G_GUINT64_FORMAT, str_num, min_offset, index,
4844       GST_TIME_ARGS (stream->current_timestamp),
4845       GST_TIME_ARGS (stream->current_ts_end), stream->current_offset,
4846       stream->current_offset_end);
4847
4848   /* index data refers to data, not chunk header (for pull mode convenience) */
4849   min_offset -= 8;
4850   GST_DEBUG_OBJECT (avi, "seeking to chunk at offset %" G_GUINT64_FORMAT,
4851       min_offset);
4852
4853   if (!perform_seek_to_offset (avi, min_offset, gst_event_get_seqnum (event))) {
4854     GST_DEBUG_OBJECT (avi, "seek event failed!");
4855     return FALSE;
4856   }
4857
4858   return TRUE;
4859 }
4860
4861 /*
4862  * Handle whether we can perform the seek event or if we have to let the chain
4863  * function handle seeks to build the seek indexes first.
4864  */
4865 static gboolean
4866 gst_avi_demux_handle_seek_push (GstAviDemux * avi, GstPad * pad,
4867     GstEvent * event)
4868 {
4869   /* check for having parsed index already */
4870   if (!avi->have_index) {
4871     guint64 offset = 0;
4872     gboolean building_index;
4873
4874     GST_OBJECT_LOCK (avi);
4875     /* handle the seek event in the chain function */
4876     avi->state = GST_AVI_DEMUX_SEEK;
4877
4878     /* copy the event */
4879     if (avi->seek_event)
4880       gst_event_unref (avi->seek_event);
4881     avi->seek_event = gst_event_ref (event);
4882
4883     /* set the building_index flag so that only one thread can setup the
4884      * structures for index seeking. */
4885     building_index = avi->building_index;
4886     if (!building_index) {
4887       avi->building_index = TRUE;
4888       if (avi->stream[0].indexes) {
4889         avi->odml_stream = 0;
4890         avi->odml_subidxs = avi->stream[avi->odml_stream].indexes;
4891         offset = avi->odml_subidxs[0];
4892       } else {
4893         offset = avi->idx1_offset;
4894       }
4895     }
4896     GST_OBJECT_UNLOCK (avi);
4897
4898     if (!building_index) {
4899       /* seek to the first subindex or legacy index */
4900       GST_INFO_OBJECT (avi,
4901           "Seeking to legacy index/first subindex at %" G_GUINT64_FORMAT,
4902           offset);
4903       return perform_seek_to_offset (avi, offset, gst_event_get_seqnum (event));
4904     }
4905
4906     /* FIXME: we have to always return true so that we don't block the seek
4907      * thread.
4908      * Note: maybe it is OK to return true if we're still building the index */
4909     return TRUE;
4910   }
4911
4912   return avi_demux_handle_seek_push (avi, pad, event);
4913 }
4914
4915 /*
4916  * Helper for gst_avi_demux_invert()
4917  */
4918 static inline void
4919 swap_line (guint8 * d1, guint8 * d2, guint8 * tmp, gint bytes)
4920 {
4921   memcpy (tmp, d1, bytes);
4922   memcpy (d1, d2, bytes);
4923   memcpy (d2, tmp, bytes);
4924 }
4925
4926
4927 #define gst_avi_demux_is_uncompressed(fourcc)           \
4928   (fourcc == GST_RIFF_DIB ||                            \
4929    fourcc == GST_RIFF_rgb ||                            \
4930    fourcc == GST_RIFF_RGB || fourcc == GST_RIFF_RAW)
4931
4932 /*
4933  * Invert DIB buffers... Takes existing buffer and
4934  * returns either the buffer or a new one (with old
4935  * one dereferenced).
4936  * FIXME: can't we preallocate tmp? and remember stride, bpp?
4937  */
4938 static GstBuffer *
4939 gst_avi_demux_invert (GstAviStream * stream, GstBuffer * buf)
4940 {
4941   gint y, w, h;
4942   gint bpp, stride;
4943   guint8 *tmp = NULL;
4944   GstMapInfo map;
4945   guint32 fourcc;
4946
4947   if (stream->strh->type != GST_RIFF_FCC_vids)
4948     return buf;
4949
4950   if (stream->strf.vids == NULL) {
4951     GST_WARNING ("Failed to retrieve vids for stream");
4952     return buf;
4953   }
4954
4955   fourcc = (stream->strf.vids->compression) ?
4956       stream->strf.vids->compression : stream->strh->fcc_handler;
4957   if (!gst_avi_demux_is_uncompressed (fourcc)) {
4958     return buf;                 /* Ignore non DIB buffers */
4959   }
4960
4961   /* raw rgb data is stored topdown, but instead of inverting the buffer, */
4962   /* some tools just negate the height field in the header (e.g. ffmpeg) */
4963   if (((gint32) stream->strf.vids->height) < 0)
4964     return buf;
4965
4966   h = stream->strf.vids->height;
4967   w = stream->strf.vids->width;
4968   bpp = stream->strf.vids->bit_cnt ? stream->strf.vids->bit_cnt : 8;
4969   stride = GST_ROUND_UP_4 (w * (bpp / 8));
4970
4971   buf = gst_buffer_make_writable (buf);
4972
4973   gst_buffer_map (buf, &map, GST_MAP_READWRITE);
4974   if (map.size < (stride * h)) {
4975     GST_WARNING ("Buffer is smaller than reported Width x Height x Depth");
4976     gst_buffer_unmap (buf, &map);
4977     return buf;
4978   }
4979
4980   tmp = g_malloc (stride);
4981
4982   for (y = 0; y < h / 2; y++) {
4983     swap_line (map.data + stride * y, map.data + stride * (h - 1 - y), tmp,
4984         stride);
4985   }
4986
4987   g_free (tmp);
4988
4989   gst_buffer_unmap (buf, &map);
4990
4991   /* append palette to paletted RGB8 buffer data */
4992   if (stream->rgb8_palette != NULL)
4993     buf = gst_buffer_append (buf, gst_buffer_ref (stream->rgb8_palette));
4994
4995   return buf;
4996 }
4997
4998 #if 0
4999 static void
5000 gst_avi_demux_add_assoc (GstAviDemux * avi, GstAviStream * stream,
5001     GstClockTime timestamp, guint64 offset, gboolean keyframe)
5002 {
5003   /* do not add indefinitely for open-ended streaming */
5004   if (G_UNLIKELY (avi->element_index && avi->seekable)) {
5005     GST_LOG_OBJECT (avi, "adding association %" GST_TIME_FORMAT "-> %"
5006         G_GUINT64_FORMAT, GST_TIME_ARGS (timestamp), offset);
5007     gst_index_add_association (avi->element_index, avi->index_id,
5008         keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5009         GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, timestamp,
5010         GST_FORMAT_BYTES, offset, NULL);
5011     /* current_entry is DEFAULT (frame #) */
5012     gst_index_add_association (avi->element_index, stream->index_id,
5013         keyframe ? GST_ASSOCIATION_FLAG_KEY_UNIT :
5014         GST_ASSOCIATION_FLAG_DELTA_UNIT, GST_FORMAT_TIME, timestamp,
5015         GST_FORMAT_BYTES, offset, GST_FORMAT_DEFAULT, stream->current_entry,
5016         NULL);
5017   }
5018 }
5019 #endif
5020
5021 /*
5022  * Returns the aggregated GstFlowReturn.
5023  */
5024 static GstFlowReturn
5025 gst_avi_demux_combine_flows (GstAviDemux * avi, GstAviStream * stream,
5026     GstFlowReturn ret)
5027 {
5028   GST_LOG_OBJECT (avi, "Stream %s:%s flow return: %s",
5029       GST_DEBUG_PAD_NAME (stream->pad), gst_flow_get_name (ret));
5030   ret = gst_flow_combiner_update_pad_flow (avi->flowcombiner, stream->pad, ret);
5031   GST_LOG_OBJECT (avi, "combined to return %s", gst_flow_get_name (ret));
5032
5033   return ret;
5034 }
5035
5036 /* move @stream to the next position in its index */
5037 static GstFlowReturn
5038 gst_avi_demux_advance (GstAviDemux * avi, GstAviStream * stream,
5039     GstFlowReturn ret)
5040 {
5041   guint old_entry, new_entry;
5042
5043   old_entry = stream->current_entry;
5044   /* move forwards */
5045   new_entry = old_entry + 1;
5046
5047   /* see if we reached the end */
5048   if (new_entry >= stream->stop_entry) {
5049     if (avi->segment.rate < 0.0) {
5050       if (stream->step_entry == stream->start_entry) {
5051         /* we stepped all the way to the start, eos */
5052         GST_DEBUG_OBJECT (avi, "reverse reached start %u", stream->start_entry);
5053         goto eos;
5054       }
5055       /* backwards, stop becomes step, find a new step */
5056       stream->stop_entry = stream->step_entry;
5057       stream->step_entry = gst_avi_demux_index_prev (avi, stream,
5058           stream->stop_entry, TRUE);
5059
5060       GST_DEBUG_OBJECT (avi,
5061           "reverse playback jump: start %u, step %u, stop %u",
5062           stream->start_entry, stream->step_entry, stream->stop_entry);
5063
5064       /* and start from the previous keyframe now */
5065       new_entry = stream->step_entry;
5066     } else {
5067       /* EOS */
5068       GST_DEBUG_OBJECT (avi, "forward reached stop %u", stream->stop_entry);
5069       goto eos;
5070     }
5071   }
5072
5073   if (new_entry != old_entry) {
5074     stream->current_entry = new_entry;
5075     stream->current_total = stream->index[new_entry].total;
5076
5077     if (new_entry == old_entry + 1) {
5078       GST_DEBUG_OBJECT (avi, "moved forwards from %u to %u",
5079           old_entry, new_entry);
5080       /* we simply moved one step forwards, reuse current info */
5081       stream->current_timestamp = stream->current_ts_end;
5082       stream->current_offset = stream->current_offset_end;
5083       gst_avi_demux_get_buffer_info (avi, stream, new_entry,
5084           NULL, &stream->current_ts_end, NULL, &stream->current_offset_end);
5085     } else {
5086       /* we moved DISCONT, full update */
5087       gst_avi_demux_get_buffer_info (avi, stream, new_entry,
5088           &stream->current_timestamp, &stream->current_ts_end,
5089           &stream->current_offset, &stream->current_offset_end);
5090       /* and MARK discont for this stream */
5091       stream->discont = TRUE;
5092       GST_DEBUG_OBJECT (avi, "Moved from %u to %u, ts %" GST_TIME_FORMAT
5093           ", ts_end %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
5094           ", off_end %" G_GUINT64_FORMAT, old_entry, new_entry,
5095           GST_TIME_ARGS (stream->current_timestamp),
5096           GST_TIME_ARGS (stream->current_ts_end), stream->current_offset,
5097           stream->current_offset_end);
5098     }
5099   }
5100   return ret;
5101
5102   /* ERROR */
5103 eos:
5104   {
5105     GST_DEBUG_OBJECT (avi, "we are EOS");
5106     /* setting current_timestamp to -1 marks EOS */
5107     stream->current_timestamp = -1;
5108     return GST_FLOW_EOS;
5109   }
5110 }
5111
5112 /* find the stream with the lowest current position when going forwards or with
5113  * the highest position when going backwards, this is the stream
5114  * we should push from next */
5115 static gint
5116 gst_avi_demux_find_next (GstAviDemux * avi, gfloat rate)
5117 {
5118   guint64 min_time, max_time;
5119   guint stream_num, i;
5120
5121   max_time = 0;
5122   min_time = G_MAXUINT64;
5123   stream_num = -1;
5124
5125   for (i = 0; i < avi->num_streams; i++) {
5126     guint64 position;
5127     GstAviStream *stream;
5128
5129     stream = &avi->stream[i];
5130
5131     /* ignore streams that finished */
5132     if (stream->pad && GST_PAD_LAST_FLOW_RETURN (stream->pad) == GST_FLOW_EOS)
5133       continue;
5134
5135     position = stream->current_timestamp;
5136
5137     /* position of -1 is EOS */
5138     if (position != -1) {
5139       if (rate > 0.0 && position < min_time) {
5140         min_time = position;
5141         stream_num = i;
5142       } else if (rate < 0.0 && position >= max_time) {
5143         max_time = position;
5144         stream_num = i;
5145       }
5146     }
5147   }
5148   return stream_num;
5149 }
5150
5151 static GstBuffer *
5152 gst_avi_demux_align_buffer (GstAviDemux * demux,
5153     GstBuffer * buffer, gsize alignment)
5154 {
5155   GstMapInfo map;
5156
5157   gst_buffer_map (buffer, &map, GST_MAP_READ);
5158
5159   if (map.size < sizeof (guintptr)) {
5160     gst_buffer_unmap (buffer, &map);
5161     return buffer;
5162   }
5163
5164   if (((guintptr) map.data) & (alignment - 1)) {
5165     GstBuffer *new_buffer;
5166     GstAllocationParams params = { 0, alignment - 1, 0, 0, };
5167
5168     new_buffer = gst_buffer_new_allocate (NULL,
5169         gst_buffer_get_size (buffer), &params);
5170
5171     /* Copy data "by hand", so ensure alignment is kept: */
5172     gst_buffer_fill (new_buffer, 0, map.data, map.size);
5173
5174     gst_buffer_copy_into (new_buffer, buffer, GST_BUFFER_COPY_METADATA, 0, -1);
5175     GST_DEBUG_OBJECT (demux,
5176         "We want output aligned on %" G_GSIZE_FORMAT ", reallocated",
5177         alignment);
5178
5179     gst_buffer_unmap (buffer, &map);
5180     gst_buffer_unref (buffer);
5181
5182     return new_buffer;
5183   }
5184
5185   gst_buffer_unmap (buffer, &map);
5186   return buffer;
5187 }
5188
5189 static GstFlowReturn
5190 gst_avi_demux_loop_data (GstAviDemux * avi)
5191 {
5192   GstFlowReturn ret = GST_FLOW_OK;
5193   guint stream_num;
5194   GstAviStream *stream;
5195   gboolean processed = FALSE;
5196   GstBuffer *buf;
5197   guint64 offset, size;
5198   GstClockTime timestamp, duration;
5199   guint64 out_offset, out_offset_end;
5200   gboolean keyframe;
5201   GstAviIndexEntry *entry;
5202
5203   do {
5204     stream_num = gst_avi_demux_find_next (avi, avi->segment.rate);
5205
5206     /* all are EOS */
5207     if (G_UNLIKELY (stream_num == -1)) {
5208       GST_DEBUG_OBJECT (avi, "all streams are EOS");
5209       goto eos;
5210     }
5211
5212     /* we have the stream now */
5213     stream = &avi->stream[stream_num];
5214
5215     /* skip streams without pads */
5216     if (!stream->pad) {
5217       GST_DEBUG_OBJECT (avi, "skipping entry from stream %d without pad",
5218           stream_num);
5219       goto next;
5220     }
5221
5222     /* get the timing info for the entry */
5223     timestamp = stream->current_timestamp;
5224     duration = stream->current_ts_end - timestamp;
5225     out_offset = stream->current_offset;
5226     out_offset_end = stream->current_offset_end;
5227
5228     /* get the entry data info */
5229     entry = &stream->index[stream->current_entry];
5230     offset = entry->offset;
5231     size = entry->size;
5232     keyframe = ENTRY_IS_KEYFRAME (entry);
5233
5234     /* skip empty entries */
5235     if (size == 0) {
5236       GST_DEBUG_OBJECT (avi, "Skipping entry %u (%" G_GUINT64_FORMAT ", %p)",
5237           stream->current_entry, size, stream->pad);
5238       goto next;
5239     }
5240
5241     if (avi->segment.rate > 0.0) {
5242       /* only check this for fowards playback for now */
5243       if (keyframe && GST_CLOCK_TIME_IS_VALID (avi->segment.stop)
5244           && (timestamp > avi->segment.stop)) {
5245         goto eos_stop;
5246       }
5247     } else {
5248       if (keyframe && GST_CLOCK_TIME_IS_VALID (avi->segment.start)
5249           && (timestamp < avi->segment.start))
5250         goto eos_stop;
5251     }
5252
5253     GST_LOG ("reading buffer (size=%" G_GUINT64_FORMAT "), stream %d, pos %"
5254         G_GUINT64_FORMAT " (0x%" G_GINT64_MODIFIER "x), kf %d", size,
5255         stream_num, offset, offset, keyframe);
5256
5257     /* FIXME, check large chunks and cut them up */
5258
5259     /* pull in the data */
5260     buf = NULL;
5261     ret = gst_pad_pull_range (avi->sinkpad, offset, size, &buf);
5262     if (ret != GST_FLOW_OK)
5263       goto pull_failed;
5264
5265     /* check for short buffers, this is EOS as well */
5266     if (gst_buffer_get_size (buf) < size)
5267       goto short_buffer;
5268
5269     /* invert the picture if needed, and append palette for RGB8P */
5270     buf = gst_avi_demux_invert (stream, buf);
5271
5272     /* mark non-keyframes */
5273     if (keyframe || stream->is_raw) {
5274       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5275       GST_BUFFER_PTS (buf) = timestamp;
5276     } else {
5277       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
5278       GST_BUFFER_PTS (buf) = GST_CLOCK_TIME_NONE;
5279     }
5280
5281     GST_BUFFER_DTS (buf) = timestamp;
5282
5283     GST_BUFFER_DURATION (buf) = duration;
5284     GST_BUFFER_OFFSET (buf) = out_offset;
5285     GST_BUFFER_OFFSET_END (buf) = out_offset_end;
5286
5287     /* mark discont when pending */
5288     if (stream->discont) {
5289       GST_DEBUG_OBJECT (avi, "setting DISCONT flag");
5290       GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5291       stream->discont = FALSE;
5292     } else {
5293       GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5294     }
5295 #if 0
5296     gst_avi_demux_add_assoc (avi, stream, timestamp, offset, keyframe);
5297 #endif
5298
5299     /* update current position in the segment */
5300     avi->segment.position = timestamp;
5301
5302     GST_DEBUG_OBJECT (avi, "Pushing buffer of size %" G_GSIZE_FORMAT ", ts %"
5303         GST_TIME_FORMAT ", dur %" GST_TIME_FORMAT ", off %" G_GUINT64_FORMAT
5304         ", off_end %" G_GUINT64_FORMAT,
5305         gst_buffer_get_size (buf), GST_TIME_ARGS (timestamp),
5306         GST_TIME_ARGS (duration), out_offset, out_offset_end);
5307
5308     if (stream->alignment > 1)
5309       buf = gst_avi_demux_align_buffer (avi, buf, stream->alignment);
5310     ret = gst_pad_push (stream->pad, buf);
5311
5312     /* mark as processed, we increment the frame and byte counters then
5313      * leave the while loop and return the GstFlowReturn */
5314     processed = TRUE;
5315
5316     if (avi->segment.rate < 0) {
5317       if (timestamp > avi->segment.stop && ret == GST_FLOW_EOS) {
5318         /* In reverse playback we can get a GST_FLOW_EOS when
5319          * we are at the end of the segment, so we just need to jump
5320          * back to the previous section. */
5321         GST_DEBUG_OBJECT (avi, "downstream has reached end of segment");
5322         ret = GST_FLOW_OK;
5323       }
5324     }
5325   next:
5326     /* move to next item */
5327     ret = gst_avi_demux_advance (avi, stream, ret);
5328
5329     /* combine flows */
5330     ret = gst_avi_demux_combine_flows (avi, stream, ret);
5331   } while (!processed);
5332
5333 beach:
5334   return ret;
5335
5336   /* special cases */
5337 eos:
5338   {
5339     GST_DEBUG_OBJECT (avi, "No samples left for any streams - EOS");
5340     ret = GST_FLOW_EOS;
5341     goto beach;
5342   }
5343 eos_stop:
5344   {
5345     GST_LOG_OBJECT (avi, "Found keyframe after segment,"
5346         " setting EOS (%" GST_TIME_FORMAT " > %" GST_TIME_FORMAT ")",
5347         GST_TIME_ARGS (timestamp), GST_TIME_ARGS (avi->segment.stop));
5348     ret = GST_FLOW_EOS;
5349     /* move to next stream */
5350     goto next;
5351   }
5352 pull_failed:
5353   {
5354     GST_DEBUG_OBJECT (avi, "pull range failed: pos=%" G_GUINT64_FORMAT
5355         " size=%" G_GUINT64_FORMAT, offset, size);
5356     goto beach;
5357   }
5358 short_buffer:
5359   {
5360     GST_WARNING_OBJECT (avi, "Short read at offset %" G_GUINT64_FORMAT
5361         ", only got %" G_GSIZE_FORMAT "/%" G_GUINT64_FORMAT
5362         " bytes (truncated file?)", offset, gst_buffer_get_size (buf), size);
5363     gst_buffer_unref (buf);
5364     ret = GST_FLOW_EOS;
5365     goto beach;
5366   }
5367 }
5368
5369 /*
5370  * Read data. If we have an index it delegates to
5371  * gst_avi_demux_process_next_entry().
5372  */
5373 static GstFlowReturn
5374 gst_avi_demux_stream_data (GstAviDemux * avi)
5375 {
5376   guint32 tag = 0;
5377   guint32 size = 0;
5378   gint stream_nr = 0;
5379   GstFlowReturn res = GST_FLOW_OK;
5380
5381   if (G_UNLIKELY (avi->have_eos)) {
5382     /* Clean adapter, we're done */
5383     gst_adapter_clear (avi->adapter);
5384     return GST_FLOW_EOS;
5385   }
5386
5387   if (G_UNLIKELY (avi->todrop)) {
5388     guint drop;
5389
5390     if ((drop = gst_adapter_available (avi->adapter))) {
5391       if (drop > avi->todrop)
5392         drop = avi->todrop;
5393       GST_DEBUG_OBJECT (avi, "Dropping %d bytes", drop);
5394       gst_adapter_flush (avi->adapter, drop);
5395       avi->todrop -= drop;
5396       avi->offset += drop;
5397     }
5398   }
5399
5400   /* Iterate until need more data, so adapter won't grow too much */
5401   while (1) {
5402     if (G_UNLIKELY (!gst_avi_demux_peek_chunk_info (avi, &tag, &size))) {
5403       return GST_FLOW_OK;
5404     }
5405
5406     GST_DEBUG ("Trying chunk (%" GST_FOURCC_FORMAT "), size %d",
5407         GST_FOURCC_ARGS (tag), size);
5408
5409     if (G_LIKELY ((tag & 0xff) >= '0' && (tag & 0xff) <= '9' &&
5410             ((tag >> 8) & 0xff) >= '0' && ((tag >> 8) & 0xff) <= '9')) {
5411       GST_LOG ("Chunk ok");
5412     } else if ((tag & 0xffff) == (('x' << 8) | 'i')) {
5413       GST_DEBUG ("Found sub-index tag");
5414       if (gst_avi_demux_peek_chunk (avi, &tag, &size) || size == 0) {
5415         /* accept 0 size buffer here */
5416         avi->abort_buffering = FALSE;
5417         GST_DEBUG ("  skipping %d bytes for now", size);
5418         gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
5419       }
5420       return GST_FLOW_OK;
5421     } else if (tag == GST_RIFF_TAG_RIFF) {
5422       /* RIFF tags can appear in ODML files, just jump over them */
5423       if (gst_adapter_available (avi->adapter) >= 12) {
5424         GST_DEBUG ("Found RIFF tag, skipping RIFF header");
5425         gst_adapter_flush (avi->adapter, 12);
5426         continue;
5427       }
5428       return GST_FLOW_OK;
5429     } else if (tag == GST_RIFF_TAG_idx1) {
5430       GST_DEBUG ("Found index tag");
5431       if (gst_avi_demux_peek_chunk (avi, &tag, &size) || size == 0) {
5432         /* accept 0 size buffer here */
5433         avi->abort_buffering = FALSE;
5434         GST_DEBUG ("  skipping %d bytes for now", size);
5435         gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
5436       }
5437       return GST_FLOW_OK;
5438     } else if (tag == GST_RIFF_TAG_LIST) {
5439       /* movi chunks might be grouped in rec list */
5440       if (gst_adapter_available (avi->adapter) >= 12) {
5441         GST_DEBUG ("Found LIST tag, skipping LIST header");
5442         gst_adapter_flush (avi->adapter, 12);
5443         continue;
5444       }
5445       return GST_FLOW_OK;
5446     } else if (tag == GST_RIFF_TAG_JUNK || tag == GST_RIFF_TAG_JUNQ) {
5447       /* rec list might contain JUNK chunks */
5448       GST_DEBUG ("Found JUNK tag");
5449       if (gst_avi_demux_peek_chunk (avi, &tag, &size) || size == 0) {
5450         /* accept 0 size buffer here */
5451         avi->abort_buffering = FALSE;
5452         GST_DEBUG ("  skipping %d bytes for now", size);
5453         gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
5454       }
5455       return GST_FLOW_OK;
5456     } else {
5457       GST_DEBUG ("No more stream chunks, send EOS");
5458       avi->have_eos = TRUE;
5459       return GST_FLOW_EOS;
5460     }
5461
5462     if (G_UNLIKELY (!gst_avi_demux_peek_chunk (avi, &tag, &size))) {
5463       /* supposedly one hopes to catch a nicer chunk later on ... */
5464       /* FIXME ?? give up here rather than possibly ending up going
5465        * through the whole file */
5466       if (avi->abort_buffering) {
5467         avi->abort_buffering = FALSE;
5468         if (size) {
5469           gst_adapter_flush (avi->adapter, 8);
5470           return GST_FLOW_OK;
5471         }
5472       } else {
5473         return GST_FLOW_OK;
5474       }
5475     }
5476     GST_DEBUG ("chunk ID %" GST_FOURCC_FORMAT ", size %u",
5477         GST_FOURCC_ARGS (tag), size);
5478
5479     stream_nr = CHUNKID_TO_STREAMNR (tag);
5480
5481     if (G_UNLIKELY (stream_nr < 0 || stream_nr >= avi->num_streams)) {
5482       /* recoverable */
5483       GST_WARNING ("Invalid stream ID %d (%" GST_FOURCC_FORMAT ")",
5484           stream_nr, GST_FOURCC_ARGS (tag));
5485       avi->offset += 8 + GST_ROUND_UP_2 (size);
5486       gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
5487     } else {
5488       GstAviStream *stream;
5489       GstClockTime next_ts = 0;
5490       GstBuffer *buf = NULL;
5491 #if 0
5492       guint64 offset;
5493 #endif
5494       gboolean saw_desired_kf = stream_nr != avi->main_stream
5495           || avi->offset >= avi->seek_kf_offset;
5496
5497       if (stream_nr == avi->main_stream && avi->offset == avi->seek_kf_offset) {
5498         GST_DEBUG_OBJECT (avi, "Desired keyframe reached");
5499         avi->seek_kf_offset = 0;
5500       }
5501
5502       if (saw_desired_kf) {
5503         gst_adapter_flush (avi->adapter, 8);
5504         /* get buffer */
5505         if (size) {
5506           buf = gst_adapter_take_buffer (avi->adapter, GST_ROUND_UP_2 (size));
5507           /* patch the size */
5508           gst_buffer_resize (buf, 0, size);
5509         } else {
5510           buf = NULL;
5511         }
5512       } else {
5513         GST_DEBUG_OBJECT (avi,
5514             "Desired keyframe not yet reached, flushing chunk");
5515         gst_adapter_flush (avi->adapter, 8 + GST_ROUND_UP_2 (size));
5516       }
5517
5518 #if 0
5519       offset = avi->offset;
5520 #endif
5521       avi->offset += 8 + GST_ROUND_UP_2 (size);
5522
5523       stream = &avi->stream[stream_nr];
5524
5525       /* set delay (if any)
5526          if (stream->strh->init_frames == stream->current_frame &&
5527          stream->delay == 0)
5528          stream->delay = next_ts;
5529        */
5530
5531       /* parsing of corresponding header may have failed */
5532       if (G_UNLIKELY (!stream->pad)) {
5533         GST_WARNING_OBJECT (avi, "no pad for stream ID %" GST_FOURCC_FORMAT,
5534             GST_FOURCC_ARGS (tag));
5535         if (buf)
5536           gst_buffer_unref (buf);
5537       } else {
5538         /* get time of this buffer */
5539         gst_pad_query_position (stream->pad, GST_FORMAT_TIME,
5540             (gint64 *) & next_ts);
5541
5542 #if 0
5543         gst_avi_demux_add_assoc (avi, stream, next_ts, offset, FALSE);
5544 #endif
5545
5546         /* increment our positions */
5547         stream->current_entry++;
5548         /* as in pull mode, 'total' is either bytes (CBR) or frames (VBR) */
5549         if (stream->strh->type == GST_RIFF_FCC_auds && stream->is_vbr) {
5550           gint blockalign = stream->strf.auds->blockalign;
5551           if (blockalign > 0)
5552             stream->current_total += DIV_ROUND_UP (size, blockalign);
5553           else
5554             stream->current_total++;
5555         } else {
5556           stream->current_total += size;
5557         }
5558         GST_LOG_OBJECT (avi, "current entry %u, total %u",
5559             stream->current_entry, stream->current_total);
5560
5561         /* update current position in the segment */
5562         avi->segment.position = next_ts;
5563
5564         if (saw_desired_kf && buf) {
5565           GstClockTime dur_ts = 0;
5566
5567           /* invert the picture if needed, and append palette for RGB8P */
5568           buf = gst_avi_demux_invert (stream, buf);
5569
5570           gst_pad_query_position (stream->pad, GST_FORMAT_TIME,
5571               (gint64 *) & dur_ts);
5572
5573           GST_BUFFER_DTS (buf) = next_ts;
5574           GST_BUFFER_PTS (buf) = GST_CLOCK_TIME_NONE;
5575           GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
5576           if (stream->strh->type == GST_RIFF_FCC_vids) {
5577             GST_BUFFER_OFFSET (buf) = stream->current_entry - 1;
5578             GST_BUFFER_OFFSET_END (buf) = stream->current_entry;
5579           } else {
5580             GST_BUFFER_OFFSET (buf) = GST_BUFFER_OFFSET_NONE;
5581             GST_BUFFER_OFFSET_END (buf) = GST_BUFFER_OFFSET_NONE;
5582           }
5583
5584           GST_DEBUG_OBJECT (avi,
5585               "Pushing buffer with time=%" GST_TIME_FORMAT ", duration %"
5586               GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT
5587               " and size %d over pad %s", GST_TIME_ARGS (next_ts),
5588               GST_TIME_ARGS (GST_BUFFER_DURATION (buf)),
5589               GST_BUFFER_OFFSET (buf), size, GST_PAD_NAME (stream->pad));
5590
5591           /* mark discont when pending */
5592           if (G_UNLIKELY (stream->discont)) {
5593             GST_DEBUG_OBJECT (avi, "Setting DISCONT");
5594             GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
5595             stream->discont = FALSE;
5596           } else {
5597             GST_BUFFER_FLAG_UNSET (buf, GST_BUFFER_FLAG_DISCONT);
5598           }
5599
5600           if (stream->alignment > 1)
5601             buf = gst_avi_demux_align_buffer (avi, buf, stream->alignment);
5602           res = gst_pad_push (stream->pad, buf);
5603           buf = NULL;
5604
5605           /* combine flows */
5606           res = gst_avi_demux_combine_flows (avi, stream, res);
5607           if (G_UNLIKELY (res != GST_FLOW_OK)) {
5608             GST_DEBUG ("Push failed; %s", gst_flow_get_name (res));
5609             return res;
5610           }
5611         }
5612       }
5613     }
5614   }
5615
5616   return res;
5617 }
5618
5619 /*
5620  * Send pending tags.
5621  */
5622 static void
5623 push_tag_lists (GstAviDemux * avi)
5624 {
5625   guint i;
5626   GstTagList *tags;
5627
5628   if (!avi->got_tags)
5629     return;
5630
5631   GST_DEBUG_OBJECT (avi, "Pushing pending tag lists");
5632
5633   for (i = 0; i < avi->num_streams; i++) {
5634     GstAviStream *stream = &avi->stream[i];
5635     GstPad *pad = stream->pad;
5636
5637     tags = stream->taglist;
5638
5639     if (pad && tags) {
5640       GST_DEBUG_OBJECT (pad, "Tags: %" GST_PTR_FORMAT, tags);
5641
5642       gst_pad_push_event (pad, gst_event_new_tag (tags));
5643       stream->taglist = NULL;
5644     }
5645   }
5646
5647   if (!(tags = avi->globaltags))
5648     tags = gst_tag_list_new_empty ();
5649
5650   gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE,
5651       GST_TAG_CONTAINER_FORMAT, "AVI", NULL);
5652
5653   GST_DEBUG_OBJECT (avi, "Global tags: %" GST_PTR_FORMAT, tags);
5654   gst_tag_list_set_scope (tags, GST_TAG_SCOPE_GLOBAL);
5655   gst_avi_demux_push_event (avi, gst_event_new_tag (tags));
5656   avi->globaltags = NULL;
5657   avi->got_tags = FALSE;
5658 }
5659
5660 static void
5661 gst_avi_demux_loop (GstPad * pad)
5662 {
5663   GstFlowReturn res;
5664   GstAviDemux *avi = GST_AVI_DEMUX (GST_PAD_PARENT (pad));
5665
5666   switch (avi->state) {
5667     case GST_AVI_DEMUX_START:
5668       res = gst_avi_demux_stream_init_pull (avi);
5669       if (G_UNLIKELY (res != GST_FLOW_OK)) {
5670         GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res));
5671         goto pause;
5672       }
5673       avi->state = GST_AVI_DEMUX_HEADER;
5674       /* fall-through */
5675     case GST_AVI_DEMUX_HEADER:
5676       res = gst_avi_demux_stream_header_pull (avi);
5677       if (G_UNLIKELY (res != GST_FLOW_OK)) {
5678         GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res));
5679         goto pause;
5680       }
5681       avi->state = GST_AVI_DEMUX_MOVI;
5682       break;
5683     case GST_AVI_DEMUX_MOVI:
5684       if (G_UNLIKELY (avi->seg_event)) {
5685         gst_avi_demux_push_event (avi, avi->seg_event);
5686         avi->seg_event = NULL;
5687       }
5688       if (G_UNLIKELY (avi->got_tags)) {
5689         push_tag_lists (avi);
5690       }
5691       /* process each index entry in turn */
5692       res = gst_avi_demux_loop_data (avi);
5693
5694       /* pause when error */
5695       if (G_UNLIKELY (res != GST_FLOW_OK)) {
5696         GST_INFO ("stream_movi flow: %s", gst_flow_get_name (res));
5697         goto pause;
5698       }
5699       break;
5700     default:
5701       GST_ERROR_OBJECT (avi, "unknown state %d", avi->state);
5702       res = GST_FLOW_ERROR;
5703       goto pause;
5704   }
5705
5706   return;
5707
5708   /* ERRORS */
5709 pause:{
5710
5711     gboolean push_eos = FALSE;
5712     GST_LOG_OBJECT (avi, "pausing task, reason %s", gst_flow_get_name (res));
5713     gst_pad_pause_task (avi->sinkpad);
5714
5715     if (res == GST_FLOW_EOS) {
5716       /* handle end-of-stream/segment */
5717       /* so align our position with the end of it, if there is one
5718        * this ensures a subsequent will arrive at correct base/acc time */
5719       if (avi->segment.rate > 0.0 &&
5720           GST_CLOCK_TIME_IS_VALID (avi->segment.stop))
5721         avi->segment.position = avi->segment.stop;
5722       else if (avi->segment.rate < 0.0)
5723         avi->segment.position = avi->segment.start;
5724       if (avi->segment.flags & GST_SEEK_FLAG_SEGMENT) {
5725         gint64 stop;
5726         GstEvent *event;
5727         GstMessage *msg;
5728
5729         if ((stop = avi->segment.stop) == -1)
5730           stop = avi->segment.duration;
5731
5732         GST_INFO_OBJECT (avi, "sending segment_done");
5733
5734         msg =
5735             gst_message_new_segment_done (GST_OBJECT_CAST (avi),
5736             GST_FORMAT_TIME, stop);
5737         if (avi->segment_seqnum)
5738           gst_message_set_seqnum (msg, avi->segment_seqnum);
5739         gst_element_post_message (GST_ELEMENT_CAST (avi), msg);
5740
5741         event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
5742         if (avi->segment_seqnum)
5743           gst_event_set_seqnum (event, avi->segment_seqnum);
5744         gst_avi_demux_push_event (avi, event);
5745       } else {
5746         push_eos = TRUE;
5747       }
5748     } else if (res == GST_FLOW_NOT_LINKED || res < GST_FLOW_EOS) {
5749       /* for fatal errors we post an error message, wrong-state is
5750        * not fatal because it happens due to flushes and only means
5751        * that we should stop now. */
5752       GST_ELEMENT_FLOW_ERROR (avi, res);
5753       push_eos = TRUE;
5754     }
5755     if (push_eos) {
5756       GstEvent *event;
5757
5758       GST_INFO_OBJECT (avi, "sending eos");
5759       event = gst_event_new_eos ();
5760       if (avi->segment_seqnum)
5761         gst_event_set_seqnum (event, avi->segment_seqnum);
5762       if (!gst_avi_demux_push_event (avi, event) && (res == GST_FLOW_EOS)) {
5763         GST_ELEMENT_ERROR (avi, STREAM, DEMUX,
5764             (NULL), ("got eos but no streams (yet)"));
5765       }
5766     }
5767   }
5768 }
5769
5770
5771 static GstFlowReturn
5772 gst_avi_demux_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
5773 {
5774   GstFlowReturn res;
5775   GstAviDemux *avi = GST_AVI_DEMUX (parent);
5776   gint i;
5777
5778   if (GST_BUFFER_IS_DISCONT (buf)) {
5779     GST_DEBUG_OBJECT (avi, "got DISCONT");
5780     gst_adapter_clear (avi->adapter);
5781     /* mark all streams DISCONT */
5782     for (i = 0; i < avi->num_streams; i++)
5783       avi->stream[i].discont = TRUE;
5784   }
5785
5786   GST_DEBUG ("Store %" G_GSIZE_FORMAT " bytes in adapter",
5787       gst_buffer_get_size (buf));
5788   gst_adapter_push (avi->adapter, buf);
5789
5790   switch (avi->state) {
5791     case GST_AVI_DEMUX_START:
5792       if ((res = gst_avi_demux_stream_init_push (avi)) != GST_FLOW_OK) {
5793         GST_WARNING ("stream_init flow: %s", gst_flow_get_name (res));
5794         break;
5795       }
5796       break;
5797     case GST_AVI_DEMUX_HEADER:
5798       if ((res = gst_avi_demux_stream_header_push (avi)) != GST_FLOW_OK) {
5799         GST_WARNING ("stream_header flow: %s", gst_flow_get_name (res));
5800         break;
5801       }
5802       break;
5803     case GST_AVI_DEMUX_MOVI:
5804       if (G_UNLIKELY (avi->seg_event)) {
5805         gst_avi_demux_push_event (avi, avi->seg_event);
5806         avi->seg_event = NULL;
5807       }
5808       if (G_UNLIKELY (avi->got_tags)) {
5809         push_tag_lists (avi);
5810       }
5811       res = gst_avi_demux_stream_data (avi);
5812       break;
5813     case GST_AVI_DEMUX_SEEK:
5814     {
5815       GstEvent *event;
5816
5817       res = GST_FLOW_OK;
5818
5819       /* obtain and parse indexes */
5820       if (avi->stream[0].indexes && !gst_avi_demux_read_subindexes_push (avi))
5821         /* seek in subindex read function failed */
5822         goto index_failed;
5823
5824       if (!avi->stream[0].indexes && !avi->have_index
5825           && avi->avih->flags & GST_RIFF_AVIH_HASINDEX)
5826         gst_avi_demux_stream_index_push (avi);
5827
5828       if (avi->have_index) {
5829         /* use the indexes now to construct nice durations */
5830         gst_avi_demux_calculate_durations_from_index (avi);
5831       } else {
5832         /* still parsing indexes */
5833         break;
5834       }
5835
5836       GST_OBJECT_LOCK (avi);
5837       event = avi->seek_event;
5838       avi->seek_event = NULL;
5839       GST_OBJECT_UNLOCK (avi);
5840
5841       /* calculate and perform seek */
5842       if (!avi_demux_handle_seek_push (avi, avi->sinkpad, event)) {
5843         gst_event_unref (event);
5844         goto seek_failed;
5845       }
5846
5847       gst_event_unref (event);
5848       avi->state = GST_AVI_DEMUX_MOVI;
5849       break;
5850     }
5851     default:
5852       GST_ELEMENT_ERROR (avi, STREAM, FAILED, (NULL),
5853           ("Illegal internal state"));
5854       res = GST_FLOW_ERROR;
5855       break;
5856   }
5857
5858   GST_DEBUG_OBJECT (avi, "state: %d res:%s", avi->state,
5859       gst_flow_get_name (res));
5860
5861   if (G_UNLIKELY (avi->abort_buffering))
5862     goto abort_buffering;
5863
5864   return res;
5865
5866   /* ERRORS */
5867 index_failed:
5868   {
5869     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("failed to read indexes"));
5870     return GST_FLOW_ERROR;
5871   }
5872 seek_failed:
5873   {
5874     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("push mode seek failed"));
5875     return GST_FLOW_ERROR;
5876   }
5877 abort_buffering:
5878   {
5879     avi->abort_buffering = FALSE;
5880     GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL), ("unhandled buffer size"));
5881     return GST_FLOW_ERROR;
5882   }
5883 }
5884
5885 static gboolean
5886 gst_avi_demux_sink_activate (GstPad * sinkpad, GstObject * parent)
5887 {
5888   GstQuery *query;
5889   gboolean pull_mode;
5890
5891   query = gst_query_new_scheduling ();
5892
5893   if (!gst_pad_peer_query (sinkpad, query)) {
5894     gst_query_unref (query);
5895     goto activate_push;
5896   }
5897
5898   pull_mode = gst_query_has_scheduling_mode_with_flags (query,
5899       GST_PAD_MODE_PULL, GST_SCHEDULING_FLAG_SEEKABLE);
5900   gst_query_unref (query);
5901
5902   if (!pull_mode)
5903     goto activate_push;
5904
5905   GST_DEBUG_OBJECT (sinkpad, "activating pull");
5906   return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PULL, TRUE);
5907
5908 activate_push:
5909   {
5910     GST_DEBUG_OBJECT (sinkpad, "activating push");
5911     return gst_pad_activate_mode (sinkpad, GST_PAD_MODE_PUSH, TRUE);
5912   }
5913 }
5914
5915 static gboolean
5916 gst_avi_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
5917     GstPadMode mode, gboolean active)
5918 {
5919   gboolean res;
5920   GstAviDemux *avi = GST_AVI_DEMUX (parent);
5921
5922   switch (mode) {
5923     case GST_PAD_MODE_PULL:
5924       if (active) {
5925         avi->streaming = FALSE;
5926         res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_avi_demux_loop,
5927             sinkpad, NULL);
5928       } else {
5929         res = gst_pad_stop_task (sinkpad);
5930       }
5931       break;
5932     case GST_PAD_MODE_PUSH:
5933       if (active) {
5934         GST_DEBUG ("avi: activating push/chain function");
5935         avi->streaming = TRUE;
5936       } else {
5937         GST_DEBUG ("avi: deactivating push/chain function");
5938       }
5939       res = TRUE;
5940       break;
5941     default:
5942       res = FALSE;
5943       break;
5944   }
5945   return res;
5946 }
5947
5948 #if 0
5949 static void
5950 gst_avi_demux_set_index (GstElement * element, GstIndex * index)
5951 {
5952   GstAviDemux *avi = GST_AVI_DEMUX (element);
5953
5954   GST_OBJECT_LOCK (avi);
5955   if (avi->element_index)
5956     gst_object_unref (avi->element_index);
5957   if (index) {
5958     avi->element_index = gst_object_ref (index);
5959   } else {
5960     avi->element_index = NULL;
5961   }
5962   GST_OBJECT_UNLOCK (avi);
5963   /* object lock might be taken again */
5964   if (index)
5965     gst_index_get_writer_id (index, GST_OBJECT_CAST (element), &avi->index_id);
5966   GST_DEBUG_OBJECT (avi, "Set index %" GST_PTR_FORMAT, avi->element_index);
5967 }
5968
5969 static GstIndex *
5970 gst_avi_demux_get_index (GstElement * element)
5971 {
5972   GstIndex *result = NULL;
5973   GstAviDemux *avi = GST_AVI_DEMUX (element);
5974
5975   GST_OBJECT_LOCK (avi);
5976   if (avi->element_index)
5977     result = gst_object_ref (avi->element_index);
5978   GST_OBJECT_UNLOCK (avi);
5979
5980   GST_DEBUG_OBJECT (avi, "Returning index %" GST_PTR_FORMAT, result);
5981
5982   return result;
5983 }
5984 #endif
5985
5986 static GstStateChangeReturn
5987 gst_avi_demux_change_state (GstElement * element, GstStateChange transition)
5988 {
5989   GstStateChangeReturn ret;
5990   GstAviDemux *avi = GST_AVI_DEMUX (element);
5991
5992   switch (transition) {
5993     case GST_STATE_CHANGE_READY_TO_PAUSED:
5994       avi->streaming = FALSE;
5995       gst_segment_init (&avi->segment, GST_FORMAT_TIME);
5996       break;
5997     default:
5998       break;
5999   }
6000
6001   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
6002   if (ret == GST_STATE_CHANGE_FAILURE)
6003     goto done;
6004
6005   switch (transition) {
6006     case GST_STATE_CHANGE_PAUSED_TO_READY:
6007       avi->have_index = FALSE;
6008       gst_avi_demux_reset (avi);
6009       break;
6010     default:
6011       break;
6012   }
6013
6014 done:
6015   return ret;
6016 }