2 * Copyright (C) <1999> Erik Walthinsen <omega@temple-baptist.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 /* #define GST_DEBUG_ENABLED */
24 #include "gstavidemux.h"
27 /* elementfactory information */
28 static GstElementDetails gst_avi_demux_details = {
31 "Parse a .avi file into audio and video",
33 "Erik Walthinsen <omega@cse.ogi.edu>\n"
34 "Wim Taymans <wim.taymans@tvd.be>",
38 static GstCaps* avi_typefind (GstBuffer *buf, gpointer private);
40 /* typefactory for 'avi' */
41 static GstTypeDefinition avidefinition = {
48 /* AviDemux signals and args */
63 GST_PADTEMPLATE_FACTORY (sink_templ,
70 "format", GST_PROPS_STRING ("AVI")
74 GST_PADTEMPLATE_FACTORY (src_video_templ,
81 "format", GST_PROPS_LIST (
82 GST_PROPS_STRING ("strf_vids"),
83 GST_PROPS_STRING ("strf_iavs")
85 "width", GST_PROPS_INT_RANGE (16, 4096),
86 "height", GST_PROPS_INT_RANGE (16, 4096)
92 "format", GST_PROPS_LIST (
93 GST_PROPS_FOURCC (GST_MAKE_FOURCC('Y','U','Y','2')),
94 GST_PROPS_FOURCC (GST_MAKE_FOURCC('I','4','2','0'))
96 "width", GST_PROPS_INT_RANGE (16, 4096),
97 "height", GST_PROPS_INT_RANGE (16, 4096)
100 "avidemux_src_video",
102 "width", GST_PROPS_INT_RANGE (16, 4096),
103 "height", GST_PROPS_INT_RANGE (16, 4096)
106 "avidemux_src_video",
108 "format", GST_PROPS_LIST (
109 GST_PROPS_STRING ("NTSC"),
110 GST_PROPS_STRING ("PAL")
112 "width", GST_PROPS_INT_RANGE (16, 4096),
113 "height", GST_PROPS_INT_RANGE (16, 4096)
117 GST_PADTEMPLATE_FACTORY (src_audio_templ,
122 "avidemux_src_audio",
124 "format", GST_PROPS_STRING ("strf_auds")
127 "avidemux_src_audio",
129 "format", GST_PROPS_STRING ("int"),
130 "law", GST_PROPS_INT (0),
131 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
132 "signed", GST_PROPS_LIST (
133 GST_PROPS_BOOLEAN (TRUE),
134 GST_PROPS_BOOLEAN (FALSE)
136 "width", GST_PROPS_LIST (
140 "depth", GST_PROPS_LIST (
144 "rate", GST_PROPS_INT_RANGE (11025, 44100),
145 "channels", GST_PROPS_INT_RANGE (1, 2)
148 "avidemux_src_audio",
154 static void gst_avi_demux_class_init (GstAviDemuxClass *klass);
155 static void gst_avi_demux_init (GstAviDemux *avi_demux);
157 static void gst_avi_demux_loop (GstElement *element);
159 static GstElementStateReturn
160 gst_avi_demux_change_state (GstElement *element);
162 static void gst_avi_demux_get_property (GObject *object, guint prop_id,
163 GValue *value, GParamSpec *pspec);
166 static GstElementClass *parent_class = NULL;
167 /*static guint gst_avi_demux_signals[LAST_SIGNAL] = { 0 }; */
170 gst_avi_demux_get_type(void)
172 static GType avi_demux_type = 0;
174 if (!avi_demux_type) {
175 static const GTypeInfo avi_demux_info = {
176 sizeof(GstAviDemuxClass),
179 (GClassInitFunc)gst_avi_demux_class_init,
184 (GInstanceInitFunc)gst_avi_demux_init,
186 avi_demux_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviDemux", &avi_demux_info, 0);
188 return avi_demux_type;
192 gst_avi_demux_class_init (GstAviDemuxClass *klass)
194 GObjectClass *gobject_class;
195 GstElementClass *gstelement_class;
197 gobject_class = (GObjectClass*)klass;
198 gstelement_class = (GstElementClass*)klass;
200 g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_BITRATE,
201 g_param_spec_long ("bitrate","bitrate","bitrate",
202 G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
203 g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_MEDIA_TIME,
204 g_param_spec_long ("media_time","media_time","media_time",
205 G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
206 g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_CURRENT_TIME,
207 g_param_spec_long ("current_time","current_time","current_time",
208 G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
209 g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_FRAME_RATE,
210 g_param_spec_int ("frame-rate","frame rate","Current (non-averaged) frame rate",
211 0, G_MAXINT, 0, G_PARAM_READABLE));
213 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
215 gobject_class->get_property = gst_avi_demux_get_property;
217 gstelement_class->change_state = gst_avi_demux_change_state;
221 gst_avi_demux_init (GstAviDemux *avi_demux)
225 GST_FLAG_SET (avi_demux, GST_ELEMENT_EVENT_AWARE);
227 avi_demux->sinkpad = gst_pad_new_from_template (
228 GST_PADTEMPLATE_GET (sink_templ), "sink");
229 gst_element_add_pad (GST_ELEMENT (avi_demux), avi_demux->sinkpad);
231 gst_element_set_loop_function (GST_ELEMENT (avi_demux), gst_avi_demux_loop);
233 avi_demux->state = GST_AVI_DEMUX_UNKNOWN;
234 avi_demux->num_audio_pads = 0;
235 avi_demux->num_video_pads = 0;
236 /*avi_demux->next_time = 500000; */
237 avi_demux->next_time = 0;
238 avi_demux->init_audio = 0;
239 avi_demux->flags = 0;
240 avi_demux->index_entries = NULL;
241 avi_demux->index_size = 0;
242 avi_demux->resync_offset = 0;
244 /*GST_FLAG_SET( GST_OBJECT (avi_demux), GST_ELEMENT_NO_SEEK); */
246 for(i=0; i<GST_AVI_DEMUX_MAX_AUDIO_PADS; i++)
247 avi_demux->audio_pad[i] = NULL;
249 for(i=0; i<GST_AVI_DEMUX_MAX_VIDEO_PADS; i++)
250 avi_demux->video_pad[i] = NULL;
255 avi_typefind (GstBuffer *buf,
258 gchar *data = GST_BUFFER_DATA (buf);
261 GST_DEBUG (0,"avi_demux: typefind\n");
263 if (GUINT32_FROM_LE (((guint32 *)data)[0]) != GST_RIFF_TAG_RIFF)
265 if (GUINT32_FROM_LE (((guint32 *)data)[2]) != GST_RIFF_RIFF_AVI)
268 new = GST_CAPS_NEW ("avi_typefind",
270 "format", GST_PROPS_STRING ("AVI"));
276 gst_avi_demux_avih (GstAviDemux *avi_demux)
279 GstByteStream *bs = avi_demux->bs;
281 avih = (gst_riff_avih *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_avih));
283 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: avih tag found");
284 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: us_frame %d", GUINT32_FROM_LE (avih->us_frame));
285 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: max_bps %d", GUINT32_FROM_LE (avih->max_bps));
286 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: pad_gran %d", GUINT32_FROM_LE (avih->pad_gran));
287 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: flags 0x%08x", GUINT32_FROM_LE (avih->flags));
288 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: tot_frames %d", GUINT32_FROM_LE (avih->tot_frames));
289 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: init_frames %d", GUINT32_FROM_LE (avih->init_frames));
290 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: streams %d", GUINT32_FROM_LE (avih->streams));
291 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: bufsize %d", GUINT32_FROM_LE (avih->bufsize));
292 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: width %d", GUINT32_FROM_LE (avih->width));
293 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: height %d", GUINT32_FROM_LE (avih->height));
294 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: scale %d", GUINT32_FROM_LE (avih->scale));
295 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: rate %d", GUINT32_FROM_LE (avih->rate));
296 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: start %d", GUINT32_FROM_LE (avih->start));
297 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: length %d", GUINT32_FROM_LE (avih->length));
299 avi_demux->time_interval = GUINT32_FROM_LE (avih->us_frame);
300 avi_demux->tot_frames = GUINT32_FROM_LE (avih->tot_frames);
301 avi_demux->flags = GUINT32_FROM_LE (avih->flags);
309 gst_avi_demux_strh (GstAviDemux *avi_demux)
312 GstByteStream *bs = avi_demux->bs;
314 strh = (gst_riff_strh *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_strh));
316 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strh tag found");
317 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: type 0x%08x (%s)",
318 GUINT32_FROM_LE (strh->type), gst_riff_id_to_fourcc (strh->type));
319 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: fcc_handler 0x%08x (%s)",
320 GUINT32_FROM_LE (strh->fcc_handler), gst_riff_id_to_fourcc (strh->fcc_handler));
321 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: flags 0x%08x", GUINT32_FROM_LE (strh->flags));
322 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: priority %d", GUINT32_FROM_LE (strh->priority));
323 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: init_frames %d", GUINT32_FROM_LE (strh->init_frames));
324 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: scale %d", GUINT32_FROM_LE (strh->scale));
325 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: rate %d", GUINT32_FROM_LE (strh->rate));
326 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: start %d", GUINT32_FROM_LE (strh->start));
327 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: length %d", GUINT32_FROM_LE (strh->length));
328 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: bufsize %d", GUINT32_FROM_LE (strh->bufsize));
329 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: quality %d", GUINT32_FROM_LE (strh->quality));
330 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: samplesize %d", GUINT32_FROM_LE (strh->samplesize));
332 avi_demux->fcc_type = GUINT32_FROM_LE (strh->type);
333 if (strh->type == GST_RIFF_FCC_auds) {
336 scale = GUINT32_FROM_LE (strh->scale);
337 avi_demux->init_audio = GUINT32_FROM_LE (strh->init_frames);
340 avi_demux->audio_rate = GUINT32_FROM_LE (strh->rate) / scale;
342 else if (strh->type == GST_RIFF_FCC_vids) {
345 scale = GUINT32_FROM_LE (strh->scale);
348 avi_demux->frame_rate = (gint) GUINT32_FROM_LE (strh->rate) / scale;
349 g_object_notify (G_OBJECT (avi_demux), "frame-rate");
358 gst_avi_demux_strf_vids (GstAviDemux *avi_demux)
360 gst_riff_strf_vids *strf;
362 GstByteStream *bs = avi_demux->bs;
363 GstCaps *newcaps = NULL, *capslist = NULL;
365 strf = (gst_riff_strf_vids *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_strf_vids));
367 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context vids");
368 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: size %d", GUINT32_FROM_LE (strf->size));
369 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: width %d", GUINT32_FROM_LE (strf->width));
370 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: height %d", GUINT32_FROM_LE (strf->height));
371 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: planes %d", GUINT16_FROM_LE (strf->planes));
372 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: bit_cnt %d", GUINT16_FROM_LE (strf->bit_cnt));
373 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: compression 0x%08x (%s)",
374 GUINT32_FROM_LE (strf->compression), gst_riff_id_to_fourcc (strf->compression));
375 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: image_size %d", GUINT32_FROM_LE (strf->image_size));
376 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: xpels_meter %d", GUINT32_FROM_LE (strf->xpels_meter));
377 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: ypels_meter %d", GUINT32_FROM_LE (strf->ypels_meter));
378 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: num_colors %d", GUINT32_FROM_LE (strf->num_colors));
379 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: imp_colors %d", GUINT32_FROM_LE (strf->imp_colors));
381 srcpad = gst_pad_new_from_template (
382 GST_PADTEMPLATE_GET (src_video_templ), g_strdup_printf ("video_%02d",
383 avi_demux->num_video_pads));
385 capslist = gst_caps_append(NULL, GST_CAPS_NEW (
386 "avidemux_video_src",
388 "format", GST_PROPS_STRING ("strf_vids"),
389 "size", GST_PROPS_INT (GUINT32_FROM_LE (strf->size)),
390 "width", GST_PROPS_INT (GUINT32_FROM_LE (strf->width)),
391 "height", GST_PROPS_INT (GUINT32_FROM_LE (strf->height)),
392 "planes", GST_PROPS_INT (GUINT16_FROM_LE (strf->planes)),
393 "bit_cnt", GST_PROPS_INT (GUINT16_FROM_LE (strf->bit_cnt)),
394 "compression", GST_PROPS_FOURCC (GUINT32_FROM_LE (strf->compression)),
395 "image_size", GST_PROPS_INT (GUINT32_FROM_LE (strf->image_size)),
396 "xpels_meter", GST_PROPS_INT (GUINT32_FROM_LE (strf->xpels_meter)),
397 "ypels_meter", GST_PROPS_INT (GUINT32_FROM_LE (strf->ypels_meter)),
398 "num_colors", GST_PROPS_INT (GUINT32_FROM_LE (strf->num_colors)),
399 "imp_colors", GST_PROPS_INT (GUINT32_FROM_LE (strf->imp_colors))
402 /* let's try some gstreamer-like mime-type caps */
403 switch (GUINT32_FROM_LE(strf->compression))
405 case GST_MAKE_FOURCC('I','4','2','0'):
406 case GST_MAKE_FOURCC('Y','U','Y','2'):
407 newcaps = GST_CAPS_NEW (
408 "avidemux_video_src",
410 "format", GST_PROPS_FOURCC(GUINT32_FROM_LE(strf->compression)),
411 "width", GST_PROPS_INT(strf->width),
412 "height", GST_PROPS_INT(strf->height)
415 case GST_MAKE_FOURCC('M','J','P','G'):
416 newcaps = GST_CAPS_NEW (
417 "avidemux_video_src",
419 "width", GST_PROPS_INT(strf->width),
420 "height", GST_PROPS_INT(strf->height)
423 case GST_MAKE_FOURCC('d','v','s','d'):
424 newcaps = GST_CAPS_NEW (
425 "avidemux_video_src",
427 "format", GST_PROPS_STRING("NTSC"), /* FIXME??? */
428 "width", GST_PROPS_INT(strf->width),
429 "height", GST_PROPS_INT(strf->height)
434 if (newcaps) capslist = gst_caps_append(capslist, newcaps);
436 gst_pad_try_set_caps(srcpad, capslist);
438 avi_demux->video_pad[avi_demux->num_video_pads++] = srcpad;
439 gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
443 gst_avi_demux_strf_auds (GstAviDemux *avi_demux)
445 gst_riff_strf_auds *strf;
447 GstByteStream *bs = avi_demux->bs;
448 GstCaps *newcaps = NULL, *capslist = NULL;
450 strf = (gst_riff_strf_auds *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_strf_auds));
452 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context auds");
453 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: format %d", GUINT16_FROM_LE (strf->format));
454 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: channels %d", GUINT16_FROM_LE (strf->channels));
455 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: rate %d", GUINT32_FROM_LE (strf->rate));
456 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: av_bps %d", GUINT32_FROM_LE (strf->av_bps));
457 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: blockalign %d", GUINT16_FROM_LE (strf->blockalign));
458 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: size %d", GUINT16_FROM_LE (strf->size));
460 srcpad = gst_pad_new_from_template (
461 GST_PADTEMPLATE_GET (src_audio_templ), g_strdup_printf ("audio_%02d",
462 avi_demux->num_audio_pads));
464 capslist = gst_caps_append(NULL, GST_CAPS_NEW (
465 "avidemux_audio_src",
467 "format", GST_PROPS_STRING ("strf_auds"),
468 "fmt", GST_PROPS_INT (GUINT16_FROM_LE (strf->format)),
469 "channels", GST_PROPS_INT (GUINT16_FROM_LE (strf->channels)),
470 "rate", GST_PROPS_INT (GUINT32_FROM_LE (strf->rate)),
471 "av_bps", GST_PROPS_INT (GUINT32_FROM_LE (strf->av_bps)),
472 "blockalign", GST_PROPS_INT (GUINT16_FROM_LE (strf->blockalign)),
473 "size", GST_PROPS_INT (GUINT16_FROM_LE (strf->size))
476 /* let's try some gstreamer-formatted mime types */
477 switch (GUINT16_FROM_LE(strf->format))
480 case 0x0055: /* mp3 */
481 newcaps = gst_caps_new ("avidemux_audio_src",
485 case 0x0001: /* PCM/wav */
486 newcaps = gst_caps_new ("avidemux_audio_src",
489 "format", GST_PROPS_STRING ("int"),
490 "law", GST_PROPS_INT (0),
491 "endianness", GST_PROPS_INT (G_BYTE_ORDER),
492 "signed", GST_PROPS_BOOLEAN ((GUINT16_FROM_LE (strf->size) != 8)),
493 "width", GST_PROPS_INT ((GUINT16_FROM_LE (strf->blockalign)*8) /
494 GUINT16_FROM_LE (strf->channels)),
495 "depth", GST_PROPS_INT (GUINT16_FROM_LE (strf->size)),
496 "rate", GST_PROPS_INT (GUINT32_FROM_LE (strf->rate)),
497 "channels", GST_PROPS_INT (GUINT16_FROM_LE (strf->channels)),
503 if (newcaps) capslist = gst_caps_append(capslist, newcaps);
505 gst_pad_try_set_caps(srcpad, capslist);
507 avi_demux->audio_pad[avi_demux->num_audio_pads++] = srcpad;
508 gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
512 gst_avi_demux_strf_iavs (GstAviDemux *avi_demux)
514 gst_riff_strf_iavs *strf;
516 GstByteStream *bs = avi_demux->bs;
517 GstCaps *newcaps = NULL, *capslist = NULL;
519 strf = (gst_riff_strf_iavs *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_strf_iavs));
521 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context iavs");
522 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVAAuxSrc %08x", GUINT32_FROM_LE (strf->DVAAuxSrc));
523 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVAAuxCtl %08x", GUINT32_FROM_LE (strf->DVAAuxCtl));
524 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVAAuxSrc1 %08x", GUINT32_FROM_LE (strf->DVAAuxSrc1));
525 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVAAuxCtl1 %08x", GUINT32_FROM_LE (strf->DVAAuxCtl1));
526 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVVAuxSrc %08x", GUINT32_FROM_LE (strf->DVVAuxSrc));
527 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVVAuxCtl %08x", GUINT32_FROM_LE (strf->DVVAuxCtl));
528 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVReserved1 %08x", GUINT32_FROM_LE (strf->DVReserved1));
529 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVReserved2 %08x", GUINT32_FROM_LE (strf->DVReserved2));
531 srcpad = gst_pad_new_from_template (
532 GST_PADTEMPLATE_GET (src_video_templ), g_strdup_printf ("video_%02d",
533 avi_demux->num_video_pads));
535 capslist = gst_caps_append(NULL, GST_CAPS_NEW (
536 "avidemux_video_src",
538 "format", GST_PROPS_STRING ("strf_iavs"),
539 "DVAAuxSrc", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxSrc)),
540 "DVAAuxCtl", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxCtl)),
541 "DVAAuxSrc1", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxSrc1)),
542 "DVAAuxCtl1", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxCtl1)),
543 "DVVAuxSrc", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVVAuxSrc)),
544 "DVVAuxCtl", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVVAuxCtl)),
545 "DVReserved1", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVReserved1)),
546 "DVReserved2", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVReserved2))
549 newcaps = gst_caps_new ("avi_type_dv",
552 "format", GST_PROPS_STRING ("NTSC"), /* FIXME??? */
555 if (newcaps) capslist = gst_caps_append(capslist, newcaps);
557 gst_pad_try_set_caps(srcpad, capslist);
559 avi_demux->video_pad[avi_demux->num_video_pads++] = srcpad;
560 gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
564 gst_avidemux_parse_index (GstAviDemux *avi_demux,
565 gulong filepos, gulong offset)
570 if (!gst_bytestream_seek (avi_demux->bs, GST_SEEK_BYTEOFFSET_SET, filepos + offset)) {
571 GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek to index");
574 buf = gst_bytestream_read (avi_demux->bs, 8);
579 gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
581 buf = gst_bytestream_read (avi_demux->bs, 8);
584 if (GST_BUFFER_OFFSET (buf) != filepos + offset || GST_BUFFER_SIZE (buf) != 8) {
585 GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not get index");
589 if (gst_riff_fourcc_to_id (GST_BUFFER_DATA (buf)) != GST_RIFF_TAG_idx1) {
590 GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: no index found");
594 index_size = GUINT32_FROM_LE(*(guint32 *)(GST_BUFFER_DATA (buf) + 4));
595 gst_buffer_unref (buf);
597 buf = gst_bytestream_read (avi_demux->bs, index_size);
599 avi_demux->index_size = index_size/sizeof(gst_riff_index_entry);
601 GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: index size %lu", avi_demux->index_size);
603 avi_demux->index_entries = g_malloc (GST_BUFFER_SIZE (buf));
604 memcpy (avi_demux->index_entries, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf));
605 gst_buffer_unref (buf);
607 if (!gst_bytestream_seek (avi_demux->bs, GST_SEEK_BYTEOFFSET_SET, filepos)) {
608 GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not seek back to movi");
614 gst_avidemux_handle_event (GstAviDemux *avi_demux)
620 gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
622 type = event? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
626 gst_pad_event_default (avi_demux->sinkpad, event);
629 g_warning ("seek event\n");
631 case GST_EVENT_FLUSH:
632 g_warning ("flush event\n");
634 case GST_EVENT_DISCONTINUOUS:
635 g_warning ("discont event\n");
638 g_warning ("unhandled event %d\n", type);
645 static inline gboolean
646 gst_avidemux_read_chunk (GstAviDemux *avi_demux, guint32 *id, guint32 *size)
648 gst_riff_chunk *chunk;
649 GstByteStream *bs = avi_demux->bs;
652 chunk = (gst_riff_chunk *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_chunk));
654 *id = GUINT32_FROM_LE (chunk->id);
655 *size = GUINT32_FROM_LE (chunk->size);
657 gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
661 } while (gst_avidemux_handle_event (avi_demux));
667 gst_avidemux_process_chunk (GstAviDemux *avi_demux, guint64 *filepos,
669 gint rec_depth, guint32 *chunksize)
672 GstByteStream *bs = avi_demux->bs;
674 if (!gst_avidemux_read_chunk (avi_demux, &chunkid, chunksize)) {
675 g_print (" ***** Error reading chunk at filepos 0x%08llx\n", *filepos);
678 if (desired_tag) { /* do we have to test identity? */
679 if (desired_tag != chunkid) {
680 g_print ("\n\n *** Error: Expected chunk '%s', found '%s'\n",
681 gst_riff_id_to_fourcc (desired_tag),
682 gst_riff_id_to_fourcc (chunkid));
687 GST_INFO (GST_CAT_PLUGIN_INFO, "chunkid %s, size %08x, filepos %08llx",
688 gst_riff_id_to_fourcc (chunkid), *chunksize, *filepos);
690 *filepos += (sizeof (guint32) + sizeof (guint32));
693 case GST_RIFF_TAG_RIFF:
694 case GST_RIFF_TAG_LIST:
697 guint32 subchunksize = 0; /* size of a read subchunk */
700 formtype = gst_bytestream_peek_bytes (bs, sizeof (guint32));
704 switch (GUINT32_FROM_LE (*((guint32*)formtype))) {
705 case GST_RIFF_LIST_movi:
706 gst_avidemux_parse_index (avi_demux, *filepos, *chunksize);
707 while (!gst_bytestream_flush (bs, sizeof (guint32))) {
711 gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
715 /* flush the form type */
716 gst_bytestream_flush_fast (bs, sizeof (guint32));
720 datashowed = sizeof (guint32); /* we showed the form type */
721 *filepos += datashowed; /* for the rest of the routine */
723 while (datashowed < *chunksize) { /* while not showed all: */
725 GST_INFO (GST_CAT_PLUGIN_INFO, "process chunk filepos %08llx", *filepos);
726 /* recurse for subchunks of RIFF and LIST chunks: */
727 if (!gst_avidemux_process_chunk (avi_demux, filepos, 0,
728 rec_depth + 1, &subchunksize))
731 subchunksize = ((subchunksize + 1) & ~1);
733 datashowed += (sizeof (guint32) + sizeof (guint32) + subchunksize);
734 GST_INFO (GST_CAT_PLUGIN_INFO, "process chunk done filepos %08llx, subchunksize %08x",
735 *filepos, subchunksize);
737 if (datashowed != *chunksize) {
738 g_warning ("error parsing AVI");
742 case GST_RIFF_TAG_avih:
743 gst_avi_demux_avih (avi_demux);
745 case GST_RIFF_TAG_strh:
747 gst_avi_demux_strh (avi_demux);
750 case GST_RIFF_TAG_strf:
751 switch (avi_demux->fcc_type) {
752 case GST_RIFF_FCC_vids:
753 gst_avi_demux_strf_vids (avi_demux);
755 case GST_RIFF_FCC_auds:
756 gst_avi_demux_strf_auds (avi_demux);
758 case GST_RIFF_FCC_iavs:
759 gst_avi_demux_strf_iavs (avi_demux);
761 case GST_RIFF_FCC_pads:
762 case GST_RIFF_FCC_txts:
764 GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux_chain: strh type %s not supported", gst_riff_id_to_fourcc (avi_demux->fcc_type));
772 GST_DEBUG (0,"gst_avi_demux_chain: tag found %08x size %08x\n",
773 chunkid, *chunksize);
775 if (GST_PAD_IS_CONNECTED (avi_demux->video_pad[0])) {
779 buf = gst_bytestream_peek (bs, *chunksize);
781 GST_BUFFER_TIMESTAMP (buf) = avi_demux->next_time;
783 avi_demux->next_time += avi_demux->time_interval;
785 if (avi_demux->video_need_flush[0]) {
786 /* FIXME, do some flush event here */
787 avi_demux->video_need_flush[0] = FALSE;
790 GST_DEBUG (0,"gst_avi_demux_chain: send video buffer %08x\n", *chunksize);
791 gst_pad_push(avi_demux->video_pad[0], buf);
792 GST_DEBUG (0,"gst_avi_demux_chain: sent video buffer %08x %p\n",
793 *chunksize, &avi_demux->video_pad[0]);
794 avi_demux->current_frame++;
797 *chunksize = (*chunksize + 1) & ~1;
802 GST_DEBUG (0,"gst_avi_demux_chain: tag found %08x size %08x\n",
803 chunkid, *chunksize);
805 if (avi_demux->init_audio) {
806 /*avi_demux->next_time += (*chunksize) * 1000000LL / avi_demux->audio_rate; */
807 avi_demux->init_audio--;
810 if (GST_PAD_IS_CONNECTED (avi_demux->audio_pad[0])) {
814 buf = gst_bytestream_peek (bs, *chunksize);
816 GST_BUFFER_TIMESTAMP (buf) = -1LL;
818 if (avi_demux->audio_need_flush[0]) {
819 GST_DEBUG (0,"audio flush\n");
820 avi_demux->audio_need_flush[0] = FALSE;
821 /* FIXME, do some flush event here */
824 GST_DEBUG (0,"gst_avi_demux_chain: send audio buffer %08x\n", *chunksize);
825 gst_pad_push (avi_demux->audio_pad[0], buf);
826 GST_DEBUG (0,"gst_avi_demux_chain: sent audio buffer %08x\n", *chunksize);
829 *chunksize = (*chunksize + 1) & ~1;
833 GST_DEBUG (0, " ***** unknown chunkid %08x (%s)\n", chunkid, gst_riff_id_to_fourcc (chunkid));
834 *chunksize = (*chunksize + 1) & ~1;
837 GST_INFO (GST_CAT_PLUGIN_INFO, "chunkid %s, flush %08x, filepos %08llx",
838 gst_riff_id_to_fourcc (chunkid), *chunksize, *filepos);
840 *filepos += *chunksize;
841 if (!gst_bytestream_flush (bs, *chunksize)) {
842 return gst_avidemux_handle_event (avi_demux);
846 /* we are running in an infinite loop, we need to _yield
847 * from time to time */
848 gst_element_yield (GST_ELEMENT (avi_demux));
854 gst_avi_demux_loop (GstElement *element)
856 GstAviDemux *avi_demux;
860 g_return_if_fail (element != NULL);
861 g_return_if_fail (GST_IS_AVI_DEMUX (element));
863 avi_demux = GST_AVI_DEMUX (element);
865 /* this is basically an infinite loop */
866 if (!gst_avidemux_process_chunk (avi_demux, &filepos, GST_RIFF_TAG_RIFF, 0, &chunksize)) {
867 gst_element_error (element, "This doesn't appear to be an AVI file");
870 /* if we exit the loop we are EOS */
871 gst_pad_event_default (avi_demux->sinkpad, gst_event_new (GST_EVENT_EOS));
874 static GstElementStateReturn
875 gst_avi_demux_change_state (GstElement *element)
877 GstAviDemux *avi_demux = GST_AVI_DEMUX (element);
879 switch (GST_STATE_TRANSITION (element)) {
880 case GST_STATE_NULL_TO_READY:
882 case GST_STATE_READY_TO_PAUSED:
883 avi_demux->bs = gst_bytestream_new (avi_demux->sinkpad);
885 case GST_STATE_PAUSED_TO_PLAYING:
887 case GST_STATE_PLAYING_TO_PAUSED:
889 case GST_STATE_PAUSED_TO_READY:
890 gst_bytestream_destroy (avi_demux->bs);
892 case GST_STATE_READY_TO_NULL:
898 parent_class->change_state (element);
900 return GST_STATE_SUCCESS;
904 gst_avi_demux_get_property (GObject *object, guint prop_id, GValue *value,
909 g_return_if_fail (GST_IS_AVI_DEMUX (object));
911 src = GST_AVI_DEMUX (object);
917 g_value_set_long (value, (src->tot_frames * src->time_interval) / 1000000);
919 case ARG_CURRENT_TIME:
920 g_value_set_long (value, (src->current_frame * src->time_interval) / 1000000);
923 g_value_set_int (value, (src->frame_rate));
931 plugin_init (GModule *module, GstPlugin *plugin)
933 GstElementFactory *factory;
934 GstTypeFactory *type;
936 /* this filter needs the riff parser */
937 if (!gst_library_load ("gstbytestream")) {
938 gst_info("avidemux: could not load support library: 'gstbytestream'\n");
941 if (!gst_library_load ("gstriff")) {
942 gst_info("avidemux: could not load support library: 'gstriff'\n");
946 /* create an elementfactory for the avi_demux element */
947 factory = gst_elementfactory_new ("avidemux",GST_TYPE_AVI_DEMUX,
948 &gst_avi_demux_details);
949 g_return_val_if_fail (factory != NULL, FALSE);
951 gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_audio_templ));
952 gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_video_templ));
953 gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sink_templ));
955 type = gst_typefactory_new (&avidefinition);
956 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type));
958 gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
963 GstPluginDesc plugin_desc = {