gstavidemux.c 49.7 KB
Newer Older
1
2
/* GStreamer
 * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */


21
/* #define GST_DEBUG_ENABLED */
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
22
23
24
25
26
27
28
#include <string.h>

#include "gstavidemux.h"


/* elementfactory information */
static GstElementDetails gst_avi_demux_details = {
29
30
  "Avi demuxer",
  "Codec/Demuxer",
31
  "LGPL",
32
  "Demultiplex an avi file into audio and video",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
33
34
35
36
37
38
  VERSION,
  "Erik Walthinsen <omega@cse.ogi.edu>\n"
  "Wim Taymans <wim.taymans@tvd.be>",
  "(C) 1999",
};

39
static GstCaps* avi_type_find (GstBuffer *buf, gpointer private);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
40
41
42
43
44
45

/* typefactory for 'avi' */
static GstTypeDefinition avidefinition = {
  "avidemux_video/avi",
  "video/avi",
  ".avi",
46
  avi_type_find,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
47
48
49
50
51
52
53
54
55
56
57
58
59
60
};

/* AviDemux signals and args */
enum {
  /* FILL ME */
  LAST_SIGNAL
};

enum {
  ARG_0,
  ARG_BITRATE,
  /* FILL ME */
};

61
GST_PAD_TEMPLATE_FACTORY (sink_templ,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
62
63
64
65
66
67
  "sink",
  GST_PAD_SINK,
  GST_PAD_ALWAYS,
  GST_CAPS_NEW (
    "avidemux_sink",
     "video/avi",
68
      "format",    GST_PROPS_STRING ("AVI")
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
69
70
71
  )
)

72
GST_PAD_TEMPLATE_FACTORY (src_video_templ,
Wim Taymans's avatar
Wim Taymans committed
73
  "video_%02d",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
74
  GST_PAD_SRC,
75
  GST_PAD_SOMETIMES,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
76
  GST_CAPS_NEW (
Ronald S. Bultje's avatar
Ronald S. Bultje committed
77
    "avidemux_src_video",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
78
79
80
81
    "video/avi",
      "format",  GST_PROPS_LIST (
	           GST_PROPS_STRING ("strf_vids"),
	           GST_PROPS_STRING ("strf_iavs")
Ronald S. Bultje's avatar
Ronald S. Bultje committed
82
83
84
85
      		 ),
      "width",   GST_PROPS_INT_RANGE (16, 4096),
      "height",  GST_PROPS_INT_RANGE (16, 4096)

Ronald S. Bultje's avatar
Ronald S. Bultje committed
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  ),
  GST_CAPS_NEW (
    "avidemux_src_video",
    "video/raw",
      "format",  GST_PROPS_LIST (
                   GST_PROPS_FOURCC (GST_MAKE_FOURCC('Y','U','Y','2')),
                   GST_PROPS_FOURCC (GST_MAKE_FOURCC('I','4','2','0'))
                 ),
      "width",          GST_PROPS_INT_RANGE (16, 4096),
      "height",         GST_PROPS_INT_RANGE (16, 4096)
  ),
  GST_CAPS_NEW (
    "avidemux_src_video",
    "video/jpeg",
      "width",   GST_PROPS_INT_RANGE (16, 4096),
      "height",  GST_PROPS_INT_RANGE (16, 4096)
  ),
  GST_CAPS_NEW (
    "avidemux_src_video",
    "video/dv",
      "format",  GST_PROPS_LIST (
                   GST_PROPS_STRING ("NTSC"),
                   GST_PROPS_STRING ("PAL")
Ronald S. Bultje's avatar
Ronald S. Bultje committed
109
110
111
                 ),
      "width",   GST_PROPS_INT_RANGE (16, 4096),
      "height",  GST_PROPS_INT_RANGE (16, 4096)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
112
113
114
  )
)

115
GST_PAD_TEMPLATE_FACTORY (src_audio_templ,
Wim Taymans's avatar
Wim Taymans committed
116
  "audio_%02d",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
117
  GST_PAD_SRC,
118
  GST_PAD_SOMETIMES,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
119
  GST_CAPS_NEW (
Ronald S. Bultje's avatar
Ronald S. Bultje committed
120
    "avidemux_src_audio",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
121
    "video/avi",
Ronald S. Bultje's avatar
Ronald S. Bultje committed
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
      "format",  GST_PROPS_STRING ("strf_auds")
  ),
  GST_CAPS_NEW (
    "avidemux_src_audio",
    "audio/raw",
      "format",           GST_PROPS_STRING ("int"),
      "law",              GST_PROPS_INT (0),
      "endianness",       GST_PROPS_INT (G_BYTE_ORDER),
      "signed",           GST_PROPS_LIST (
      			    GST_PROPS_BOOLEAN (TRUE),
      			    GST_PROPS_BOOLEAN (FALSE)
			  ),
      "width",            GST_PROPS_LIST (
      			    GST_PROPS_INT (8),
      			    GST_PROPS_INT (16)
			  ),
      "depth",            GST_PROPS_LIST (
      			    GST_PROPS_INT (8),
      			    GST_PROPS_INT (16)
			  ),
      "rate",             GST_PROPS_INT_RANGE (11025, 44100),
      "channels",         GST_PROPS_INT_RANGE (1, 2)
  ),
  GST_CAPS_NEW (
    "avidemux_src_audio",
147
    "audio/x-mp3",
Ronald S. Bultje's avatar
Ronald S. Bultje committed
148
      NULL
149
150
151
152
153
  ),
  GST_CAPS_NEW (
    "avidemux_src_audio",
    "application/x-ogg",
    NULL
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
154
155
156
  )
)

157
158
static void 		gst_avi_demux_class_init		(GstAviDemuxClass *klass);
static void 		gst_avi_demux_init			(GstAviDemux *avi_demux);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
159

160
static void 		gst_avi_demux_loop 			(GstElement *element);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
161

162
163
164
static gboolean 	gst_avi_demux_process_chunk 		(GstAviDemux *avi_demux, guint64 *filepos,
				    				 guint32 desired_tag,
				    				 gint rec_depth, guint32 *chunksize);
165

166
static gboolean 	gst_avi_demux_send_event 		(GstElement *element, GstEvent *event);
167

168
169
170
171
static const GstEventMask*
			gst_avi_demux_get_event_mask 		(GstPad *pad);
static gboolean 	gst_avi_demux_handle_src_event 		(GstPad *pad, GstEvent *event);
static const GstFormat* gst_avi_demux_get_src_formats 		(GstPad *pad); 
Wim Taymans's avatar
Wim Taymans committed
172
static const GstQueryType*
173
			gst_avi_demux_get_src_query_types 	(GstPad *pad);
Wim Taymans's avatar
Wim Taymans committed
174
static gboolean 	gst_avi_demux_handle_src_query 		(GstPad *pad, GstQueryType type, 
175
176
177
								 GstFormat *format, gint64 *value);
static gboolean 	gst_avi_demux_src_convert 		(GstPad *pad, GstFormat src_format, gint64 src_value,
	        	          				 GstFormat *dest_format, gint64 *dest_value);
Wim Taymans's avatar
Wim Taymans committed
178

Wim Taymans's avatar
Wim Taymans committed
179
static GstElementStateReturn
180
			gst_avi_demux_change_state 		(GstElement *element);
Wim Taymans's avatar
Wim Taymans committed
181

182
183
static void     	gst_avi_demux_get_property      	(GObject *object, guint prop_id, 	
								 GValue *value, GParamSpec *pspec);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
184
185
186


static GstElementClass *parent_class = NULL;
187
/*static guint gst_avi_demux_signals[LAST_SIGNAL] = { 0 }; */
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221

GType
gst_avi_demux_get_type(void) 
{
  static GType avi_demux_type = 0;

  if (!avi_demux_type) {
    static const GTypeInfo avi_demux_info = {
      sizeof(GstAviDemuxClass),      
      NULL,
      NULL,
      (GClassInitFunc)gst_avi_demux_class_init,
      NULL,
      NULL,
      sizeof(GstAviDemux),
      0,
      (GInstanceInitFunc)gst_avi_demux_init,
    };
    avi_demux_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviDemux", &avi_demux_info, 0);
  }
  return avi_demux_type;
}

static void
gst_avi_demux_class_init (GstAviDemuxClass *klass) 
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

  gobject_class = (GObjectClass*)klass;
  gstelement_class = (GstElementClass*)klass;

  g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_BITRATE,
    g_param_spec_long ("bitrate","bitrate","bitrate",
222
                       G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
223
224
225
226

  parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
  
  gobject_class->get_property = gst_avi_demux_get_property;
Wim Taymans's avatar
Wim Taymans committed
227
228
  
  gstelement_class->change_state = gst_avi_demux_change_state;
229
  gstelement_class->send_event = gst_avi_demux_send_event;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
230
231
232
233
234
235
236
237
}

static void 
gst_avi_demux_init (GstAviDemux *avi_demux) 
{
  GST_FLAG_SET (avi_demux, GST_ELEMENT_EVENT_AWARE);
				
  avi_demux->sinkpad = gst_pad_new_from_template (
238
		  GST_PAD_TEMPLATE_GET (sink_templ), "sink");
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
239
240
241
242
  gst_element_add_pad (GST_ELEMENT (avi_demux), avi_demux->sinkpad);

  gst_element_set_loop_function (GST_ELEMENT (avi_demux), gst_avi_demux_loop);

Wim Taymans's avatar
Wim Taymans committed
243
244
245
  avi_demux->num_streams = 0;
  avi_demux->num_v_streams = 0;
  avi_demux->num_a_streams = 0;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
246
247
  avi_demux->index_entries = NULL;
  avi_demux->index_size = 0;
Wim Taymans's avatar
Wim Taymans committed
248
  avi_demux->seek_pending = 0;
249
  avi_demux->restart = FALSE;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
250
251
252
253

}

static GstCaps*
254
avi_type_find (GstBuffer *buf,
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
255
256
257
258
259
              gpointer private)
{
  gchar *data = GST_BUFFER_DATA (buf);
  GstCaps *new;

260
  GST_DEBUG (0,"avi_demux: typefind");
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
261
262
263
264
265
266

  if (GUINT32_FROM_LE (((guint32 *)data)[0]) != GST_RIFF_TAG_RIFF)
    return NULL;
  if (GUINT32_FROM_LE (((guint32 *)data)[2]) != GST_RIFF_RIFF_AVI)
    return NULL;

267
  new = GST_CAPS_NEW ("avi_type_find",
268
		      "video/avi", 
269
		        "format", GST_PROPS_STRING ("AVI"));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
270
271
272
273
274
275
276
  return new;
}

static gboolean
gst_avi_demux_avih (GstAviDemux *avi_demux)
{
  gst_riff_avih *avih;
277
  guint32       got_bytes;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
278
279
  GstByteStream *bs = avi_demux->bs;

280
281
  got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&avih, sizeof (gst_riff_avih));
  if (got_bytes == sizeof (gst_riff_avih)) {
Wim Taymans's avatar
Wim Taymans committed
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
    avi_demux->avih.us_frame 	= GUINT32_FROM_LE (avih->us_frame);
    avi_demux->avih.max_bps 	= GUINT32_FROM_LE (avih->max_bps);
    avi_demux->avih.pad_gran 	= GUINT32_FROM_LE (avih->pad_gran);
    avi_demux->avih.flags 	= GUINT32_FROM_LE (avih->flags);
    avi_demux->avih.tot_frames 	= GUINT32_FROM_LE (avih->tot_frames);
    avi_demux->avih.init_frames = GUINT32_FROM_LE (avih->init_frames);
    avi_demux->avih.streams 	= GUINT32_FROM_LE (avih->streams);
    avi_demux->avih.bufsize 	= GUINT32_FROM_LE (avih->bufsize);
    avi_demux->avih.width 	= GUINT32_FROM_LE (avih->width);
    avi_demux->avih.height 	= GUINT32_FROM_LE (avih->height);
    avi_demux->avih.scale 	= GUINT32_FROM_LE (avih->scale);
    avi_demux->avih.rate 	= GUINT32_FROM_LE (avih->rate);
    avi_demux->avih.start 	= GUINT32_FROM_LE (avih->start);
    avi_demux->avih.length 	= GUINT32_FROM_LE (avih->length);

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
297
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: avih tag found");
Wim Taymans's avatar
Wim Taymans committed
298
299
300
301
302
303
304
305
306
307
308
309
310
311
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  us_frame    %d", avi_demux->avih.us_frame);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  max_bps     %d", avi_demux->avih.max_bps);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  pad_gran    %d", avi_demux->avih.pad_gran);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  flags       0x%08x", avi_demux->avih.flags);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  tot_frames  %d", avi_demux->avih.tot_frames);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  init_frames %d", avi_demux->avih.init_frames);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  streams     %d", avi_demux->avih.streams);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  bufsize     %d", avi_demux->avih.bufsize);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  width       %d", avi_demux->avih.width);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  height      %d", avi_demux->avih.height);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  scale       %d", avi_demux->avih.scale);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  rate        %d", avi_demux->avih.rate);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  start       %d", avi_demux->avih.start);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  length      %d", avi_demux->avih.length);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
312
313
314
315
316
317
318
319
320
321
322

    return TRUE;
  }
  return FALSE;
}

static gboolean 
gst_avi_demux_strh (GstAviDemux *avi_demux)
{
  gst_riff_strh *strh;
  GstByteStream *bs = avi_demux->bs;
323
  guint32       got_bytes;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
324

325
326
  got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&strh, sizeof (gst_riff_strh));
  if (got_bytes == sizeof (gst_riff_strh)) {
Wim Taymans's avatar
Wim Taymans committed
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
    avi_stream_context *target;

    avi_demux->fcc_type = GUINT32_FROM_LE (strh->type);

    target = &avi_demux->stream[avi_demux->num_streams];

    target->num = avi_demux->num_streams;

    target->strh.type 		= avi_demux->fcc_type;
    target->strh.fcc_handler 	= GUINT32_FROM_LE (strh->fcc_handler);
    target->strh.flags		= GUINT32_FROM_LE (strh->flags);
    target->strh.priority	= GUINT32_FROM_LE (strh->priority);
    target->strh.init_frames	= GUINT32_FROM_LE (strh->init_frames);
    target->strh.scale		= GUINT32_FROM_LE (strh->scale);
    target->strh.rate		= GUINT32_FROM_LE (strh->rate);
    target->strh.start		= GUINT32_FROM_LE (strh->start);
    target->strh.length		= GUINT32_FROM_LE (strh->length);
    target->strh.bufsize	= GUINT32_FROM_LE (strh->bufsize);
    target->strh.quality	= GUINT32_FROM_LE (strh->quality);
    target->strh.samplesize	= GUINT32_FROM_LE (strh->samplesize);

    if (!target->strh.scale)
      target->strh.scale = 1; /* avoid division by zero */
    if (!target->strh.rate)
      target->strh.rate = 1; /* avoid division by zero */

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
353
354
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strh tag found");
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  type        0x%08x (%s)", 
Wim Taymans's avatar
Wim Taymans committed
355
  		  target->strh.type, gst_riff_id_to_fourcc (strh->type));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
356
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  fcc_handler 0x%08x (%s)", 
Wim Taymans's avatar
Wim Taymans committed
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
		  target->strh.fcc_handler, gst_riff_id_to_fourcc (strh->fcc_handler));
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  flags       0x%08x", strh->flags);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  priority    %d", target->strh.priority);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  init_frames %d", target->strh.init_frames);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  scale       %d", target->strh.scale);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  rate        %d", target->strh.rate);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  start       %d", target->strh.start);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  length      %d", target->strh.length);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  bufsize     %d", target->strh.bufsize);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  quality     %d", target->strh.quality);
    GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  samplesize  %d", target->strh.samplesize);

    target->delay = 0LL;
    target->total_bytes = 0LL;
    target->total_frames = 0;
Wim Taymans's avatar
Wim Taymans committed
372
    target->end_pos = -1;
Wim Taymans's avatar
Wim Taymans committed
373
374

    target->skip = 0;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
375

376
377
    avi_demux->avih.bufsize = MAX (avi_demux->avih.bufsize, target->strh.bufsize);

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
378
379
380
381
382
    return TRUE;
  }
  return FALSE;
}

383
384
385
386
387
388
389
390
391
392
393
static void
gst_avi_demux_dmlh (GstAviDemux *avi_demux)
{
  gst_riff_dmlh *dmlh;
  guint32 got_bytes;

  got_bytes = gst_bytestream_peek_bytes (avi_demux->bs, (guint8**) &dmlh, sizeof (gst_riff_dmlh));

/*   g_print ("Found total frame: %u\n", dmlh->totalframes); */
}

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
394
395
396
397
398
399
static void 
gst_avi_demux_strf_vids (GstAviDemux *avi_demux)
{
  gst_riff_strf_vids *strf;
  GstPad *srcpad;
  GstByteStream *bs = avi_demux->bs;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
400
  GstCaps *newcaps = NULL, *capslist = NULL;
Wim Taymans's avatar
Wim Taymans committed
401
  avi_stream_context *stream;
402
  guint32       got_bytes;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
403

404
  got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&strf, sizeof (gst_riff_strf_vids));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420

  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context vids");
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  size        %d", GUINT32_FROM_LE (strf->size));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  width       %d", GUINT32_FROM_LE (strf->width));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  height      %d", GUINT32_FROM_LE (strf->height));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  planes      %d", GUINT16_FROM_LE (strf->planes));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  bit_cnt     %d", GUINT16_FROM_LE (strf->bit_cnt));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  compression 0x%08x (%s)", 
		  GUINT32_FROM_LE (strf->compression), gst_riff_id_to_fourcc (strf->compression));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  image_size  %d", GUINT32_FROM_LE (strf->image_size));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  xpels_meter %d", GUINT32_FROM_LE (strf->xpels_meter));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  ypels_meter %d", GUINT32_FROM_LE (strf->ypels_meter));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  num_colors  %d", GUINT32_FROM_LE (strf->num_colors));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  imp_colors  %d", GUINT32_FROM_LE (strf->imp_colors));

  srcpad =  gst_pad_new_from_template (
421
		  GST_PAD_TEMPLATE_GET (src_video_templ), g_strdup_printf ("video_%02d", 
Wim Taymans's avatar
Wim Taymans committed
422
			  avi_demux->num_v_streams));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
423

Ronald S. Bultje's avatar
Ronald S. Bultje committed
424
425
  capslist = gst_caps_append(NULL, GST_CAPS_NEW (
			  "avidemux_video_src",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
426
427
428
429
430
431
432
433
434
435
436
437
			  "video/avi",
			    "format",    	GST_PROPS_STRING ("strf_vids"),
			      "size", 		GST_PROPS_INT (GUINT32_FROM_LE (strf->size)),
			      "width", 		GST_PROPS_INT (GUINT32_FROM_LE (strf->width)),
			      "height", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->height)),
			      "planes", 	GST_PROPS_INT (GUINT16_FROM_LE (strf->planes)),
			      "bit_cnt", 	GST_PROPS_INT (GUINT16_FROM_LE (strf->bit_cnt)),
			      "compression", 	GST_PROPS_FOURCC (GUINT32_FROM_LE (strf->compression)),
			      "image_size", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->image_size)),
			      "xpels_meter", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->xpels_meter)),
			      "ypels_meter", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->ypels_meter)),
			      "num_colors", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->num_colors)),
438
439
			      "imp_colors", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->imp_colors))
			      ));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
440

Ronald S. Bultje's avatar
Ronald S. Bultje committed
441
  /* let's try some gstreamer-like mime-type caps */
Ronald S. Bultje's avatar
Ronald S. Bultje committed
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
  switch (GUINT32_FROM_LE(strf->compression))
  {
    case GST_MAKE_FOURCC('I','4','2','0'):
    case GST_MAKE_FOURCC('Y','U','Y','2'):
      newcaps = GST_CAPS_NEW (
                  "avidemux_video_src",
                  "video/raw",
                    "format",  GST_PROPS_FOURCC(GUINT32_FROM_LE(strf->compression)),
                    "width",   GST_PROPS_INT(strf->width),
                    "height",  GST_PROPS_INT(strf->height)
                );
      break;
    case GST_MAKE_FOURCC('M','J','P','G'):
      newcaps = GST_CAPS_NEW (
                  "avidemux_video_src",
                  "video/jpeg",
                    "width",   GST_PROPS_INT(strf->width),
                    "height",  GST_PROPS_INT(strf->height)
                );
      break;
    case GST_MAKE_FOURCC('d','v','s','d'):
      newcaps = GST_CAPS_NEW (
                  "avidemux_video_src",
                  "video/dv",
                    "format",  GST_PROPS_STRING("NTSC"), /* FIXME??? */
                    "width",   GST_PROPS_INT(strf->width),
                    "height",  GST_PROPS_INT(strf->height)
                );
      break;
  }

Wim Taymans's avatar
Wim Taymans committed
473
  if (newcaps) capslist = gst_caps_append (capslist, newcaps);
Ronald S. Bultje's avatar
Ronald S. Bultje committed
474

Wim Taymans's avatar
Wim Taymans committed
475
  gst_pad_try_set_caps (srcpad, capslist);
476
477
  gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
  gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
Wim Taymans's avatar
Wim Taymans committed
478
  gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
479
  gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
Wim Taymans's avatar
Wim Taymans committed
480
  gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
481
  gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
Wim Taymans's avatar
Wim Taymans committed
482
483
484
485
486
487

  stream = &avi_demux->stream[avi_demux->num_streams];
  stream->pad = srcpad;
  gst_pad_set_element_private (srcpad, stream);
  avi_demux->num_streams++;
  avi_demux->num_v_streams++;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
488

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
489
490
491
492
493
494
495
496
497
  gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
}

static void 
gst_avi_demux_strf_auds (GstAviDemux *avi_demux)
{
  gst_riff_strf_auds *strf;
  GstPad *srcpad;
  GstByteStream *bs = avi_demux->bs;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
498
  GstCaps *newcaps = NULL, *capslist = NULL;
Wim Taymans's avatar
Wim Taymans committed
499
  avi_stream_context *stream;
500
  guint32       got_bytes;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
501

502
  got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&strf, sizeof (gst_riff_strf_auds));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
503
504
505
506
507
508
509
510
511
512

  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context auds");
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  format      %d", GUINT16_FROM_LE (strf->format));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  channels    %d", GUINT16_FROM_LE (strf->channels));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  rate        %d", GUINT32_FROM_LE (strf->rate));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  av_bps      %d", GUINT32_FROM_LE (strf->av_bps));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  blockalign  %d", GUINT16_FROM_LE (strf->blockalign));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  size        %d", GUINT16_FROM_LE (strf->size));

  srcpad =  gst_pad_new_from_template (
513
		  GST_PAD_TEMPLATE_GET (src_audio_templ), g_strdup_printf ("audio_%02d", 
Wim Taymans's avatar
Wim Taymans committed
514
			  avi_demux->num_a_streams));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
515

Ronald S. Bultje's avatar
Ronald S. Bultje committed
516
517
  capslist = gst_caps_append(NULL, GST_CAPS_NEW (
			  "avidemux_audio_src",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
518
519
520
521
522
523
524
			  "video/avi",
			    "format",    	GST_PROPS_STRING ("strf_auds"),
			      "fmt", 		GST_PROPS_INT (GUINT16_FROM_LE (strf->format)),
			      "channels", 	GST_PROPS_INT (GUINT16_FROM_LE (strf->channels)),
			      "rate", 		GST_PROPS_INT (GUINT32_FROM_LE (strf->rate)),
			      "av_bps",		GST_PROPS_INT (GUINT32_FROM_LE (strf->av_bps)),
			      "blockalign",	GST_PROPS_INT (GUINT16_FROM_LE (strf->blockalign)),
525
526
			      "size",		GST_PROPS_INT (GUINT16_FROM_LE (strf->size))
			  ));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
527

Ronald S. Bultje's avatar
Ronald S. Bultje committed
528
529
530
  /* let's try some gstreamer-formatted mime types */
  switch (GUINT16_FROM_LE(strf->format))
  {
531
532
    case GST_RIFF_WAVE_FORMAT_MPEGL3:
    case GST_RIFF_WAVE_FORMAT_MPEGL12: /* mp3 */
Ronald S. Bultje's avatar
Ronald S. Bultje committed
533
      newcaps = gst_caps_new ("avidemux_audio_src",
534
                              "audio/x-mp3",
Ronald S. Bultje's avatar
Ronald S. Bultje committed
535
536
                                NULL);
      break;
537
    case GST_RIFF_WAVE_FORMAT_PCM: /* PCM/wav */
Ronald S. Bultje's avatar
Ronald S. Bultje committed
538
539
540
541
542
543
544
545
      newcaps = gst_caps_new ("avidemux_audio_src",
                              "audio/raw",
                              gst_props_new (
                                "format",     GST_PROPS_STRING ("int"),
                                "law",        GST_PROPS_INT (0),
                                "endianness", GST_PROPS_INT (G_BYTE_ORDER),
                                "signed",     GST_PROPS_BOOLEAN ((GUINT16_FROM_LE (strf->size) != 8)),
                                "width",      GST_PROPS_INT ((GUINT16_FROM_LE (strf->blockalign)*8) /
Wim Taymans's avatar
Wim Taymans committed
546
                                                              GUINT16_FROM_LE (strf->channels)),
Ronald S. Bultje's avatar
Ronald S. Bultje committed
547
548
549
550
551
552
                                "depth",      GST_PROPS_INT (GUINT16_FROM_LE (strf->size)),
                                "rate",       GST_PROPS_INT (GUINT32_FROM_LE (strf->rate)),
                                "channels",   GST_PROPS_INT (GUINT16_FROM_LE (strf->channels)),
                                NULL
                              ));
      break;
553
554
555
556
557
558
559
560
561
562
    case GST_RIFF_WAVE_FORMAT_VORBIS1: /* ogg/vorbis mode 1 */
    case GST_RIFF_WAVE_FORMAT_VORBIS2: /* ogg/vorbis mode 2 */
    case GST_RIFF_WAVE_FORMAT_VORBIS3: /* ogg/vorbis mode 3 */
    case GST_RIFF_WAVE_FORMAT_VORBIS1PLUS: /* ogg/vorbis mode 1+ */
    case GST_RIFF_WAVE_FORMAT_VORBIS2PLUS: /* ogg/vorbis mode 2+ */
    case GST_RIFF_WAVE_FORMAT_VORBIS3PLUS: /* ogg/vorbis mode 3+ */
      newcaps = gst_caps_new ("avidemux_audio_src",
                              "application/x-ogg",
                              NULL);
      break;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
563
564
565
566
  }

  if (newcaps) capslist = gst_caps_append(capslist, newcaps);

Wim Taymans's avatar
Wim Taymans committed
567

Ronald S. Bultje's avatar
Ronald S. Bultje committed
568
  gst_pad_try_set_caps(srcpad, capslist);
569
570
  gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
  gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
Wim Taymans's avatar
Wim Taymans committed
571
  gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
572
  gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
Wim Taymans's avatar
Wim Taymans committed
573
  gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
574
  gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
Wim Taymans's avatar
Wim Taymans committed
575
576
577
578
579
580

  stream = &avi_demux->stream[avi_demux->num_streams];
  stream->pad = srcpad;
  gst_pad_set_element_private (srcpad, stream);
  avi_demux->num_streams++;
  avi_demux->num_a_streams++;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
581

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
582
583
584
585
586
587
588
589
590
  gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
}

static void 
gst_avi_demux_strf_iavs (GstAviDemux *avi_demux)
{
  gst_riff_strf_iavs *strf;
  GstPad *srcpad;
  GstByteStream *bs = avi_demux->bs;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
591
  GstCaps *newcaps = NULL, *capslist = NULL;
Wim Taymans's avatar
Wim Taymans committed
592
  avi_stream_context *stream;
593
  guint32       got_bytes;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
594

595
  got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&strf, sizeof (gst_riff_strf_iavs));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
596
597
598
599
600
601
602
603
604
605
606
607

  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context iavs");
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxSrc   %08x", GUINT32_FROM_LE (strf->DVAAuxSrc));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxCtl   %08x", GUINT32_FROM_LE (strf->DVAAuxCtl));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxSrc1  %08x", GUINT32_FROM_LE (strf->DVAAuxSrc1));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVAAuxCtl1  %08x", GUINT32_FROM_LE (strf->DVAAuxCtl1));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVVAuxSrc   %08x", GUINT32_FROM_LE (strf->DVVAuxSrc));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVVAuxCtl   %08x", GUINT32_FROM_LE (strf->DVVAuxCtl));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVReserved1 %08x", GUINT32_FROM_LE (strf->DVReserved1));
  GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux:  DVReserved2 %08x", GUINT32_FROM_LE (strf->DVReserved2));

  srcpad =  gst_pad_new_from_template (
608
		  GST_PAD_TEMPLATE_GET (src_video_templ), g_strdup_printf ("video_%02d", 
Wim Taymans's avatar
Wim Taymans committed
609
			  avi_demux->num_v_streams));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
610

Ronald S. Bultje's avatar
Ronald S. Bultje committed
611
612
  capslist = gst_caps_append(NULL, GST_CAPS_NEW (
			  "avidemux_video_src",
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
613
614
615
616
617
618
619
620
621
			  "video/avi",
			    "format",    	GST_PROPS_STRING ("strf_iavs"),
                              "DVAAuxSrc", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxSrc)),
                              "DVAAuxCtl", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxCtl)),
                              "DVAAuxSrc1", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxSrc1)),
                              "DVAAuxCtl1", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxCtl1)),
                              "DVVAuxSrc", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVVAuxSrc)),
                              "DVVAuxCtl", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVVAuxCtl)),
                              "DVReserved1", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVReserved1)),
622
623
                              "DVReserved2", 	GST_PROPS_INT (GUINT32_FROM_LE (strf->DVReserved2))
			 ));
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
624

Ronald S. Bultje's avatar
Ronald S. Bultje committed
625
626
627
628
629
630
631
632
  newcaps = gst_caps_new ("avi_type_dv", 
                          "video/dv", 
                          gst_props_new (
                            "format",		GST_PROPS_STRING ("NTSC"), /* FIXME??? */
                            NULL));

  if (newcaps) capslist = gst_caps_append(capslist, newcaps);

Ronald S. Bultje's avatar
Ronald S. Bultje committed
633
  gst_pad_try_set_caps(srcpad, capslist);
634
635
  gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
  gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
Wim Taymans's avatar
Wim Taymans committed
636
  gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
637
  gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
Wim Taymans's avatar
Wim Taymans committed
638
  gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
639
  gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
Wim Taymans's avatar
Wim Taymans committed
640
641
642
643
644
645

  stream = &avi_demux->stream[avi_demux->num_streams];
  stream->pad = srcpad;
  gst_pad_set_element_private (srcpad, stream);
  avi_demux->num_streams++;
  avi_demux->num_v_streams++;
Ronald S. Bultje's avatar
Ronald S. Bultje committed
646

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
647
648
649
650
  gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
}

static void
Wim Taymans's avatar
Wim Taymans committed
651
652
gst_avi_debug_entry (const gchar *prefix, gst_avi_index_entry *entry)
{
Wim Taymans's avatar
Wim Taymans committed
653
  GST_DEBUG (0, "%s: %05d %d %08llx %05d %14lld %08x %08x (%d) %08x", prefix, entry->index_nr, entry->stream_nr, 
Wim Taymans's avatar
Wim Taymans committed
654
655
		  entry->bytes_before, entry->frames_before, entry->ts, entry->flags, entry->offset, 
		  entry->offset, entry->size);
Wim Taymans's avatar
Wim Taymans committed
656
657
658
659
}

static void
gst_avi_demux_parse_index (GstAviDemux *avi_demux,
Wim Taymans's avatar
Wim Taymans committed
660
		          gulong filepos, gulong offset)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
661
662
663
{
  GstBuffer *buf;
  gulong index_size;
664
  guint32 got_bytes;
Wim Taymans's avatar
Wim Taymans committed
665
666
  gint i;
  gst_riff_index_entry *entry;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
667

Wim Taymans's avatar
Wim Taymans committed
668
  if (!gst_bytestream_seek (avi_demux->bs, filepos + offset, GST_SEEK_METHOD_SET)) {
Wim Taymans's avatar
Wim Taymans committed
669
670
671
    GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek to index");
    return;
  }
672
673
  got_bytes = gst_bytestream_read (avi_demux->bs, &buf, 8);
  while (got_bytes < 8) {
Wim Taymans's avatar
Wim Taymans committed
674
675
676
677
    guint32 remaining;
    GstEvent *event;
  
    gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
678
    gst_event_unref (event);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
679

680
    got_bytes = gst_bytestream_read (avi_demux->bs, &buf, 8);
Wim Taymans's avatar
Wim Taymans committed
681
682
683
  }
		  
  if (GST_BUFFER_OFFSET (buf) != filepos + offset || GST_BUFFER_SIZE (buf) != 8) {
Wim Taymans's avatar
Wim Taymans committed
684
685
    GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not get index, got %lld %d, expected %ld", 
		    GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf), filepos + offset);
Wim Taymans's avatar
Wim Taymans committed
686
    goto end;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
687
688
689
690
  }

  if (gst_riff_fourcc_to_id (GST_BUFFER_DATA (buf)) != GST_RIFF_TAG_idx1) {
    GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: no index found");
Wim Taymans's avatar
Wim Taymans committed
691
    goto end;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
692
693
694
  }

  index_size = GUINT32_FROM_LE(*(guint32 *)(GST_BUFFER_DATA (buf) + 4));
Wim Taymans's avatar
Wim Taymans committed
695
  gst_buffer_unref (buf);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
696

697
698
  gst_bytestream_size_hint (avi_demux->bs, index_size);

699
  got_bytes = gst_bytestream_read (avi_demux->bs, &buf, index_size);
Wim Taymans's avatar
Wim Taymans committed
700
701
702
703
  if (got_bytes < index_size) {
    GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: error reading index");
    goto end;
  }
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
704
705
706
707

  avi_demux->index_size = index_size/sizeof(gst_riff_index_entry);
  GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: index size %lu", avi_demux->index_size);

Wim Taymans's avatar
Wim Taymans committed
708
709
710
711
712
713
714
715
  avi_demux->index_entries = g_malloc (avi_demux->index_size * sizeof (gst_avi_index_entry));

  entry = (gst_riff_index_entry *) GST_BUFFER_DATA (buf);

  for (i = 0; i < avi_demux->index_size; i++) {
    avi_stream_context *stream;
    gint stream_nr;
    gst_avi_index_entry *target = &avi_demux->index_entries[i];
716
    GstFormat format;
Wim Taymans's avatar
Wim Taymans committed
717
718

    stream_nr = CHUNKID_TO_STREAMNR (entry[i].id);
Wim Taymans's avatar
Wim Taymans committed
719
720
721
722
723
    if (stream_nr > avi_demux->num_streams || stream_nr < 0) {
      avi_demux->index_entries[i].stream_nr = -1;
      continue;
    }

Wim Taymans's avatar
Wim Taymans committed
724
725
726
727
728
729
730
    target->stream_nr = stream_nr;
    stream = &avi_demux->stream[stream_nr];

    target->index_nr = i;
    target->flags    = entry[i].flags;
    target->size     = entry[i].size;
    target->offset   = entry[i].offset;
Wim Taymans's avatar
Wim Taymans committed
731

732
733
734
735
736
737
738
739
    /* figure out if the index is 0 based or relative to the MOVI start */
    if (i == 0) {
      if (target->offset < filepos)
	avi_demux->index_offset = filepos;
      else
	avi_demux->index_offset = 0;
    }

Wim Taymans's avatar
Wim Taymans committed
740
741
742
    target->bytes_before = stream->total_bytes;
    target->frames_before = stream->total_frames;

743
    format = GST_FORMAT_TIME;
Wim Taymans's avatar
Wim Taymans committed
744
    if (stream->strh.type == GST_RIFF_FCC_auds) {
Wim Taymans's avatar
Wim Taymans committed
745
746
      /* all audio frames are keyframes */
      target->flags |= GST_RIFF_IF_KEYFRAME;
747
    }
Wim Taymans's avatar
Wim Taymans committed
748
      
749
750
    /* constant rate stream */
    if (stream->strh.samplesize) {
751
752
      gst_pad_convert (stream->pad, GST_FORMAT_BYTES, stream->total_bytes,
		                 &format, &target->ts);
Wim Taymans's avatar
Wim Taymans committed
753
    }
754
    /* VBR stream */
Wim Taymans's avatar
Wim Taymans committed
755
    else {
756
757
      gst_pad_convert (stream->pad, GST_FORMAT_UNITS, stream->total_frames,
		                 &format, &target->ts);
Wim Taymans's avatar
Wim Taymans committed
758
759
760
761
762
763
    }
    gst_avi_debug_entry ("index", target);

    stream->total_bytes += target->size;
    stream->total_frames++;
  }
764
765
766
767
768
769
  for (i = 0; i < avi_demux->num_streams; i++) {
    avi_stream_context *stream;

    stream = &avi_demux->stream[i];
    GST_DEBUG (GST_CAT_PLUGIN_INFO, "stream %i: %d frames, %lld bytes", i, stream->total_frames, stream->total_bytes);
  }
Wim Taymans's avatar
Wim Taymans committed
770
  gst_buffer_unref (buf);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
771

Wim Taymans's avatar
Wim Taymans committed
772
end:
773
  GST_DEBUG (GST_CAT_PLUGIN_INFO, "index offset at %08lx", filepos);
Wim Taymans's avatar
Wim Taymans committed
774
775

  if (!gst_bytestream_seek (avi_demux->bs, filepos, GST_SEEK_METHOD_SET)) {
Wim Taymans's avatar
Wim Taymans committed
776
777
    GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek back to movi");
    return;
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
778
779
780
  }
}

Wim Taymans's avatar
Wim Taymans committed
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
static gst_avi_index_entry*
gst_avi_demux_index_next (GstAviDemux *avi_demux, gint stream_nr, gint start, guint32 flags)
{
  gint i;
  gst_avi_index_entry *entry = NULL;

  for (i = start; i < avi_demux->index_size; i++) {
    entry = &avi_demux->index_entries[i];

    if (entry->stream_nr == stream_nr && (entry->flags & flags) == flags) {
      break;
    }
  }

  return entry;
}

static gst_avi_index_entry*
gst_avi_demux_index_entry_for_time (GstAviDemux *avi_demux, gint stream_nr, guint64 time, guint32 flags)
{
  gst_avi_index_entry *entry = NULL, *last_entry = NULL;
  gint i;

  i = -1;
  do {
    entry = gst_avi_demux_index_next (avi_demux, stream_nr, i + 1, flags);
    if (!entry)
      return NULL;

    i = entry->index_nr;

    if (entry->ts <= time) {
      last_entry = entry;
    }
  }
  while (entry->ts <= time);

  return last_entry;
}

821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
static const GstFormat*
gst_avi_demux_get_src_formats (GstPad *pad) 
{
  avi_stream_context *stream = gst_pad_get_element_private (pad);

  static const GstFormat src_a_formats[] = {
    GST_FORMAT_TIME,
    GST_FORMAT_BYTES,
    GST_FORMAT_UNITS,
    0
  };
  static const GstFormat src_v_formats[] = {
    GST_FORMAT_TIME,
    GST_FORMAT_UNITS,
    0
  };

  return (stream->strh.type == GST_RIFF_FCC_auds ? src_a_formats : src_v_formats);
}

841
842
843
844
845
846
847
static gboolean
gst_avi_demux_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
	                   GstFormat *dest_format, gint64 *dest_value)
{
  gboolean res = TRUE;
  avi_stream_context *stream = gst_pad_get_element_private (pad);

848
849
850
851
  if (stream->strh.type != GST_RIFF_FCC_auds && 
		  (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
    return FALSE;

852
853
854
855
  switch (src_format) {
    case GST_FORMAT_TIME:
      switch (*dest_format) {
	case GST_FORMAT_BYTES:
856
          *dest_value = src_value * stream->strh.rate / (stream->strh.scale * GST_SECOND);
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
          break;
        case GST_FORMAT_DEFAULT:
          *dest_format = GST_FORMAT_UNITS;
	case GST_FORMAT_UNITS:
          *dest_value = src_value * stream->strh.rate / (stream->strh.scale * GST_SECOND);
          break;
	default:
	  res = FALSE;
	  break;
      }
      break;
    case GST_FORMAT_BYTES:
    case GST_FORMAT_UNITS:
      switch (*dest_format) {
	case GST_FORMAT_TIME:
872
          *dest_value = ((((gfloat)src_value) * stream->strh.scale)  / stream->strh.rate) * GST_SECOND;
873
874
875
876
877
878
879
880
881
882
883
884
885
	  break;
	default:
	  res = FALSE;
	  break;
      }
      break;
    default:
      res = FALSE;
  }

  return res;
}

Wim Taymans's avatar
Wim Taymans committed
886
static const GstQueryType*
887
888
gst_avi_demux_get_src_query_types (GstPad *pad) 
{
Wim Taymans's avatar
Wim Taymans committed
889
890
891
  static const GstQueryType src_types[] = {
    GST_QUERY_TOTAL,
    GST_QUERY_POSITION,
892
893
894
895
896
897
    0
  };

  return src_types;
}

Wim Taymans's avatar
Wim Taymans committed
898
static gboolean
Wim Taymans's avatar
Wim Taymans committed
899
gst_avi_demux_handle_src_query (GstPad *pad, GstQueryType type, 
Wim Taymans's avatar
Wim Taymans committed
900
901
902
903
904
905
906
				GstFormat *format, gint64 *value)
{
  gboolean res = TRUE;
  //GstAviDemux *avi_demux = GST_AVI_DEMUX (gst_pad_get_parent (pad));
  avi_stream_context *stream = gst_pad_get_element_private (pad);

  switch (type) {
Wim Taymans's avatar
Wim Taymans committed
907
    case GST_QUERY_TOTAL:
Wim Taymans's avatar
Wim Taymans committed
908
909
910
911
912
      switch (*format) {
        case GST_FORMAT_DEFAULT:
          *format = GST_FORMAT_TIME;
          /* fall through */
        case GST_FORMAT_TIME:
913
          *value = (((gfloat)stream->strh.scale) * stream->strh.length / stream->strh.rate) * GST_SECOND;
Wim Taymans's avatar
Wim Taymans committed
914
915
	  break;
        case GST_FORMAT_BYTES:
916
917
918
          if (stream->strh.type == GST_RIFF_FCC_auds) {
            *value = stream->total_bytes;
	  }
Wim Taymans's avatar
Wim Taymans committed
919
920
921
	  else
	    res = FALSE;
	  break;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
922
        case GST_FORMAT_UNITS:
Wim Taymans's avatar
Wim Taymans committed
923
924
          if (stream->strh.type == GST_RIFF_FCC_auds)
            *value = stream->strh.length * stream->strh.samplesize;
925
	  else if (stream->strh.type == GST_RIFF_FCC_vids)
Wim Taymans's avatar
Wim Taymans committed
926
927
928
929
930
931
932
933
934
            *value = stream->strh.length;
	  else
	    res = FALSE;
	  break;
	default:
          res = FALSE;
	  break;
      }
      break;
Wim Taymans's avatar
Wim Taymans committed
935
    case GST_QUERY_POSITION:
Wim Taymans's avatar
Wim Taymans committed
936
937
938
939
940
      switch (*format) {
        case GST_FORMAT_DEFAULT:
          *format = GST_FORMAT_TIME;
          /* fall through */
        case GST_FORMAT_TIME:
941
          if (stream->strh.samplesize) {
942
            *value = (((gfloat)stream->current_byte) * stream->strh.scale / stream->strh.rate) * GST_SECOND;
943
944
	  }
	  else {
945
            *value = (((gfloat)stream->current_frame) * stream->strh.scale / stream->strh.rate) * GST_SECOND;
946
	  }
Wim Taymans's avatar
Wim Taymans committed
947
948
949
950
	  break;
        case GST_FORMAT_BYTES:
          *value = stream->current_byte;
	  break;
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
951
        case GST_FORMAT_UNITS:
952
          if (stream->strh.samplesize) 
Wim Taymans's avatar
Wim Taymans committed
953
            *value = stream->current_byte * stream->strh.samplesize;
954
	  else 
Wim Taymans's avatar
Wim Taymans committed
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
            *value = stream->current_frame;
	  break;
	default:
          res = FALSE;
	  break;
      }
      break;
    default:
      res = FALSE;
      break;
  }

  return res;
}

static gint32
gst_avi_demux_sync_streams (GstAviDemux *avi_demux, guint64 time)
{
  gint i;
Wim Taymans's avatar
Wim Taymans committed
974
  guint32 min_index = G_MAXUINT;
Wim Taymans's avatar
Wim Taymans committed
975
976
977
978
979
980
  avi_stream_context *stream;
  gst_avi_index_entry *entry;

  for (i = 0; i < avi_demux->num_streams; i++) {
    stream = &avi_demux->stream[i];

981
    GST_DEBUG (0, "finding %d for time %lld", i, time);
Wim Taymans's avatar
Wim Taymans committed
982
983
984
985
986
987
988
989

    entry = gst_avi_demux_index_entry_for_time (avi_demux, stream->num, time, GST_RIFF_IF_KEYFRAME);
    if (entry) {
      gst_avi_debug_entry ("sync entry", entry);

      min_index = MIN (entry->index_nr, min_index);
    }
  }
Wim Taymans's avatar
Wim Taymans committed
990
  GST_DEBUG (0, "first index at %d", min_index);
Wim Taymans's avatar
Wim Taymans committed
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
  
  /* now we know the entry we need to sync on. calculate number of frames to
   * skip fro there on and the stream stats */
  for (i = 0; i < avi_demux->num_streams; i++) {
    gst_avi_index_entry *next_entry;
    stream = &avi_demux->stream[i];

    /* next entry */
    next_entry = gst_avi_demux_index_next (avi_demux, stream->num, min_index, 0);
    /* next entry with keyframe */
    entry = gst_avi_demux_index_next (avi_demux, stream->num, min_index, GST_RIFF_IF_KEYFRAME);
    gst_avi_debug_entry ("final sync", entry);

    stream->current_byte = next_entry->bytes_before;
    stream->current_frame = next_entry->frames_before;
    stream->skip = entry->frames_before - next_entry->frames_before;

1008
    GST_DEBUG (0, "%d skip %d", stream->num, stream->skip);
Wim Taymans's avatar
Wim Taymans committed
1009
  }
Wim Taymans's avatar
Wim Taymans committed
1010
  GST_DEBUG (0, "final index at %d", min_index);
Wim Taymans's avatar
Wim Taymans committed
1011
1012
1013
1014

  return min_index;
}

1015
1016
1017
static gboolean
gst_avi_demux_send_event (GstElement *element, GstEvent *event)
{
Wim Taymans's avatar
Wim Taymans committed
1018
  const GList *pads;
1019
1020
1021
1022
1023
1024
1025

  pads = gst_element_get_pad_list (element);

  while (pads) { 
    GstPad *pad = GST_PAD (pads->data);

    if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
Wim Taymans's avatar
Wim Taymans committed
1026
1027
1028
1029
1030
1031
1032
      /* we ref the event here as we might have to try again if the event
       * failed on this pad */
      gst_event_ref (event);
      if (gst_avi_demux_handle_src_event (pad, event)) {
	gst_event_unref (event);
	return TRUE;
      }
1033
1034
1035
1036
1037
    }
    
    pads = g_list_next (pads);
  }
  
Wim Taymans's avatar
Wim Taymans committed
1038
  gst_event_unref (event);
1039
1040
1041
  return FALSE;
}

1042
1043
1044
1045
1046
static const GstEventMask*
gst_avi_demux_get_event_mask (GstPad *pad)
{
  static const GstEventMask masks[] = {
    { GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
Wim Taymans's avatar
Wim Taymans committed
1047
    { GST_EVENT_SEEK_SEGMENT, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
1048
1049
1050
1051
1052
1053
    { 0, }
  };

  return masks;
}
	
Wim Taymans's avatar
Wim Taymans committed
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
static gboolean
gst_avi_demux_handle_src_event (GstPad *pad, GstEvent *event)
{
  gboolean res = TRUE;
  GstAviDemux *avi_demux = GST_AVI_DEMUX (gst_pad_get_parent (pad));
  avi_stream_context *stream;
  
  stream = gst_pad_get_element_private (pad);

  switch (GST_EVENT_TYPE (event)) {
Wim Taymans's avatar
Wim Taymans committed
1064
1065
    case GST_EVENT_SEEK_SEGMENT:
      stream->end_pos = GST_EVENT_SEEK_ENDOFFSET (event);
Wim Taymans's avatar
Wim Taymans committed
1066
    case GST_EVENT_SEEK:
Wim Taymans's avatar
Wim Taymans committed
1067
      GST_DEBUG (0, "seek format %d, %08x", GST_EVENT_SEEK_FORMAT (event), stream->strh.type);
Wim Taymans's avatar
Wim Taymans committed
1068
1069
      switch (GST_EVENT_SEEK_FORMAT (event)) {
	case GST_FORMAT_BYTES:
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
1070
	case GST_FORMAT_UNITS:
Wim Taymans's avatar
Wim Taymans committed
1071
1072
1073
1074
1075
1076
1077
	  break;
	case GST_FORMAT_TIME:
        {
	  gst_avi_index_entry *seek_entry, *entry;
	  gint64 desired_offset = GST_EVENT_SEEK_OFFSET (event);
	  guint32 flags;
          guint64 min_index;
Wim Taymans's avatar
Wim Taymans committed
1078
	  
Wim Taymans's avatar
Wim Taymans committed
1079
1080

	  /* no seek on audio yet */
Wim Taymans's avatar
Wim Taymans committed
1081
1082
1083
1084
	  if (stream->strh.type == GST_RIFF_FCC_auds) {
	    res = FALSE;
	    goto done;
	  }
Wim Taymans's avatar
Wim Taymans committed
1085
          GST_DEBUG (0, "seeking to %lld", desired_offset);
Wim Taymans's avatar
Wim Taymans committed
1086
1087
1088
1089
1090
1091
1092
1093
1094

          flags = GST_RIFF_IF_KEYFRAME;

          entry = gst_avi_demux_index_entry_for_time (avi_demux, stream->num, desired_offset, GST_RIFF_IF_KEYFRAME);
	  if (entry) {
            desired_offset = entry->ts;
	    min_index = gst_avi_demux_sync_streams (avi_demux, desired_offset);
            seek_entry = &avi_demux->index_entries[min_index];
	    
Wim Taymans's avatar
Wim Taymans committed
1095
1096
            gst_avi_debug_entry ("syncing to entry", seek_entry);
	    
Wim Taymans's avatar
Wim Taymans committed
1097
1098
1099
1100
1101
	    avi_demux->seek_offset = seek_entry->offset + avi_demux->index_offset;
            avi_demux->seek_pending = TRUE;
	    avi_demux->last_seek = seek_entry->ts;
	  }
	  else {
Wim Taymans's avatar
Wim Taymans committed
1102
            GST_DEBUG (0, "no index entry found for time %lld", desired_offset);
Wim Taymans's avatar
Wim Taymans committed
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
	    res = FALSE;
	  }
	  break;
	}
	default:
	  res = FALSE;
          break;
      }
      break;
    default:
      res = FALSE;
      break;
  }
Wim Taymans's avatar
Wim Taymans committed
1116
1117
1118
1119

done:
  gst_event_unref (event);

Wim Taymans's avatar
Wim Taymans committed
1120
1121
1122
  return res;
}

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1123
static gboolean
Wim Taymans's avatar
Wim Taymans committed
1124
gst_avi_demux_handle_sink_event (GstAviDemux *avi_demux)
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
{
  guint32 remaining;
  GstEvent *event;
  GstEventType type;
  
  gst_bytestream_get_status (avi_demux->bs, &remaining, &event);

  type = event? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;

  switch (type) {
    case GST_EVENT_EOS:
Wim Taymans's avatar
Wim Taymans committed
1136
      gst_bytestream_flush (avi_demux->bs, remaining);
Wim Taymans's avatar
Wim Taymans committed
1137
      gst_pad_event_default (avi_demux->sinkpad, event);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1138
1139
      break;
    case GST_EVENT_FLUSH:
1140
      g_warning ("flush event");
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1141
1142
      break;
    case GST_EVENT_DISCONTINUOUS:
Wim Taymans's avatar
Wim Taymans committed
1143
1144
    {
      gint i;
Wim Taymans's avatar
Wim Taymans committed
1145
      GstEvent *discont;
Wim Taymans's avatar
Wim Taymans committed
1146
1147
1148
1149

      for (i = 0; i < avi_demux->num_streams; i++) {
        avi_stream_context *stream = &avi_demux->stream[i];

1150
1151
	if (GST_PAD_IS_USABLE (stream->pad)) {
	  GST_DEBUG (GST_CAT_EVENT, "sending discont on %d %lld + %lld = %lld", i, 
Wim Taymans's avatar
Wim Taymans committed
1152
			avi_demux->last_seek, stream->delay, avi_demux->last_seek + stream->delay);
1153
         discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, 
Wim Taymans's avatar
Wim Taymans committed
1154
			avi_demux->last_seek + stream->delay , NULL);
1155
1156
	  gst_pad_push (stream->pad, GST_BUFFER (discont));
	}
Wim Taymans's avatar
Wim Taymans committed
1157
      }
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1158
      break;
Wim Taymans's avatar
Wim Taymans committed
1159
    }
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1160
    default:
1161
      g_warning ("unhandled event %d", type);
Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1162
1163
1164
      break;
  }

Wim Taymans's avatar
Wim Taymans committed
1165
1166
  gst_event_unref (event);

Andy Wingo Wingo's avatar
Andy Wingo Wingo committed
1167
1168
1169
  return TRUE;
}

Wim Taymans's avatar
Wim Taymans committed
1170
static inline gboolean 
Wim Taymans's avatar
Wim Taymans committed
1171
gst_avi_demux_read_chunk (GstAviDemux *avi_demux, guint32 *id, guint32 *size)
Wim Taymans's avatar
Wim Taymans committed
1172
1173
1174
{
  gst_riff_chunk *chunk;
  GstByteStream *bs = avi_demux->bs;
1175
  guint32       got_bytes;
Wim Taymans's avatar
Wim Taymans committed
1176

Wim Taymans's avatar
Wim Taymans committed
1177
  do {
1178
1179
    got_bytes = gst_bytestream_peek_bytes (bs, (guint8**)&chunk, sizeof (gst_riff_chunk));
    if (got_bytes == sizeof (gst_riff_chunk)) {
Wim Taymans's avatar
Wim Taymans committed
1180
1181
      *id =   GUINT32_FROM_LE (chunk->id);
      *size = GUINT32_FROM_LE (chunk->size);
Wim Taymans's avatar
Wim Taymans committed
1182

Wim Taymans's avatar
Wim Taymans committed
1183
      gst_bytestream_flush (bs, sizeof (gst_riff_chunk));