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