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 */
27 #include "gstavidemux.h"
28 #include "gstavimux.h"
30 GST_DEBUG_CATEGORY_STATIC (avidemux_debug);
31 #define GST_CAT_DEFAULT avidemux_debug
33 /* AviDemux signals and args */
47 GST_PAD_TEMPLATE_FACTORY (sink_templ,
58 static void gst_avi_demux_base_init (gpointer g_class);
59 static void gst_avi_demux_class_init (GstAviDemuxClass *klass);
60 static void gst_avi_demux_init (GstAviDemux *avi_demux);
62 static void gst_avi_demux_loop (GstElement *element);
64 static gboolean gst_avi_demux_send_event (GstElement *element,
67 static const GstEventMask *
68 gst_avi_demux_get_event_mask (GstPad *pad);
69 static gboolean gst_avi_demux_handle_src_event (GstPad *pad,
71 static const GstFormat *
72 gst_avi_demux_get_src_formats (GstPad *pad);
73 static const GstQueryType *
74 gst_avi_demux_get_src_query_types (GstPad *pad);
75 static gboolean gst_avi_demux_handle_src_query (GstPad *pad,
79 static gboolean gst_avi_demux_src_convert (GstPad *pad,
82 GstFormat *dest_format,
85 static GstElementStateReturn
86 gst_avi_demux_change_state (GstElement *element);
88 static void gst_avi_demux_get_property (GObject *object,
93 static GstCaps * gst_avi_demux_audio_caps (guint16 codec_id,
94 gst_riff_strf_auds *strf, GstAviDemux *avi_demux);
95 static GstCaps * gst_avi_demux_video_caps (guint32 codec_fcc,
96 gst_riff_strh *strh, gst_riff_strf_vids *strf,
97 GstAviDemux *avi_demux);
98 static GstCaps * gst_avi_demux_iavs_caps (void);
100 static GstPadTemplate *videosrctempl, *audiosrctempl;
101 static GstElementClass *parent_class = NULL;
102 /*static guint gst_avi_demux_signals[LAST_SIGNAL] = { 0 }; */
105 gst_avi_demux_get_type(void)
107 static GType avi_demux_type = 0;
109 if (!avi_demux_type) {
110 static const GTypeInfo avi_demux_info = {
111 sizeof(GstAviDemuxClass),
112 gst_avi_demux_base_init,
114 (GClassInitFunc)gst_avi_demux_class_init,
119 (GInstanceInitFunc)gst_avi_demux_init,
121 avi_demux_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviDemux", &avi_demux_info, 0);
123 return avi_demux_type;
127 gst_avi_demux_base_init (gpointer g_class)
129 static GstElementDetails gst_avi_demux_details = GST_ELEMENT_DETAILS (
132 "Demultiplex an avi file into audio and video",
133 "Erik Walthinsen <omega@cse.ogi.edu>\n"
134 "Wim Taymans <wim.taymans@chello.be>"
136 static guint32 vid_list[] = {
137 GST_MAKE_FOURCC('I','4','2','0'),
138 GST_MAKE_FOURCC('Y','U','Y','2'),
139 GST_MAKE_FOURCC('M','J','P','G'),
140 GST_MAKE_FOURCC('D','V','S','D'),
141 GST_MAKE_FOURCC('W','M','V','1'),
142 GST_MAKE_FOURCC('W','M','V','2'),
143 GST_MAKE_FOURCC('M','P','G','4'),
144 GST_MAKE_FOURCC('M','P','4','2'),
145 GST_MAKE_FOURCC('M','P','4','3'),
146 GST_MAKE_FOURCC('H','F','Y','U'),
147 GST_MAKE_FOURCC('D','I','V','3'),
148 GST_MAKE_FOURCC('M','P','E','G'),
149 GST_MAKE_FOURCC('H','2','6','3'),
150 GST_MAKE_FOURCC('D','I','V','X'),
151 GST_MAKE_FOURCC('X','V','I','D'),
152 GST_MAKE_FOURCC('3','I','V','1'),
155 static gint aud_list[] = {
156 GST_RIFF_WAVE_FORMAT_MPEGL3,
157 GST_RIFF_WAVE_FORMAT_MPEGL12,
158 GST_RIFF_WAVE_FORMAT_PCM,
159 GST_RIFF_WAVE_FORMAT_VORBIS1,
160 GST_RIFF_WAVE_FORMAT_A52,
161 GST_RIFF_WAVE_FORMAT_ALAW,
162 GST_RIFF_WAVE_FORMAT_MULAW,
165 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
167 GstCaps *audcaps = NULL, *vidcaps = NULL, *temp;
169 for (i = 0; aud_list[i] != -1; i++) {
170 temp = gst_avi_demux_audio_caps (aud_list[i], NULL, NULL);
171 audcaps = gst_caps_append (audcaps, temp);
173 audiosrctempl = gst_pad_template_new ("audio_%02d",
177 for (i = 0; vid_list[i] != 0; i++) {
178 temp = gst_avi_demux_video_caps (vid_list[i], NULL, NULL, NULL);
179 vidcaps = gst_caps_append (vidcaps, temp);
181 vidcaps = gst_caps_append (vidcaps,
182 gst_avi_demux_iavs_caps ());
183 videosrctempl = gst_pad_template_new ("video_%02d",
187 gst_element_class_add_pad_template (element_class, audiosrctempl);
188 gst_element_class_add_pad_template (element_class, videosrctempl);
189 gst_element_class_add_pad_template (element_class,
190 GST_PAD_TEMPLATE_GET (sink_templ));
191 gst_element_class_set_details (element_class, &gst_avi_demux_details);
196 gst_avi_demux_class_init (GstAviDemuxClass *klass)
198 GObjectClass *gobject_class;
199 GstElementClass *gstelement_class;
201 gobject_class = (GObjectClass*)klass;
202 gstelement_class = (GstElementClass*)klass;
204 g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_BITRATE,
205 g_param_spec_long ("bitrate","bitrate","bitrate",
206 G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
207 g_object_class_install_property (gobject_class, ARG_METADATA,
208 g_param_spec_boxed ("metadata", "Metadata", "Metadata",
209 GST_TYPE_CAPS, G_PARAM_READABLE));
210 g_object_class_install_property (gobject_class, ARG_STREAMINFO,
211 g_param_spec_boxed ("streaminfo", "Streaminfo", "Streaminfo",
212 GST_TYPE_CAPS, G_PARAM_READABLE));
214 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
216 gobject_class->get_property = gst_avi_demux_get_property;
218 gstelement_class->change_state = gst_avi_demux_change_state;
219 gstelement_class->send_event = gst_avi_demux_send_event;
223 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_PAD_TEMPLATE_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);
235 gst_avi_demux_avih (GstAviDemux *avi_demux)
239 GstByteStream *bs = avi_demux->bs;
242 got_bytes = gst_bytestream_peek_bytes (bs, &avihdata, sizeof (gst_riff_avih));
243 avih = (gst_riff_avih *) avihdata;
245 if (got_bytes == sizeof (gst_riff_avih)) {
246 avi_demux->avih.us_frame = GUINT32_FROM_LE (avih->us_frame);
247 avi_demux->avih.max_bps = GUINT32_FROM_LE (avih->max_bps);
248 avi_demux->avih.pad_gran = GUINT32_FROM_LE (avih->pad_gran);
249 avi_demux->avih.flags = GUINT32_FROM_LE (avih->flags);
250 avi_demux->avih.tot_frames = GUINT32_FROM_LE (avih->tot_frames);
251 avi_demux->avih.init_frames = GUINT32_FROM_LE (avih->init_frames);
252 avi_demux->avih.streams = GUINT32_FROM_LE (avih->streams);
253 avi_demux->avih.bufsize = GUINT32_FROM_LE (avih->bufsize);
254 avi_demux->avih.width = GUINT32_FROM_LE (avih->width);
255 avi_demux->avih.height = GUINT32_FROM_LE (avih->height);
256 avi_demux->avih.scale = GUINT32_FROM_LE (avih->scale);
257 avi_demux->avih.rate = GUINT32_FROM_LE (avih->rate);
258 avi_demux->avih.start = GUINT32_FROM_LE (avih->start);
259 avi_demux->avih.length = GUINT32_FROM_LE (avih->length);
261 GST_INFO ( "gst_avi_demux: avih tag found");
262 GST_INFO ( "gst_avi_demux: us_frame %d", avi_demux->avih.us_frame);
263 GST_INFO ( "gst_avi_demux: max_bps %d", avi_demux->avih.max_bps);
264 GST_INFO ( "gst_avi_demux: pad_gran %d", avi_demux->avih.pad_gran);
265 GST_INFO ( "gst_avi_demux: flags 0x%08x", avi_demux->avih.flags);
266 GST_INFO ( "gst_avi_demux: tot_frames %d", avi_demux->avih.tot_frames);
267 GST_INFO ( "gst_avi_demux: init_frames %d", avi_demux->avih.init_frames);
268 GST_INFO ( "gst_avi_demux: streams %d", avi_demux->avih.streams);
269 GST_INFO ( "gst_avi_demux: bufsize %d", avi_demux->avih.bufsize);
270 GST_INFO ( "gst_avi_demux: width %d", avi_demux->avih.width);
271 GST_INFO ( "gst_avi_demux: height %d", avi_demux->avih.height);
272 GST_INFO ( "gst_avi_demux: scale %d", avi_demux->avih.scale);
273 GST_INFO ( "gst_avi_demux: rate %d", avi_demux->avih.rate);
274 GST_INFO ( "gst_avi_demux: start %d", avi_demux->avih.start);
275 GST_INFO ( "gst_avi_demux: length %d", avi_demux->avih.length);
283 gst_avi_demux_strh (GstAviDemux *avi_demux)
287 GstByteStream *bs = avi_demux->bs;
290 got_bytes = gst_bytestream_peek_bytes (bs, &strhdata, sizeof (gst_riff_strh));
291 strh = (gst_riff_strh *) strhdata;
293 if (got_bytes == sizeof (gst_riff_strh)) {
294 avi_stream_context *target;
296 avi_demux->fcc_type = GUINT32_FROM_LE (strh->type);
298 target = &avi_demux->stream[avi_demux->num_streams];
300 target->num = avi_demux->num_streams;
302 target->strh.type = avi_demux->fcc_type;
303 target->strh.fcc_handler = GUINT32_FROM_LE (strh->fcc_handler);
304 target->strh.flags = GUINT32_FROM_LE (strh->flags);
305 target->strh.priority = GUINT32_FROM_LE (strh->priority);
306 target->strh.init_frames = GUINT32_FROM_LE (strh->init_frames);
307 target->strh.scale = GUINT32_FROM_LE (strh->scale);
308 target->strh.rate = GUINT32_FROM_LE (strh->rate);
309 target->strh.start = GUINT32_FROM_LE (strh->start);
310 target->strh.length = GUINT32_FROM_LE (strh->length);
311 target->strh.bufsize = GUINT32_FROM_LE (strh->bufsize);
312 target->strh.quality = GUINT32_FROM_LE (strh->quality);
313 target->strh.samplesize = GUINT32_FROM_LE (strh->samplesize);
315 if (!target->strh.scale)
316 target->strh.scale = 1; /* avoid division by zero */
317 if (!target->strh.rate)
318 target->strh.rate = 1; /* avoid division by zero */
320 GST_INFO ( "gst_avi_demux: strh tag found");
321 GST_INFO ( "gst_avi_demux: type 0x%08x (%s)",
322 target->strh.type, gst_riff_id_to_fourcc (strh->type));
323 GST_INFO ( "gst_avi_demux: fcc_handler 0x%08x (%s)",
324 target->strh.fcc_handler, gst_riff_id_to_fourcc (strh->fcc_handler));
325 GST_INFO ( "gst_avi_demux: flags 0x%08x", strh->flags);
326 GST_INFO ( "gst_avi_demux: priority %d", target->strh.priority);
327 GST_INFO ( "gst_avi_demux: init_frames %d", target->strh.init_frames);
328 GST_INFO ( "gst_avi_demux: scale %d", target->strh.scale);
329 GST_INFO ( "gst_avi_demux: rate %d", target->strh.rate);
330 GST_INFO ( "gst_avi_demux: start %d", target->strh.start);
331 GST_INFO ( "gst_avi_demux: length %d", target->strh.length);
332 GST_INFO ( "gst_avi_demux: bufsize %d", target->strh.bufsize);
333 GST_INFO ( "gst_avi_demux: quality %d", target->strh.quality);
334 GST_INFO ( "gst_avi_demux: samplesize %d", target->strh.samplesize);
337 target->total_bytes = 0LL;
338 target->total_frames = 0;
339 target->end_pos = -1;
340 target->current_frame = 0;
341 target->current_byte = 0;
342 target->need_flush = FALSE;
345 avi_demux->avih.bufsize = MAX (avi_demux->avih.bufsize, target->strh.bufsize);
353 gst_avi_demux_dmlh (GstAviDemux *avi_demux)
357 GstByteStream *bs = avi_demux->bs;
360 got_bytes = gst_bytestream_peek_bytes (bs, &dmlhdata, sizeof (gst_riff_dmlh));
361 dmlh = (gst_riff_dmlh *) dmlhdata;
365 gst_avi_demux_strn (GstAviDemux *avi_demux, gint len)
369 GstByteStream *bs = avi_demux->bs;
372 got_bytes = gst_bytestream_peek_bytes (bs, &namedata, len);
373 name = (gchar *) namedata;
374 if (got_bytes != len)
377 GST_DEBUG ("Stream name: \"%s\"", name);
381 gst_avi_demux_metadata (GstAviDemux *avi_demux, gint len)
384 GstByteStream *bs = avi_demux->bs;
385 gst_riff_chunk *temp_chunk, chunk;
389 GstPropsEntry *entry;
391 props = gst_props_empty_new ();
394 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
395 temp_chunk = (gst_riff_chunk *) tempdata;
397 /* fixup for our big endian friends */
398 chunk.id = GUINT32_FROM_LE (temp_chunk->id);
399 chunk.size = GUINT32_FROM_LE (temp_chunk->size);
401 gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
402 if (got_bytes != sizeof (gst_riff_chunk))
404 len -= sizeof (gst_riff_chunk);
406 /* don't care about empty entries - move on */
410 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, chunk.size);
411 name = (gchar *) tempdata;
412 gst_bytestream_flush (bs, (chunk.size + 1) & ~1);
413 if (got_bytes != chunk.size)
415 len -= ((chunk.size + 1) & ~1);
417 /* we now have an info string in 'name' of type 'chunk.id' - find 'type' */
419 case GST_RIFF_INFO_IARL:
422 case GST_RIFF_INFO_IART:
425 case GST_RIFF_INFO_ICMS:
426 type = "Commissioner";
428 case GST_RIFF_INFO_ICMT:
431 case GST_RIFF_INFO_ICOP:
434 case GST_RIFF_INFO_ICRD:
435 type = "Creation Date";
437 case GST_RIFF_INFO_ICRP:
440 case GST_RIFF_INFO_IDIM:
443 case GST_RIFF_INFO_IDPI:
444 type = "Dots per Inch";
446 case GST_RIFF_INFO_IENG:
449 case GST_RIFF_INFO_IGNR:
452 case GST_RIFF_INFO_IKEY:
455 case GST_RIFF_INFO_ILGT:
458 case GST_RIFF_INFO_IMED:
461 case GST_RIFF_INFO_INAM:
462 type = "Title"; /* "Name" */
464 case GST_RIFF_INFO_IPLT:
467 case GST_RIFF_INFO_IPRD:
470 case GST_RIFF_INFO_ISBJ:
473 case GST_RIFF_INFO_ISFT:
474 type = "Encoder"; /* "Software" */
476 case GST_RIFF_INFO_ISHP:
479 case GST_RIFF_INFO_ISRC:
482 case GST_RIFF_INFO_ISRF:
483 type = "Source Form";
485 case GST_RIFF_INFO_ITCH:
494 /* create props entry */
495 entry = gst_props_entry_new (type, GST_PROPS_STRING (name));
496 gst_props_add_entry (props, entry);
500 gst_props_debug(props);
502 gst_caps_replace_sink (&avi_demux->metadata,
503 gst_caps_new("avi_metadata",
504 "application/x-gst-metadata",
507 g_object_notify(G_OBJECT(avi_demux), "metadata");
511 gst_avi_demux_streaminfo (GstAviDemux *avi_demux)
515 props = gst_props_empty_new ();
517 /* compression formats are added later - a bit hacky */
519 gst_caps_replace_sink (&avi_demux->streaminfo,
520 gst_caps_new("avi_streaminfo",
521 "application/x-gst-streaminfo",
524 /*g_object_notify(G_OBJECT(avi_demux), "streaminfo");*/
527 /* video/audio pad/caps stuff */
529 #ifdef G_HAVE_ISO_VARARGS
531 #define GST_AVI_VID_CAPS_NEW(name, mimetype, ...) \
533 GST_CAPS_NEW (name, \
535 "width", GST_PROPS_INT (width), \
536 "height", GST_PROPS_INT (height), \
537 "framerate", GST_PROPS_FLOAT (framerate), \
540 GST_CAPS_NEW (name, \
542 "width", GST_PROPS_INT_RANGE (16, 4096), \
543 "height", GST_PROPS_INT_RANGE (16, 4096), \
544 "framerate", GST_PROPS_FLOAT_RANGE (0., G_MAXFLOAT), \
547 #elif defined(G_HAVE_GNUC_VARARGS)
549 #define GST_AVI_VID_CAPS_NEW(name, mimetype, props...) \
551 GST_CAPS_NEW (name, \
553 "width", GST_PROPS_INT (width), \
554 "height", GST_PROPS_INT (height), \
555 "framerate", GST_PROPS_FLOAT (framerate), \
558 GST_CAPS_NEW (name, \
560 "width", GST_PROPS_INT_RANGE (16, 4096), \
561 "height", GST_PROPS_INT_RANGE (16, 4096), \
562 "framerate", GST_PROPS_FLOAT_RANGE (0., G_MAXFLOAT), \
567 gst_avi_demux_video_caps (guint32 codec_fcc,
569 gst_riff_strf_vids *strf,
570 GstAviDemux *avi_demux)
572 GstCaps *caps = NULL;
573 gchar *codecname = NULL;
574 gint width = -1, height = -1;
575 gdouble framerate = 0.;
578 width = GUINT32_FROM_LE (strf->width);
579 height = GUINT32_FROM_LE (strf->height);
582 framerate = 1. * GUINT32_FROM_LE (strh->rate) /
583 GUINT32_FROM_LE (strh->scale); /* fps */
587 case GST_MAKE_FOURCC('I','4','2','0'):
588 case GST_MAKE_FOURCC('Y','U','Y','2'):
589 caps = GST_AVI_VID_CAPS_NEW (
590 "avidemux_video_src_raw",
592 "format", GST_PROPS_FOURCC (codec_fcc)
594 codecname = g_strdup_printf("Raw Video (" GST_FOURCC_FORMAT ")",
595 GST_FOURCC_ARGS(codec_fcc));
598 case GST_MAKE_FOURCC('M','J','P','G'): /* YUY2 MJPEG */
599 case GST_MAKE_FOURCC('J','P','E','G'): /* generic (mostly RGB) MJPEG */
600 case GST_MAKE_FOURCC('P','I','X','L'): /* Miro/Pinnacle fourccs */
601 case GST_MAKE_FOURCC('V','I','X','L'): /* Miro/Pinnacle fourccs */
602 caps = GST_AVI_VID_CAPS_NEW (
603 "avidemux_video_src_jpeg",
607 codecname = g_strdup_printf("Motion-JPEG (" GST_FOURCC_FORMAT ")",
608 GST_FOURCC_ARGS(codec_fcc));
611 case GST_MAKE_FOURCC('H','F','Y','U'):
612 caps = GST_AVI_VID_CAPS_NEW (
613 "avidemux_video_src_hfyu",
617 codecname = g_strdup_printf("HuffYUV (" GST_FOURCC_FORMAT ")",
618 GST_FOURCC_ARGS(codec_fcc));
621 case GST_MAKE_FOURCC('M','P','E','G'):
622 case GST_MAKE_FOURCC('M','P','G','I'):
623 caps = GST_AVI_VID_CAPS_NEW (
624 "avidemux_video_src_mpeg",
626 "systemstream", GST_PROPS_BOOLEAN (FALSE),
627 "mpegversion", GST_PROPS_BOOLEAN (1)
629 codecname = g_strdup_printf("MPEG-1 (" GST_FOURCC_FORMAT ")",
630 GST_FOURCC_ARGS(codec_fcc));
633 case GST_MAKE_FOURCC('H','2','6','3'):
634 case GST_MAKE_FOURCC('i','2','6','3'):
635 case GST_MAKE_FOURCC('L','2','6','3'):
636 case GST_MAKE_FOURCC('M','2','6','3'):
637 case GST_MAKE_FOURCC('V','D','O','W'):
638 case GST_MAKE_FOURCC('V','I','V','O'):
639 case GST_MAKE_FOURCC('x','2','6','3'):
640 caps = GST_AVI_VID_CAPS_NEW (
641 "avidemux_video_src_263",
645 codecname = g_strdup_printf("H263-compatible (" GST_FOURCC_FORMAT ")",
646 GST_FOURCC_ARGS(codec_fcc));
649 case GST_MAKE_FOURCC('D','I','V','3'):
650 case GST_MAKE_FOURCC('D','I','V','4'):
651 case GST_MAKE_FOURCC('D','I','V','5'):
652 caps = GST_AVI_VID_CAPS_NEW (
653 "avidemux_video_src_divx3",
655 "divxversion", GST_PROPS_INT(3)
657 codecname = g_strdup_printf("DivX-3.x (" GST_FOURCC_FORMAT ")",
658 GST_FOURCC_ARGS(codec_fcc));
661 case GST_MAKE_FOURCC('d','i','v','x'):
662 case GST_MAKE_FOURCC('D','I','V','X'):
663 case GST_MAKE_FOURCC('D','X','5','0'):
664 caps = GST_AVI_VID_CAPS_NEW (
665 "avidemux_video_src_divx5",
667 "divxversion", GST_PROPS_INT(5)
669 codecname = g_strdup_printf("DivX 4.x/5.x (" GST_FOURCC_FORMAT ")",
670 GST_FOURCC_ARGS(codec_fcc));
673 case GST_MAKE_FOURCC('X','V','I','D'):
674 case GST_MAKE_FOURCC('x','v','i','d'):
675 caps = GST_AVI_VID_CAPS_NEW (
676 "avidemux_video_src",
680 codecname = g_strdup_printf("XviD (" GST_FOURCC_FORMAT ")",
681 GST_FOURCC_ARGS(codec_fcc));
684 case GST_MAKE_FOURCC('M','P','G','4'):
685 caps = GST_AVI_VID_CAPS_NEW (
686 "avidemux_video_src",
688 "msmpegversion", GST_PROPS_INT (41)
690 codecname = g_strdup_printf("MS MPEG-4.1 (" GST_FOURCC_FORMAT ")",
691 GST_FOURCC_ARGS(codec_fcc));
694 case GST_MAKE_FOURCC('M','P','4','2'):
695 caps = GST_AVI_VID_CAPS_NEW (
696 "avidemux_video_src",
698 "msmpegversion", GST_PROPS_INT (42)
700 codecname = g_strdup_printf("MS MPEG-4.2 (" GST_FOURCC_FORMAT ")",
701 GST_FOURCC_ARGS(codec_fcc));
704 case GST_MAKE_FOURCC('M','P','4','3'):
705 caps = GST_AVI_VID_CAPS_NEW (
706 "avidemux_video_src",
708 "msmpegversion", GST_PROPS_INT (43)
710 codecname = g_strdup_printf("MS MPEG-4.3 (" GST_FOURCC_FORMAT ")",
711 GST_FOURCC_ARGS(codec_fcc));
714 case GST_MAKE_FOURCC('3','I','V','1'):
715 case GST_MAKE_FOURCC('3','I','V','2'):
716 caps = GST_AVI_VID_CAPS_NEW (
717 "avidemux_video_src_3ivx",
721 codecname = g_strdup_printf("3ivX (" GST_FOURCC_FORMAT ")",
722 GST_FOURCC_ARGS(codec_fcc));
725 case GST_MAKE_FOURCC('D','V','S','D'):
726 case GST_MAKE_FOURCC('d','v','s','d'):
727 caps = GST_AVI_VID_CAPS_NEW (
728 "avidemux_video_src",
730 "systemstream", GST_PROPS_BOOLEAN (FALSE)
732 codecname = g_strdup_printf("Digital Video type 2 (" GST_FOURCC_FORMAT ")",
733 GST_FOURCC_ARGS(codec_fcc));
736 case GST_MAKE_FOURCC('W','M','V','1'):
737 caps = GST_AVI_VID_CAPS_NEW (
738 "avidemux_video_src_wmv1",
740 "wmvversion", GST_PROPS_INT (1)
742 codecname = g_strdup_printf("Windows Media Format 1 ("
743 GST_FOURCC_FORMAT ")",
744 GST_FOURCC_ARGS(codec_fcc));
747 case GST_MAKE_FOURCC('W','M','V','2'):
748 caps = GST_AVI_VID_CAPS_NEW (
749 "avidemux_video_src_wmv2",
751 "wmvversion", GST_PROPS_INT (2)
753 codecname = g_strdup_printf("Windows Media Format 2 ("
754 GST_FOURCC_FORMAT ")",
755 GST_FOURCC_ARGS(codec_fcc));
759 g_warning ("avidemux: unkown video format " GST_FOURCC_FORMAT,
760 GST_FOURCC_ARGS(codec_fcc));
764 /* set video codec info on streaminfo caps */
765 if (avi_demux != NULL && codecname != NULL) {
766 GstPropsEntry *entry;
767 entry = gst_props_entry_new("videocodec",
768 GST_PROPS_STRING(codecname));
769 gst_props_add_entry(avi_demux->streaminfo->properties, entry);
771 if (codecname != NULL) {
779 gst_avi_demux_strf_vids (GstAviDemux *avi_demux)
781 gst_riff_strf_vids *strf;
785 GstCaps *caps = NULL;
786 avi_stream_context *stream;
787 GstByteStream *bs = avi_demux->bs;
791 got_bytes = gst_bytestream_peek_bytes (bs, &strfdata, sizeof (gst_riff_strf_vids));
792 strf = (gst_riff_strf_vids *) strfdata;
793 if (got_bytes != sizeof (gst_riff_strf_vids))
796 padname = g_strdup_printf ("video_%02d", avi_demux->num_v_streams);
797 srcpad = gst_pad_new_from_template (videosrctempl, padname);
800 /* let's try some gstreamer-like mime-type caps */
801 strh = &avi_demux->stream[avi_demux->num_streams].strh;
802 caps = gst_avi_demux_video_caps (GUINT32_FROM_LE(strf->compression),
803 strh, strf, avi_demux);
806 gst_pad_try_set_caps (srcpad, caps);
808 gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
809 gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
810 gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
811 gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
812 gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
813 gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
815 stream = &avi_demux->stream[avi_demux->num_streams];
816 stream->pad = srcpad;
817 gst_pad_set_element_private (srcpad, stream);
818 avi_demux->num_streams++;
819 avi_demux->num_v_streams++;
821 gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
824 #ifdef G_HAVE_ISO_VARARGS
826 #define GST_AVI_AUD_CAPS_NEW(name, mimetype, ...) \
828 GST_CAPS_NEW (name, \
830 "rate", GST_PROPS_INT (rate), \
831 "channels", GST_PROPS_INT (channels), \
834 GST_CAPS_NEW (name, \
836 "rate", GST_PROPS_INT_RANGE (8000, 96000), \
837 "channels", GST_PROPS_INT_RANGE (1, 2), \
841 #elif defined(G_HAVE_GNUC_VARARGS)
843 #define GST_AVI_AUD_CAPS_NEW(name, mimetype, props...) \
845 GST_CAPS_NEW (name, \
847 "rate", GST_PROPS_INT (rate), \
848 "channels", GST_PROPS_INT (channels), \
851 GST_CAPS_NEW (name, \
853 "rate", GST_PROPS_INT_RANGE (8000, 96000), \
854 "channels", GST_PROPS_INT_RANGE (1, 2), \
859 gst_avi_demux_audio_caps (guint16 codec_id,
860 gst_riff_strf_auds *strf,
861 GstAviDemux *avi_demux)
863 GstCaps *caps = NULL;
864 gchar *codecname = NULL;
865 gint rate = -1, channels = -1;
868 rate = GUINT32_FROM_LE (strf->rate);
869 channels = GUINT16_FROM_LE (strf->channels);
873 case GST_RIFF_WAVE_FORMAT_MPEGL3: /* mp3 */
874 caps = GST_AVI_AUD_CAPS_NEW ("avi_demux_audio_src_mp3",
876 "layer", GST_PROPS_INT (3));
877 codecname = g_strdup_printf("MPEG-1 layer 3 audio (0x%04x)",
881 case GST_RIFF_WAVE_FORMAT_MPEGL12: /* mp1 or mp2 */
882 caps = GST_AVI_AUD_CAPS_NEW ("avi_demux_audio_src_mp12",
884 "layer", GST_PROPS_INT (2));
885 codecname = g_strdup_printf("MPEG-1 layer 1/2 audio (0x%04x)",
889 case GST_RIFF_WAVE_FORMAT_PCM: /* PCM/wav */ {
890 GstPropsEntry *width = NULL, *depth = NULL, *signedness = NULL;
893 gint ba = GUINT16_FROM_LE (strf->blockalign);
894 gint ch = GUINT16_FROM_LE (strf->channels);
895 gint ws = GUINT16_FROM_LE (strf->size);
897 width = gst_props_entry_new ("width",
898 GST_PROPS_INT (ba * 8 / ch));
899 depth = gst_props_entry_new ("depth",
901 signedness = gst_props_entry_new ("signed",
902 GST_PROPS_BOOLEAN (ws != 8));
904 signedness = gst_props_entry_new ("signed",
906 GST_PROPS_BOOLEAN (TRUE),
907 GST_PROPS_BOOLEAN (FALSE)));
908 width = gst_props_entry_new ("width",
911 GST_PROPS_INT (16)));
912 depth = gst_props_entry_new ("depth",
915 GST_PROPS_INT (16)));
918 caps = GST_AVI_AUD_CAPS_NEW ("avi_demux_audio_src_pcm",
921 GST_PROPS_INT (G_LITTLE_ENDIAN));
922 gst_props_add_entry (caps->properties, width);
923 gst_props_add_entry (caps->properties, depth);
924 gst_props_add_entry (caps->properties, signedness);
926 codecname = g_strdup_printf("Raw PCM/WAV (0x%04x)",
931 case GST_RIFF_WAVE_FORMAT_MULAW:
932 if (strf != NULL && strf->size != 8) {
933 g_warning ("invalid depth (%d) of mulaw audio, overwriting.",
936 caps = GST_AVI_AUD_CAPS_NEW ("avidemux_audio_src",
939 codecname = g_strdup_printf("A-law encoded (0x%04x)",
943 case GST_RIFF_WAVE_FORMAT_ALAW:
944 if (strf != NULL && strf->size != 8) {
945 g_warning ("invalid depth (%d) of alaw audio, overwriting.",
948 caps = GST_AVI_AUD_CAPS_NEW ("avidemux_audio_src",
951 codecname = g_strdup_printf("A-law encoded (0x%04x)",
955 case GST_RIFF_WAVE_FORMAT_VORBIS1: /* ogg/vorbis mode 1 */
956 case GST_RIFF_WAVE_FORMAT_VORBIS2: /* ogg/vorbis mode 2 */
957 case GST_RIFF_WAVE_FORMAT_VORBIS3: /* ogg/vorbis mode 3 */
958 case GST_RIFF_WAVE_FORMAT_VORBIS1PLUS: /* ogg/vorbis mode 1+ */
959 case GST_RIFF_WAVE_FORMAT_VORBIS2PLUS: /* ogg/vorbis mode 2+ */
960 case GST_RIFF_WAVE_FORMAT_VORBIS3PLUS: /* ogg/vorbis mode 3+ */
961 caps = GST_AVI_AUD_CAPS_NEW ("asf_demux_audio_src_vorbis",
964 codecname = g_strdup_printf("Vorbis (0x%04x)",
968 case GST_RIFF_WAVE_FORMAT_A52:
969 caps = GST_AVI_AUD_CAPS_NEW ("asf_demux_audio_src_ac3",
972 codecname = g_strdup_printf("AC-3 (0x%04x)",
977 g_warning ("avidemux: unkown audio format 0x%04x",
982 if (avi_demux != NULL && codecname != NULL) {
983 /* set audio codec in streaminfo */
984 GstPropsEntry *entry;
985 entry = gst_props_entry_new("audiocodec",
986 GST_PROPS_STRING(codecname));
987 gst_props_add_entry(avi_demux->streaminfo->properties, entry);
989 if (codecname != NULL) {
997 gst_avi_demux_strf_auds (GstAviDemux *avi_demux)
999 gst_riff_strf_auds *strf;
1002 GstCaps *caps = NULL;
1003 avi_stream_context *stream;
1004 GstByteStream *bs = avi_demux->bs;
1008 got_bytes = gst_bytestream_peek_bytes (bs, &strfdata, sizeof (gst_riff_strf_auds));
1009 strf = (gst_riff_strf_auds *) strfdata;
1010 if (got_bytes != sizeof (gst_riff_strf_auds))
1013 GST_INFO ( "gst_avi_demux: strf tag found in context auds");
1014 GST_INFO ( "gst_avi_demux: format %d", GUINT16_FROM_LE (strf->format));
1015 GST_INFO ( "gst_avi_demux: channels %d", GUINT16_FROM_LE (strf->channels));
1016 GST_INFO ( "gst_avi_demux: rate %d", GUINT32_FROM_LE (strf->rate));
1017 GST_INFO ( "gst_avi_demux: av_bps %d", GUINT32_FROM_LE (strf->av_bps));
1018 GST_INFO ( "gst_avi_demux: blockalign %d", GUINT16_FROM_LE (strf->blockalign));
1019 GST_INFO ( "gst_avi_demux: size %d", GUINT16_FROM_LE (strf->size));
1021 padname = g_strdup_printf ("audio_%02d",
1022 avi_demux->num_a_streams);
1023 srcpad = gst_pad_new_from_template (audiosrctempl, padname);
1026 caps = gst_avi_demux_audio_caps (GUINT16_FROM_LE (strf->format),
1030 gst_pad_try_set_caps(srcpad, caps);
1032 gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
1033 gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
1034 gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
1035 gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
1036 gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
1037 gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
1039 stream = &avi_demux->stream[avi_demux->num_streams];
1040 stream->pad = srcpad;
1041 gst_pad_set_element_private (srcpad, stream);
1042 avi_demux->num_streams++;
1043 avi_demux->num_a_streams++;
1045 gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
1049 gst_avi_demux_iavs_caps (void)
1051 return GST_CAPS_NEW ("avi_type_dv",
1053 "systemstream", GST_PROPS_BOOLEAN (TRUE));
1057 gst_avi_demux_strf_iavs (GstAviDemux *avi_demux)
1059 gst_riff_strf_iavs *strf;
1062 GstCaps *caps = NULL;
1063 avi_stream_context *stream;
1064 GstByteStream *bs = avi_demux->bs;
1067 GstPropsEntry *entry;
1069 got_bytes = gst_bytestream_peek_bytes (bs, &strfdata, sizeof (gst_riff_strf_iavs));
1070 strf = (gst_riff_strf_iavs *) strfdata;
1071 if (got_bytes != sizeof (gst_riff_strf_iavs))
1074 GST_INFO ( "gst_avi_demux: strf tag found in context iavs");
1075 GST_INFO ( "gst_avi_demux: DVAAuxSrc %08x", GUINT32_FROM_LE (strf->DVAAuxSrc));
1076 GST_INFO ( "gst_avi_demux: DVAAuxCtl %08x", GUINT32_FROM_LE (strf->DVAAuxCtl));
1077 GST_INFO ( "gst_avi_demux: DVAAuxSrc1 %08x", GUINT32_FROM_LE (strf->DVAAuxSrc1));
1078 GST_INFO ( "gst_avi_demux: DVAAuxCtl1 %08x", GUINT32_FROM_LE (strf->DVAAuxCtl1));
1079 GST_INFO ( "gst_avi_demux: DVVAuxSrc %08x", GUINT32_FROM_LE (strf->DVVAuxSrc));
1080 GST_INFO ( "gst_avi_demux: DVVAuxCtl %08x", GUINT32_FROM_LE (strf->DVVAuxCtl));
1081 GST_INFO ( "gst_avi_demux: DVReserved1 %08x", GUINT32_FROM_LE (strf->DVReserved1));
1082 GST_INFO ( "gst_avi_demux: DVReserved2 %08x", GUINT32_FROM_LE (strf->DVReserved2));
1084 padname = g_strdup_printf ("video_%02d",
1085 avi_demux->num_v_streams);
1086 srcpad = gst_pad_new_from_template (videosrctempl, padname);
1089 caps = gst_avi_demux_iavs_caps ();
1090 entry = gst_props_entry_new("videocodec",
1091 GST_PROPS_STRING("Digital Video type 1"));
1092 gst_props_add_entry(avi_demux->streaminfo->properties, entry);
1095 gst_pad_try_set_caps(srcpad, caps);
1097 gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
1098 gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
1099 gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
1100 gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
1101 gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
1102 gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
1104 stream = &avi_demux->stream[avi_demux->num_streams];
1105 stream->pad = srcpad;
1106 gst_pad_set_element_private (srcpad, stream);
1107 avi_demux->num_streams++;
1108 avi_demux->num_v_streams++;
1110 gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
1114 gst_avi_debug_entry (const gchar *prefix, gst_avi_index_entry *entry)
1116 GST_DEBUG ("%s: %05d %d %08llx %05d %14" G_GINT64_FORMAT " %08x %08x (%d) %08x",
1117 prefix, entry->index_nr, entry->stream_nr,
1118 (unsigned long long)entry->bytes_before,
1119 entry->frames_before, entry->ts, entry->flags, entry->offset,
1120 entry->offset, entry->size);
1124 gst_avi_demux_parse_index (GstAviDemux *avi_demux,
1125 gulong filepos, gulong offset)
1131 gst_riff_index_entry *entry;
1134 if (!gst_bytestream_seek (avi_demux->bs, filepos + offset, GST_SEEK_METHOD_SET)) {
1135 GST_INFO ( "avidemux: could not seek to index");
1142 got_bytes = gst_bytestream_read (avi_demux->bs, &buf, 8);
1146 gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
1147 gst_event_unref (event);
1150 if (GST_BUFFER_OFFSET (buf) != filepos + offset || GST_BUFFER_SIZE (buf) != 8) {
1151 GST_INFO ( "avidemux: could not get index, got %" G_GINT64_FORMAT " %d, expected %ld",
1152 GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf), filepos + offset);
1156 id = GUINT32_FROM_LE (*(guint32 *)GST_BUFFER_DATA (buf));
1158 if (id != GST_RIFF_TAG_idx1) {
1159 GST_INFO ( "avidemux: no index found");
1163 index_size = GUINT32_FROM_LE(*(guint32 *)(GST_BUFFER_DATA (buf) + 4));
1164 gst_buffer_unref (buf);
1166 gst_bytestream_size_hint (avi_demux->bs, index_size);
1168 got_bytes = gst_bytestream_read (avi_demux->bs, &buf, index_size);
1169 if (got_bytes < index_size) {
1170 GST_INFO ( "avidemux: error reading index");
1174 avi_demux->index_size = index_size/sizeof(gst_riff_index_entry);
1175 GST_INFO ( "avidemux: index size %lu", avi_demux->index_size);
1177 avi_demux->index_entries = g_malloc (avi_demux->index_size * sizeof (gst_avi_index_entry));
1179 entry = (gst_riff_index_entry *) GST_BUFFER_DATA (buf);
1181 for (i = 0; i < avi_demux->index_size; i++) {
1182 avi_stream_context *stream;
1184 gst_avi_index_entry *target = &avi_demux->index_entries[i];
1188 id = GUINT32_FROM_LE (entry[i].id);
1189 stream_nr = CHUNKID_TO_STREAMNR (id);
1190 if (stream_nr > avi_demux->num_streams || stream_nr < 0) {
1191 avi_demux->index_entries[i].stream_nr = -1;
1195 target->stream_nr = stream_nr;
1196 stream = &avi_demux->stream[stream_nr];
1198 target->index_nr = i;
1199 target->flags = GUINT32_FROM_LE (entry[i].flags);
1200 target->size = GUINT32_FROM_LE (entry[i].size);
1201 target->offset = GUINT32_FROM_LE (entry[i].offset);
1203 /* figure out if the index is 0 based or relative to the MOVI start */
1205 if (target->offset < filepos)
1206 avi_demux->index_offset = filepos - 4;
1208 avi_demux->index_offset = 0;
1211 target->bytes_before = stream->total_bytes;
1212 target->frames_before = stream->total_frames;
1214 format = GST_FORMAT_TIME;
1215 if (stream->strh.type == GST_RIFF_FCC_auds) {
1216 /* all audio frames are keyframes */
1217 target->flags |= GST_RIFF_IF_KEYFRAME;
1220 /* constant rate stream */
1221 if (stream->strh.samplesize && stream->strh.type == GST_RIFF_FCC_auds) {
1222 gst_pad_convert (stream->pad, GST_FORMAT_BYTES, stream->total_bytes,
1223 &format, &target->ts);
1227 gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT, stream->total_frames,
1228 &format, &target->ts);
1230 gst_avi_debug_entry ("index", target);
1232 stream->total_bytes += target->size;
1233 stream->total_frames++;
1235 for (i = 0; i < avi_demux->num_streams; i++) {
1236 avi_stream_context *stream;
1238 stream = &avi_demux->stream[i];
1239 GST_DEBUG ("stream %i: %d frames, %" G_GINT64_FORMAT " bytes",
1240 i, stream->total_frames, stream->total_bytes);
1242 gst_buffer_unref (buf);
1245 GST_DEBUG ("index offset at %08lx", filepos);
1247 if (!gst_bytestream_seek (avi_demux->bs, filepos, GST_SEEK_METHOD_SET)) {
1248 GST_INFO ( "avidemux: could not seek back to movi");
1253 static gst_avi_index_entry*
1254 gst_avi_demux_index_next (GstAviDemux *avi_demux, gint stream_nr, gint start, guint32 flags)
1257 gst_avi_index_entry *entry = NULL;
1259 for (i = start; i < avi_demux->index_size; i++) {
1260 entry = &avi_demux->index_entries[i];
1262 if (entry->stream_nr == stream_nr && (entry->flags & flags) == flags) {
1270 static gst_avi_index_entry*
1271 gst_avi_demux_index_entry_for_time (GstAviDemux *avi_demux, gint stream_nr, guint64 time, guint32 flags)
1273 gst_avi_index_entry *entry = NULL, *last_entry = NULL;
1278 entry = gst_avi_demux_index_next (avi_demux, stream_nr, i + 1, flags);
1282 i = entry->index_nr;
1284 if (entry->ts <= time) {
1288 while (entry->ts <= time);
1293 static const GstFormat*
1294 gst_avi_demux_get_src_formats (GstPad *pad)
1296 avi_stream_context *stream = gst_pad_get_element_private (pad);
1298 static const GstFormat src_a_formats[] = {
1304 static const GstFormat src_v_formats[] = {
1310 return (stream->strh.type == GST_RIFF_FCC_auds ? src_a_formats : src_v_formats);
1314 gst_avi_demux_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
1315 GstFormat *dest_format, gint64 *dest_value)
1317 gboolean res = TRUE;
1318 avi_stream_context *stream = gst_pad_get_element_private (pad);
1320 if (stream->strh.type != GST_RIFF_FCC_auds &&
1321 (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
1324 switch (src_format) {
1325 case GST_FORMAT_TIME:
1326 switch (*dest_format) {
1327 case GST_FORMAT_BYTES:
1328 *dest_value = src_value * stream->strh.rate / (stream->strh.scale * GST_SECOND);
1330 case GST_FORMAT_DEFAULT:
1331 *dest_value = src_value * stream->strh.rate / (stream->strh.scale * GST_SECOND);
1338 case GST_FORMAT_BYTES:
1339 switch (*dest_format) {
1340 case GST_FORMAT_TIME:
1341 *dest_value = ((gfloat)src_value) * GST_SECOND / stream->strh.rate;
1348 case GST_FORMAT_DEFAULT:
1349 switch (*dest_format) {
1350 case GST_FORMAT_TIME:
1351 *dest_value = ((((gfloat)src_value) * stream->strh.scale) / stream->strh.rate) * GST_SECOND;
1365 static const GstQueryType*
1366 gst_avi_demux_get_src_query_types (GstPad *pad)
1368 static const GstQueryType src_types[] = {
1378 gst_avi_demux_handle_src_query (GstPad *pad, GstQueryType type,
1379 GstFormat *format, gint64 *value)
1381 gboolean res = TRUE;
1382 //GstAviDemux *avi_demux = GST_AVI_DEMUX (gst_pad_get_parent (pad));
1383 avi_stream_context *stream = gst_pad_get_element_private (pad);
1386 case GST_QUERY_TOTAL:
1388 case GST_FORMAT_TIME:
1389 *value = (((gfloat)stream->strh.scale) * stream->strh.length / stream->strh.rate) * GST_SECOND;
1391 case GST_FORMAT_BYTES:
1392 if (stream->strh.type == GST_RIFF_FCC_auds) {
1393 *value = stream->total_bytes;
1398 case GST_FORMAT_DEFAULT:
1399 if (stream->strh.type == GST_RIFF_FCC_auds)
1400 *value = stream->strh.length * stream->strh.samplesize;
1401 else if (stream->strh.type == GST_RIFF_FCC_vids)
1402 *value = stream->strh.length;
1411 case GST_QUERY_POSITION:
1413 case GST_FORMAT_TIME:
1414 if (stream->strh.samplesize && stream->strh.type == GST_RIFF_FCC_auds) {
1415 //*value = (((gfloat)stream->current_byte) * stream->strh.scale / stream->strh.rate) * GST_SECOND;
1416 *value = ((gfloat)stream->current_byte) * GST_SECOND / stream->strh.rate;
1419 *value = (((gfloat)stream->current_frame) * stream->strh.scale / stream->strh.rate) * GST_SECOND;
1422 case GST_FORMAT_BYTES:
1423 *value = stream->current_byte;
1425 case GST_FORMAT_DEFAULT:
1426 if (stream->strh.samplesize && stream->strh.type == GST_RIFF_FCC_auds)
1427 *value = stream->current_byte * stream->strh.samplesize;
1429 *value = stream->current_frame;
1445 gst_avi_demux_sync_streams (GstAviDemux *avi_demux, guint64 time)
1448 guint32 min_index = G_MAXUINT;
1449 avi_stream_context *stream;
1450 gst_avi_index_entry *entry;
1452 for (i = 0; i < avi_demux->num_streams; i++) {
1453 stream = &avi_demux->stream[i];
1455 GST_DEBUG ("finding %d for time %" G_GINT64_FORMAT, i, time);
1457 entry = gst_avi_demux_index_entry_for_time (avi_demux, stream->num, time, GST_RIFF_IF_KEYFRAME);
1459 gst_avi_debug_entry ("sync entry", entry);
1461 min_index = MIN (entry->index_nr, min_index);
1464 GST_DEBUG ("first index at %d", min_index);
1466 /* now we know the entry we need to sync on. calculate number of frames to
1467 * skip fro there on and the stream stats */
1468 for (i = 0; i < avi_demux->num_streams; i++) {
1469 gst_avi_index_entry *next_entry;
1470 stream = &avi_demux->stream[i];
1473 next_entry = gst_avi_demux_index_next (avi_demux, stream->num, min_index, 0);
1474 /* next entry with keyframe */
1475 entry = gst_avi_demux_index_next (avi_demux, stream->num, min_index, GST_RIFF_IF_KEYFRAME);
1476 gst_avi_debug_entry ("final sync", entry);
1478 stream->current_byte = next_entry->bytes_before;
1479 stream->current_frame = next_entry->frames_before;
1480 stream->skip = entry->frames_before - next_entry->frames_before;
1482 GST_DEBUG ("%d skip %d", stream->num, stream->skip);
1484 GST_DEBUG ("final index at %d", min_index);
1490 gst_avi_demux_send_event (GstElement *element, GstEvent *event)
1494 pads = gst_element_get_pad_list (element);
1497 GstPad *pad = GST_PAD (pads->data);
1499 if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
1500 /* we ref the event here as we might have to try again if the event
1501 * failed on this pad */
1502 gst_event_ref (event);
1503 if (gst_avi_demux_handle_src_event (pad, event)) {
1504 gst_event_unref (event);
1509 pads = g_list_next (pads);
1512 gst_event_unref (event);
1516 static const GstEventMask*
1517 gst_avi_demux_get_event_mask (GstPad *pad)
1519 static const GstEventMask masks[] = {
1520 { GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
1521 { GST_EVENT_SEEK_SEGMENT, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
1529 gst_avi_demux_handle_src_event (GstPad *pad, GstEvent *event)
1531 gboolean res = TRUE;
1532 GstAviDemux *avi_demux = GST_AVI_DEMUX (gst_pad_get_parent (pad));
1533 avi_stream_context *stream;
1535 stream = gst_pad_get_element_private (pad);
1537 switch (GST_EVENT_TYPE (event)) {
1538 case GST_EVENT_SEEK_SEGMENT:
1539 stream->end_pos = GST_EVENT_SEEK_ENDOFFSET (event);
1540 case GST_EVENT_SEEK:
1541 GST_DEBUG ("seek format %d, %08x", GST_EVENT_SEEK_FORMAT (event), stream->strh.type);
1542 switch (GST_EVENT_SEEK_FORMAT (event)) {
1543 case GST_FORMAT_BYTES:
1544 case GST_FORMAT_DEFAULT:
1546 case GST_FORMAT_TIME:
1548 gst_avi_index_entry *seek_entry, *entry;
1549 gint64 desired_offset = GST_EVENT_SEEK_OFFSET (event);
1554 /* no seek on audio yet */
1555 if (stream->strh.type == GST_RIFF_FCC_auds) {
1559 GST_DEBUG ("seeking to %" G_GINT64_FORMAT, desired_offset);
1561 flags = GST_RIFF_IF_KEYFRAME;
1563 entry = gst_avi_demux_index_entry_for_time (avi_demux, stream->num, desired_offset, GST_RIFF_IF_KEYFRAME);
1565 desired_offset = entry->ts;
1566 min_index = gst_avi_demux_sync_streams (avi_demux, desired_offset);
1567 seek_entry = &avi_demux->index_entries[min_index];
1569 gst_avi_debug_entry ("syncing to entry", seek_entry);
1571 avi_demux->seek_offset = seek_entry->offset + avi_demux->index_offset;
1572 avi_demux->seek_pending = TRUE;
1573 avi_demux->last_seek = seek_entry->ts;
1576 GST_DEBUG ("no index entry found for time %" G_GINT64_FORMAT, desired_offset);
1592 gst_event_unref (event);
1598 gst_avi_demux_handle_sink_event (GstAviDemux *avi_demux)
1603 gboolean res = TRUE;
1605 gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
1607 type = event? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
1608 GST_DEBUG ("avidemux: event %p %d", event, type);
1612 gst_bytestream_flush (avi_demux->bs, remaining);
1613 gst_pad_event_default (avi_demux->sinkpad, event);
1616 case GST_EVENT_FLUSH:
1617 g_warning ("flush event");
1619 case GST_EVENT_DISCONTINUOUS:
1624 for (i = 0; i < avi_demux->num_streams; i++) {
1625 avi_stream_context *stream = &avi_demux->stream[i];
1627 if (GST_PAD_IS_USABLE (stream->pad)) {
1628 GST_DEBUG ("sending discont on %d %" G_GINT64_FORMAT " + %" G_GINT64_FORMAT " = %" G_GINT64_FORMAT,
1629 i, avi_demux->last_seek, stream->delay, avi_demux->last_seek + stream->delay);
1631 discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
1632 avi_demux->last_seek + stream->delay , NULL);
1634 gst_pad_push (stream->pad, GST_DATA (discont));
1640 g_warning ("unhandled event %d", type);
1644 gst_event_unref (event);
1653 gst_avi_demux_loop (GstElement *element)
1655 GstAviDemux *avi_demux;
1656 gst_riff_riff chunk;
1662 avi_demux = GST_AVI_DEMUX (element);
1666 if (avi_demux->seek_pending) {
1667 GST_DEBUG ("avidemux: seek pending to %" G_GINT64_FORMAT " %08llx",
1668 avi_demux->seek_offset, (unsigned long long)avi_demux->seek_offset);
1670 if (!gst_bytestream_seek (avi_demux->bs,
1671 avi_demux->seek_offset,
1672 GST_SEEK_METHOD_SET))
1674 GST_INFO ( "avidemux: could not seek");
1676 avi_demux->seek_pending = FALSE;
1679 pos = gst_bytestream_tell (bs);
1681 gst_riff_riff *temp_chunk;
1685 /* read first two dwords to get chunktype and size */
1687 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
1688 temp_chunk = (gst_riff_riff *) tempdata;
1689 if (got_bytes < sizeof (gst_riff_chunk)) {
1690 if (!gst_avi_demux_handle_sink_event (avi_demux))
1696 chunk.id = GUINT32_FROM_LE (temp_chunk->id);
1697 chunk.size = GUINT32_FROM_LE (temp_chunk->size);
1700 case GST_RIFF_TAG_RIFF:
1701 case GST_RIFF_TAG_LIST:
1702 /* read complete list chunk */
1704 got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_list));
1705 temp_chunk = (gst_riff_riff *) tempdata;
1706 if (got_bytes < sizeof (gst_riff_list)) {
1707 if (!gst_avi_demux_handle_sink_event (avi_demux))
1712 chunk.type = GUINT32_FROM_LE (temp_chunk->type);
1713 skipsize = sizeof (gst_riff_list);
1716 skipsize = sizeof (gst_riff_chunk);
1719 gst_bytestream_flush_fast (bs, skipsize);
1723 /* need to flush an even number of bytes at the end */
1724 flush = (chunk.size + 1) & ~1;
1726 switch (avi_demux->state) {
1727 case GST_AVI_DEMUX_START:
1728 if (chunk.id != GST_RIFF_TAG_RIFF &&
1729 chunk.type != GST_RIFF_RIFF_AVI) {
1730 gst_element_error (element, "This doesn't appear to be an AVI file %08x %08x", chunk.id, chunk.type);
1733 avi_demux->state = GST_AVI_DEMUX_HEADER;
1734 /* we are not going to flush lists */
1737 case GST_AVI_DEMUX_HEADER:
1738 GST_DEBUG ("riff tag: %4.4s %08x", (gchar *)&chunk.id, chunk.size);
1740 case GST_RIFF_TAG_LIST:
1741 GST_DEBUG ("list type: %4.4s", (gchar *)&chunk.type);
1742 switch (chunk.type) {
1743 case GST_RIFF_LIST_movi:
1747 filepos = gst_bytestream_tell (bs);
1749 gst_avi_demux_parse_index (avi_demux, filepos , chunk.size - 4);
1751 if (avi_demux->avih.bufsize) {
1752 gst_bytestream_size_hint (avi_demux->bs, avi_demux->avih.bufsize);
1755 avi_demux->state = GST_AVI_DEMUX_MOVI;
1756 /* and tell the bastards that we have stream info too */
1757 gst_props_debug(avi_demux->streaminfo->properties);
1758 g_object_notify(G_OBJECT(avi_demux), "streaminfo");
1761 case GST_RIFF_LIST_INFO:
1762 gst_avi_demux_metadata (avi_demux, chunk.size);
1769 case GST_RIFF_TAG_avih:
1770 gst_avi_demux_avih (avi_demux);
1772 case GST_RIFF_TAG_strh:
1773 gst_avi_demux_strh (avi_demux);
1775 case GST_RIFF_TAG_strf:
1776 switch (avi_demux->fcc_type) {
1777 case GST_RIFF_FCC_vids:
1778 gst_avi_demux_strf_vids (avi_demux);
1780 case GST_RIFF_FCC_auds:
1781 gst_avi_demux_strf_auds (avi_demux);
1783 case GST_RIFF_FCC_iavs:
1784 gst_avi_demux_strf_iavs (avi_demux);
1786 case GST_RIFF_FCC_pads:
1787 case GST_RIFF_FCC_txts:
1789 GST_INFO ( "gst_avi_demux_chain: strh type %s not supported",
1790 gst_riff_id_to_fourcc (avi_demux->fcc_type));
1794 case GST_RIFF_TAG_strn:
1795 gst_avi_demux_strn (avi_demux, chunk.size);
1797 case GST_RIFF_TAG_dmlh:
1798 gst_avi_demux_dmlh (avi_demux);
1800 case GST_RIFF_TAG_JUNK:
1804 GST_DEBUG (" ***** unknown chunkid %08x", chunk.id);
1808 case GST_AVI_DEMUX_MOVI:
1816 avi_stream_context *stream;
1820 stream_id = CHUNKID_TO_STREAMNR (chunk.id);
1822 stream = &avi_demux->stream[stream_id];
1824 GST_LOG_OBJECT (avi_demux, "gst_avi_demux_chain: tag found %08x size %08x stream_id %d",
1825 chunk.id, chunk.size, stream_id);
1827 format = GST_FORMAT_TIME;
1828 gst_pad_query (stream->pad, GST_QUERY_POSITION, &format, &next_ts);
1830 if (stream->strh.init_frames == stream->current_frame && stream->delay == 0)
1831 stream->delay = next_ts;
1833 stream->current_frame++;
1834 stream->current_byte += chunk.size;
1840 if (GST_PAD_IS_USABLE (stream->pad)) {
1841 if (next_ts >= stream->end_pos) {
1842 gst_pad_push (stream->pad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
1843 GST_DEBUG ("end stream %d: %" G_GINT64_FORMAT " %d %" G_GINT64_FORMAT,
1844 stream_id, next_ts, stream->current_frame - 1,
1852 GstClockTime dur_ts;
1853 got_bytes = gst_bytestream_peek (avi_demux->bs, &buf, chunk.size);
1855 GST_BUFFER_TIMESTAMP (buf) = next_ts;
1857 gst_pad_query (stream->pad, GST_QUERY_POSITION, &format, &dur_ts);
1858 GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
1860 if (stream->need_flush) {
1861 /* FIXME, do some flush event here */
1862 stream->need_flush = FALSE;
1864 GST_LOG_OBJECT (avi_demux, "send stream %d: %"
1865 G_GINT64_FORMAT " %d %" G_GINT64_FORMAT " %08x",
1866 stream_id, next_ts, stream->current_frame - 1,
1867 stream->delay, chunk.size);
1869 gst_pad_push(stream->pad, GST_DATA (buf));
1877 GST_DEBUG (" ***** unknown chunkid %08x", chunk.id);
1886 res = gst_bytestream_flush (avi_demux->bs, flush);
1891 gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
1892 gst_event_unref (event);
1899 static GstElementStateReturn
1900 gst_avi_demux_change_state (GstElement *element)
1902 GstAviDemux *avi_demux = GST_AVI_DEMUX (element);
1904 switch (GST_STATE_TRANSITION (element)) {
1905 case GST_STATE_NULL_TO_READY:
1907 case GST_STATE_READY_TO_PAUSED:
1908 avi_demux->bs = gst_bytestream_new (avi_demux->sinkpad);
1909 avi_demux->last_seek = 0;
1910 avi_demux->state = GST_AVI_DEMUX_START;
1911 avi_demux->num_streams = 0;
1912 avi_demux->num_v_streams = 0;
1913 avi_demux->num_a_streams = 0;
1914 avi_demux->index_entries = NULL;
1915 avi_demux->index_size = 0;
1916 avi_demux->seek_pending = 0;
1917 avi_demux->metadata = NULL;
1918 gst_avi_demux_streaminfo(avi_demux);
1920 case GST_STATE_PAUSED_TO_PLAYING:
1922 case GST_STATE_PLAYING_TO_PAUSED:
1924 case GST_STATE_PAUSED_TO_READY:
1925 gst_bytestream_destroy (avi_demux->bs);
1926 gst_caps_replace (&avi_demux->metadata, NULL);
1927 gst_caps_replace (&avi_demux->streaminfo, NULL);
1929 case GST_STATE_READY_TO_NULL:
1935 parent_class->change_state (element);
1937 return GST_STATE_SUCCESS;
1941 gst_avi_demux_get_property (GObject *object, guint prop_id, GValue *value,
1946 g_return_if_fail (GST_IS_AVI_DEMUX (object));
1948 src = GST_AVI_DEMUX (object);
1954 g_value_set_boxed(value, src->metadata);
1956 case ARG_STREAMINFO:
1957 g_value_set_boxed(value, src->streaminfo);
1965 plugin_init (GstPlugin *plugin)
1967 if (!gst_library_load ("gstbytestream"))
1969 if (!gst_library_load ("gstriff"))
1971 if (!gst_library_load("gstvideo"))
1974 GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux", 0, "Demuxer for AVI video");
1976 if (!gst_element_register (plugin, "avidemux", GST_RANK_PRIMARY,
1977 GST_TYPE_AVI_DEMUX)) {
1981 if (!gst_element_register (plugin, "avimux", GST_RANK_PRIMARY,
1994 "AVI stream handling",