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.
19 /* Element-Checklist-Version: 5 */
27 #include "gst/riff/riff-media.h"
28 #include "gstavidemux.h"
31 GST_DEBUG_CATEGORY_STATIC (avidemux_debug);
32 #define GST_CAT_DEFAULT avidemux_debug
34 /* AviDemux signals and args */
46 static GstStaticPadTemplate sink_templ =
47 GST_STATIC_PAD_TEMPLATE (
51 GST_STATIC_CAPS ("video/x-msvideo")
54 static void gst_avi_demux_base_init (GstAviDemuxClass *klass);
55 static void gst_avi_demux_class_init (GstAviDemuxClass *klass);
56 static void gst_avi_demux_init (GstAviDemux *avi);
58 static void gst_avi_demux_reset (GstAviDemux *avi);
59 static void gst_avi_demux_loop (GstElement *element);
61 static gboolean gst_avi_demux_send_event (GstElement *element,
64 static const GstEventMask *
65 gst_avi_demux_get_event_mask (GstPad *pad);
66 static gboolean gst_avi_demux_handle_src_event (GstPad *pad,
68 static const GstFormat *
69 gst_avi_demux_get_src_formats (GstPad *pad);
70 static const GstQueryType *
71 gst_avi_demux_get_src_query_types (GstPad *pad);
72 static gboolean gst_avi_demux_handle_src_query (GstPad *pad,
76 static gboolean gst_avi_demux_src_convert (GstPad *pad,
79 GstFormat *dest_format,
82 static GstElementStateReturn
83 gst_avi_demux_change_state (GstElement *element);
85 static void gst_avi_demux_get_property (GObject *object,
90 static GstRiffReadClass *parent_class = NULL;
91 /*static guint gst_avi_demux_signals[LAST_SIGNAL] = { 0 }; */
94 gst_avi_demux_get_type(void)
96 static GType avi_demux_type = 0;
98 if (!avi_demux_type) {
99 static const GTypeInfo avi_demux_info = {
100 sizeof (GstAviDemuxClass),
101 (GBaseInitFunc) gst_avi_demux_base_init,
103 (GClassInitFunc) gst_avi_demux_class_init,
106 sizeof (GstAviDemux),
108 (GInstanceInitFunc) gst_avi_demux_init,
112 g_type_register_static (GST_TYPE_RIFF_READ,
117 return avi_demux_type;
121 gst_avi_demux_base_init (GstAviDemuxClass *klass)
123 static GstElementDetails gst_avi_demux_details = GST_ELEMENT_DETAILS (
126 "Demultiplex an avi file into audio and video",
127 "Erik Walthinsen <omega@cse.ogi.edu>\n"
128 "Wim Taymans <wim.taymans@chello.be>\n"
129 "Ronald Bultje <rbultje@ronald.bitfreak.net>"
131 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
132 GstPadTemplate *videosrctempl, *audiosrctempl;
133 GstCaps *audcaps, *vidcaps;
135 audcaps = gst_riff_create_audio_template_caps ();
136 audiosrctempl = gst_pad_template_new ("audio_%02d",
141 vidcaps = gst_riff_create_video_template_caps ();
142 gst_caps_append (vidcaps, gst_riff_create_iavs_template_caps ());
143 videosrctempl = gst_pad_template_new ("video_%02d",
148 gst_element_class_add_pad_template (element_class, audiosrctempl);
149 gst_element_class_add_pad_template (element_class, videosrctempl);
150 gst_element_class_add_pad_template (element_class,
151 gst_static_pad_template_get (&sink_templ));
152 gst_element_class_set_details (element_class, &gst_avi_demux_details);
156 gst_avi_demux_class_init (GstAviDemuxClass *klass)
158 GObjectClass *gobject_class;
159 GstElementClass *gstelement_class;
161 gobject_class = (GObjectClass*)klass;
162 gstelement_class = (GstElementClass*)klass;
164 g_object_class_install_property (gobject_class, ARG_STREAMINFO,
165 g_param_spec_boxed ("streaminfo", "Streaminfo", "Streaminfo",
166 GST_TYPE_CAPS, G_PARAM_READABLE));
168 GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux",
169 0, "Demuxer for AVI streams");
171 parent_class = g_type_class_ref (GST_TYPE_RIFF_READ);
173 gobject_class->get_property = gst_avi_demux_get_property;
175 gstelement_class->change_state = gst_avi_demux_change_state;
176 gstelement_class->send_event = gst_avi_demux_send_event;
180 gst_avi_demux_init (GstAviDemux *avi)
182 GST_FLAG_SET (avi, GST_ELEMENT_EVENT_AWARE);
184 avi->sinkpad = gst_pad_new_from_template (
185 gst_static_pad_template_get (&sink_templ), "sink");
186 gst_element_add_pad (GST_ELEMENT (avi), avi->sinkpad);
187 GST_RIFF_READ (avi)->sinkpad = avi->sinkpad;
189 gst_element_set_loop_function (GST_ELEMENT (avi), gst_avi_demux_loop);
190 gst_avi_demux_reset (avi);
192 avi->streaminfo = NULL;
193 avi->index_entries = NULL;
194 memset (&avi->stream, 0, sizeof (avi->stream));
198 gst_avi_demux_reset (GstAviDemux *avi)
202 for (i = 0; i < avi->num_streams; i++) {
203 g_free (avi->stream[i].strh);
204 gst_element_remove_pad (GST_ELEMENT (avi), avi->stream[i].pad);
206 memset (&avi->stream, 0, sizeof (avi->stream));
208 avi->num_streams = 0;
209 avi->num_v_streams = 0;
210 avi->num_a_streams = 0;
212 avi->state = GST_AVI_DEMUX_START;
215 if (avi->index_entries) {
216 g_free (avi->index_entries);
217 avi->index_entries = NULL;
222 avi->us_per_frame = 0;
224 avi->seek_offset = (guint64) -1;
226 gst_caps_replace (&avi->streaminfo, NULL);
230 gst_avi_demux_streaminfo (GstAviDemux *avi)
232 /* compression formats are added later - a bit hacky */
234 gst_caps_replace (&avi->streaminfo,
235 gst_caps_new_simple ("application/x-gst-streaminfo", NULL));
237 /*g_object_notify(G_OBJECT(avi), "streaminfo");*/
240 static gst_avi_index_entry *
241 gst_avi_demux_index_next (GstAviDemux *avi,
247 gst_avi_index_entry *entry = NULL;
249 for (i = start; i < avi->index_size; i++) {
250 entry = &avi->index_entries[i];
252 if (entry->stream_nr == stream_nr && (entry->flags & flags) == flags) {
260 static gst_avi_index_entry *
261 gst_avi_demux_index_entry_for_time (GstAviDemux *avi,
266 gst_avi_index_entry *entry = NULL, *last_entry = NULL;
271 entry = gst_avi_demux_index_next (avi, stream_nr, i + 1, flags);
277 if (entry->ts <= time) {
280 } while (entry->ts <= time);
285 static gst_avi_index_entry *
286 gst_avi_demux_index_entry_for_byte (GstAviDemux *avi,
291 gst_avi_index_entry *entry = NULL, *last_entry = NULL;
296 entry = gst_avi_demux_index_next (avi, stream_nr, i + 1, flags);
302 if (entry->bytes_before <= byte) {
305 } while (entry->bytes_before <= byte);
310 static gst_avi_index_entry *
311 gst_avi_demux_index_entry_for_frame (GstAviDemux *avi,
316 gst_avi_index_entry *entry = NULL, *last_entry = NULL;
321 entry = gst_avi_demux_index_next (avi, stream_nr, i + 1, flags);
327 if (entry->frames_before <= frame) {
330 } while (entry->frames_before <= frame);
335 static const GstFormat *
336 gst_avi_demux_get_src_formats (GstPad *pad)
338 avi_stream_context *stream = gst_pad_get_element_private (pad);
340 static const GstFormat src_a_formats[] = {
346 static const GstFormat src_v_formats[] = {
352 return (stream->strh->type == GST_RIFF_FCC_auds ?
353 src_a_formats : src_v_formats);
357 gst_avi_demux_src_convert (GstPad *pad,
358 GstFormat src_format,
360 GstFormat *dest_format,
364 /*GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));*/
365 avi_stream_context *stream = gst_pad_get_element_private (pad);
367 if (stream->strh->type != GST_RIFF_FCC_auds &&
368 (src_format == GST_FORMAT_BYTES ||
369 *dest_format == GST_FORMAT_BYTES))
372 switch (src_format) {
373 case GST_FORMAT_TIME:
374 switch (*dest_format) {
375 case GST_FORMAT_BYTES:
376 *dest_value = src_value * stream->strh->rate /
377 (stream->strh->scale * GST_SECOND);
379 case GST_FORMAT_DEFAULT:
380 *dest_value = src_value * stream->strh->rate /
381 (stream->strh->scale * GST_SECOND);
388 case GST_FORMAT_BYTES:
389 switch (*dest_format) {
390 case GST_FORMAT_TIME:
391 *dest_value = ((gfloat) src_value) * GST_SECOND / stream->strh->rate;
398 case GST_FORMAT_DEFAULT:
399 switch (*dest_format) {
400 case GST_FORMAT_TIME:
401 *dest_value = ((((gfloat) src_value) * stream->strh->scale) /
402 stream->strh->rate) * GST_SECOND;
416 static const GstQueryType *
417 gst_avi_demux_get_src_query_types (GstPad *pad)
419 static const GstQueryType src_types[] = {
429 gst_avi_demux_handle_src_query (GstPad *pad,
435 /*GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));*/
436 avi_stream_context *stream = gst_pad_get_element_private (pad);
439 case GST_QUERY_TOTAL:
441 case GST_FORMAT_TIME:
442 *value = (((gfloat) stream->strh->scale) * stream->strh->length /
443 stream->strh->rate) * GST_SECOND;
445 case GST_FORMAT_BYTES:
446 if (stream->strh->type == GST_RIFF_FCC_auds) {
447 *value = stream->total_bytes;
452 case GST_FORMAT_DEFAULT:
453 if (stream->strh->type == GST_RIFF_FCC_auds)
454 *value = stream->strh->length * stream->strh->samplesize;
455 else if (stream->strh->type == GST_RIFF_FCC_vids)
456 *value = stream->strh->length;
465 case GST_QUERY_POSITION:
467 case GST_FORMAT_TIME:
468 if (stream->strh->samplesize &&
469 stream->strh->type == GST_RIFF_FCC_auds) {
470 *value = ((gfloat) stream->current_byte) * GST_SECOND /
474 *value = (((gfloat) stream->current_frame) * stream->strh->scale /
475 stream->strh->rate) * GST_SECOND;
478 case GST_FORMAT_BYTES:
479 *value = stream->current_byte;
481 case GST_FORMAT_DEFAULT:
482 if (stream->strh->samplesize &&
483 stream->strh->type == GST_RIFF_FCC_auds)
484 *value = stream->current_byte * stream->strh->samplesize;
486 *value = stream->current_frame;
502 gst_avi_demux_src_getcaps (GstPad *pad)
504 avi_stream_context *stream = gst_pad_get_element_private (pad);
506 return gst_caps_copy (stream->caps);
510 gst_avi_demux_sync_streams (GstAviDemux *avi,
514 guint32 min_index = G_MAXUINT;
515 avi_stream_context *stream;
516 gst_avi_index_entry *entry;
518 for (i = 0; i < avi->num_streams; i++) {
519 stream = &avi->stream[i];
521 GST_DEBUG ("finding %d for time %" G_GINT64_FORMAT, i, time);
523 entry = gst_avi_demux_index_entry_for_time (avi, stream->num, time,
524 GST_RIFF_IF_KEYFRAME);
526 min_index = MIN (entry->index_nr, min_index);
529 GST_DEBUG ("first index at %d", min_index);
531 /* now we know the entry we need to sync on. calculate number of frames to
532 * skip fro there on and the stream stats */
533 for (i = 0; i < avi->num_streams; i++) {
534 gst_avi_index_entry *next_entry;
535 stream = &avi->stream[i];
538 next_entry = gst_avi_demux_index_next (avi, stream->num,
540 /* next entry with keyframe */
541 entry = gst_avi_demux_index_next (avi, stream->num, min_index,
542 GST_RIFF_IF_KEYFRAME);
544 stream->current_byte = next_entry->bytes_before;
545 stream->current_frame = next_entry->frames_before;
546 stream->skip = entry->frames_before - next_entry->frames_before;
548 GST_DEBUG ("%d skip %d", stream->num, stream->skip);
551 GST_DEBUG ("final index at %d", min_index);
557 gst_avi_demux_send_event (GstElement *element,
562 pads = gst_element_get_pad_list (element);
565 GstPad *pad = GST_PAD (pads->data);
567 if (GST_PAD_DIRECTION (pad) == GST_PAD_SRC) {
568 /* we ref the event here as we might have to try again if the event
569 * failed on this pad */
570 gst_event_ref (event);
571 if (gst_avi_demux_handle_src_event (pad, event)) {
572 gst_event_unref (event);
578 pads = g_list_next (pads);
581 gst_event_unref (event);
586 static const GstEventMask *
587 gst_avi_demux_get_event_mask (GstPad *pad)
589 static const GstEventMask masks[] = {
590 { GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
598 gst_avi_demux_handle_src_event (GstPad *pad,
602 GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
603 avi_stream_context *stream;
605 stream = gst_pad_get_element_private (pad);
607 switch (GST_EVENT_TYPE (event)) {
609 GST_DEBUG ("seek format %d, %08x", GST_EVENT_SEEK_FORMAT (event),
612 switch (GST_EVENT_SEEK_FORMAT (event)) {
613 case GST_FORMAT_BYTES:
614 case GST_FORMAT_DEFAULT:
615 case GST_FORMAT_TIME: {
616 gst_avi_index_entry *seek_entry, *entry = NULL;
617 gint64 desired_offset = GST_EVENT_SEEK_OFFSET (event);
621 /* no seek on audio yet */
622 if (stream->strh->type == GST_RIFF_FCC_auds) {
626 GST_DEBUG ("seeking to %" G_GINT64_FORMAT, desired_offset);
628 flags = GST_RIFF_IF_KEYFRAME;
629 switch (GST_EVENT_SEEK_FORMAT (event)) {
630 case GST_FORMAT_BYTES:
631 entry = gst_avi_demux_index_entry_for_byte (avi, stream->num,
635 case GST_FORMAT_DEFAULT:
636 entry = gst_avi_demux_index_entry_for_frame (avi, stream->num,
640 case GST_FORMAT_TIME:
641 entry = gst_avi_demux_index_entry_for_time (avi, stream->num,
648 min_index = gst_avi_demux_sync_streams (avi, entry->ts);
649 seek_entry = &avi->index_entries[min_index];
651 avi->seek_offset = seek_entry->offset + avi->index_offset;
652 avi->last_seek = entry->ts;
654 GST_DEBUG ("no index entry found for format=%d value=%"
655 G_GINT64_FORMAT, GST_EVENT_SEEK_FORMAT (event),
672 gst_event_unref (event);
678 * "Open" a RIFF file.
682 gst_avi_demux_stream_init (GstAviDemux *avi)
684 GstRiffRead *riff = GST_RIFF_READ (avi);
687 if (!gst_riff_read_header (riff, &doctype))
689 if (doctype != GST_RIFF_RIFF_AVI) {
690 GST_ELEMENT_ERROR (avi, STREAM, WRONG_TYPE, (NULL), (NULL));
698 * Read 'avih' header.
702 gst_avi_demux_stream_avih (GstAviDemux *avi,
706 GstRiffRead *riff = GST_RIFF_READ (avi);
709 gst_riff_avih avih, *_avih;
711 if (!gst_riff_read_data (riff, &tag, &buf))
714 if (tag != GST_RIFF_TAG_avih) {
715 g_warning ("Not a avih chunk");
716 gst_buffer_unref (buf);
719 if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_avih)) {
720 g_warning ("Too small avih (%d available, %d needed)",
721 GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_avih));
722 gst_buffer_unref (buf);
726 _avih = (gst_riff_avih *) GST_BUFFER_DATA (buf);
727 avih.us_frame = GUINT32_FROM_LE (_avih->us_frame);
728 avih.max_bps = GUINT32_FROM_LE (_avih->max_bps);
729 avih.pad_gran = GUINT32_FROM_LE (_avih->pad_gran);
730 avih.flags = GUINT32_FROM_LE (_avih->flags);
731 avih.tot_frames = GUINT32_FROM_LE (_avih->tot_frames);
732 avih.init_frames = GUINT32_FROM_LE (_avih->init_frames);
733 avih.streams = GUINT32_FROM_LE (_avih->streams);
734 avih.bufsize = GUINT32_FROM_LE (_avih->bufsize);
735 avih.width = GUINT32_FROM_LE (_avih->width);
736 avih.height = GUINT32_FROM_LE (_avih->height);
737 avih.scale = GUINT32_FROM_LE (_avih->scale);
738 avih.rate = GUINT32_FROM_LE (_avih->rate);
739 avih.start = GUINT32_FROM_LE (_avih->start);
740 avih.length = GUINT32_FROM_LE (_avih->length);
743 GST_INFO ("avih tag found:");
744 GST_INFO (" us_frame %u", avih.us_frame);
745 GST_INFO (" max_bps %u", avih.max_bps);
746 GST_INFO (" pad_gran %u", avih.pad_gran);
747 GST_INFO (" flags 0x%08x", avih.flags);
748 GST_INFO (" tot_frames %u", avih.tot_frames);
749 GST_INFO (" init_frames %u", avih.init_frames);
750 GST_INFO (" streams %u", avih.streams);
751 GST_INFO (" bufsize %u", avih.bufsize);
752 GST_INFO (" width %u", avih.width);
753 GST_INFO (" height %u", avih.height);
754 GST_INFO (" scale %u", avih.scale);
755 GST_INFO (" rate %u", avih.rate);
756 GST_INFO (" start %u", avih.start);
757 GST_INFO (" length %u", avih.length);
759 avi->num_frames = avih.tot_frames;
760 avi->us_per_frame = avih.us_frame;
761 *streams = avih.streams;
764 gst_buffer_unref (buf);
774 gst_avi_demux_add_stream (GstAviDemux *avi)
776 GstElementClass *klass = GST_ELEMENT_GET_CLASS (avi);
777 GstRiffRead *riff = GST_RIFF_READ (avi);
780 gchar *name = NULL, *padname = NULL;
781 GstCaps *caps = NULL;
782 GstPadTemplate *templ = NULL;
784 avi_stream_context *stream;
786 gst_riff_strf_vids *vids;
787 gst_riff_strf_auds *auds;
788 gst_riff_strf_iavs *iavs;
791 /* the stream starts with a 'strh' header */
792 if (!(tag = gst_riff_peek_tag (riff, NULL)))
794 if (tag != GST_RIFF_TAG_strh) {
795 g_warning ("Invalid stream header (no strh at begin)");
798 if (!gst_riff_read_strh (riff, &strh))
801 /* then comes a 'strf' of that specific type */
802 if (!(tag = gst_riff_peek_tag (riff, NULL)))
804 if (tag != GST_RIFF_TAG_strf) {
805 GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
806 ("Invalid AVI header (no strf as second tag)"));
809 switch (strh->type) {
810 case GST_RIFF_FCC_vids:
811 if (!gst_riff_read_strf_vids (riff, &strf.vids))
814 case GST_RIFF_FCC_auds:
815 if (!gst_riff_read_strf_auds (riff, &strf.auds))
818 case GST_RIFF_FCC_iavs:
819 if (!gst_riff_read_strf_iavs (riff, &strf.iavs))
823 g_warning ("Unknown stream type " GST_FOURCC_FORMAT,
824 GST_FOURCC_ARGS (strh->type));
828 /* read other things */
830 if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
832 else if (avi->level_up) {
838 case GST_RIFF_TAG_strn:
841 if (!gst_riff_read_ascii (riff, &tag, &name))
846 GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
847 GST_FOURCC_ARGS (tag));
850 case GST_RIFF_TAG_strd: /* what is this? */
851 case GST_RIFF_TAG_JUNK:
852 if (!gst_riff_read_skip (riff))
863 /* create stream name + pad */
864 switch (strh->type) {
865 case GST_RIFF_FCC_vids:
867 char *codec_name = NULL;
868 GstTagList *list = gst_tag_list_new ();
869 padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
870 templ = gst_element_class_get_pad_template (klass, "video_%02d");
871 caps = gst_riff_create_video_caps (strf.vids->compression, strh,
872 strf.vids, &codec_name);
873 gst_tag_list_add (list, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
875 gst_element_found_tags (GST_ELEMENT (avi), list);
876 gst_tag_list_free (list);
877 if (codec_name) g_free (codec_name);
879 avi->num_v_streams++;
882 case GST_RIFF_FCC_auds:
884 char *codec_name = NULL;
885 GstTagList *list = gst_tag_list_new ();
886 padname = g_strdup_printf ("audio_%02d", avi->num_a_streams);
887 templ = gst_element_class_get_pad_template (klass, "audio_%02d");
888 caps = gst_riff_create_audio_caps (strf.auds->format, strh, strf.auds,
890 gst_tag_list_add (list, GST_TAG_MERGE_APPEND, GST_TAG_AUDIO_CODEC,
892 gst_element_found_tags (GST_ELEMENT (avi), list);
893 gst_tag_list_free (list);
894 if (codec_name) g_free (codec_name);
896 avi->num_a_streams++;
899 case GST_RIFF_FCC_iavs:
901 char *codec_name = NULL;
902 GstTagList *list = gst_tag_list_new ();
903 padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
904 templ = gst_element_class_get_pad_template (klass, "video_%02d");
905 caps = gst_riff_create_iavs_caps (strh->fcc_handler, strh, strf.iavs,
907 gst_tag_list_add (list, GST_TAG_MERGE_APPEND, GST_TAG_VIDEO_CODEC,
909 gst_element_found_tags (GST_ELEMENT (avi), list);
910 gst_tag_list_free (list);
911 if (codec_name) g_free (codec_name);
913 avi->num_v_streams++;
920 /* set proper settings and add it */
921 pad = gst_pad_new_from_template (templ, padname);
924 gst_pad_set_formats_function (pad, gst_avi_demux_get_src_formats);
925 gst_pad_set_event_mask_function (pad, gst_avi_demux_get_event_mask);
926 gst_pad_set_event_function (pad, gst_avi_demux_handle_src_event);
927 gst_pad_set_query_type_function (pad, gst_avi_demux_get_src_query_types);
928 gst_pad_set_query_function (pad, gst_avi_demux_handle_src_query);
929 gst_pad_set_convert_function (pad, gst_avi_demux_src_convert);
930 gst_pad_set_getcaps_function (pad, gst_avi_demux_src_getcaps);
932 stream = &avi->stream[avi->num_streams];
933 stream->caps = caps ? caps : gst_caps_new_empty ();
936 stream->num = avi->num_streams;
938 stream->total_bytes = 0LL;
939 stream->total_frames = 0;
940 stream->current_frame = 0;
941 stream->current_byte = 0;
942 stream->current_entry = -1;
944 gst_pad_set_element_private (pad, stream);
947 /* auto-negotiates */
948 gst_element_add_pad (GST_ELEMENT (avi), pad);
954 if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
960 if (!gst_riff_read_skip (riff))
964 /* add a "NULL" stream */
967 return TRUE; /* recoverable */
971 * Read an openDML-2.0 extension header.
975 gst_avi_demux_stream_odml (GstAviDemux *avi)
977 GstRiffRead *riff = GST_RIFF_READ (avi);
982 if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
984 else if (avi->level_up) {
990 case GST_RIFF_TAG_dmlh: {
991 gst_riff_dmlh dmlh, *_dmlh;
994 if (!gst_riff_read_data (riff, &tag, &buf))
996 if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_dmlh)) {
997 g_warning ("DMLH entry is too small (%d bytes, %d needed)",
998 GST_BUFFER_SIZE (buf), (int) sizeof (gst_riff_dmlh));
999 gst_buffer_unref (buf);
1002 _dmlh = (gst_riff_dmlh *) GST_BUFFER_DATA (buf);
1003 dmlh.totalframes = GUINT32_FROM_LE (_dmlh->totalframes);
1005 GST_INFO ("dmlh tag found:");
1006 GST_INFO (" totalframes: %u", dmlh.totalframes);
1008 avi->num_frames = dmlh.totalframes;
1009 gst_buffer_unref (buf);
1014 GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
1015 GST_FOURCC_ARGS (tag));
1018 case GST_RIFF_TAG_JUNK:
1019 if (!gst_riff_read_skip (riff))
1024 if (avi->level_up) {
1034 * Seek to index, read it, seek back.
1038 gst_avi_demux_stream_index (GstAviDemux *avi)
1040 GstBuffer *buf = NULL;
1043 GstRiffRead *riff = GST_RIFF_READ (avi);
1044 guint64 pos_before, pos_after, length;
1047 /* first, we need to know the current position (to seek back
1048 * when we're done) and the total length of the file. */
1049 length = gst_bytestream_length (riff->bs);
1050 pos_before = gst_bytestream_tell (riff->bs);
1053 if (!gst_riff_read_skip (riff))
1056 /* assure that we've got data left */
1057 pos_after = gst_bytestream_tell (riff->bs);
1058 if (pos_after + 8 > length) {
1059 g_warning ("File said that it has an index, but there is no index data!");
1063 /* assure that it's an index */
1064 if (!(tag = gst_riff_peek_tag (riff, NULL)))
1066 if (tag != GST_RIFF_TAG_idx1) {
1067 g_warning ("No index after data, but " GST_FOURCC_FORMAT,
1068 GST_FOURCC_ARGS (tag));
1073 if (!gst_riff_read_data (riff, &tag, &buf))
1076 /* parse all entries */
1077 avi->index_size = GST_BUFFER_SIZE (buf) / sizeof (gst_riff_index_entry);
1078 avi->index_entries = g_malloc (avi->index_size * sizeof (gst_avi_index_entry));
1079 GST_INFO ("%u index entries", avi->index_size);
1081 for (i = 0; i < avi->index_size; i++) {
1082 gst_riff_index_entry entry, *_entry;
1083 avi_stream_context *stream;
1085 gst_avi_index_entry *target;
1088 _entry = &((gst_riff_index_entry *) GST_BUFFER_DATA (buf))[i];
1089 entry.id = GUINT32_FROM_LE (_entry->id);
1090 entry.offset = GUINT32_FROM_LE (_entry->offset);
1091 entry.flags = GUINT32_FROM_LE (_entry->flags);
1092 entry.size = GUINT32_FROM_LE (_entry->size);
1093 target = &avi->index_entries[i];
1095 stream_nr = CHUNKID_TO_STREAMNR (entry.id);
1096 if (stream_nr >= avi->num_streams || stream_nr < 0) {
1097 g_warning ("Index entry %d has invalid stream nr %d",
1099 target->stream_nr = -1;
1102 target->stream_nr = stream_nr;
1103 stream = &avi->stream[stream_nr];
1105 target->index_nr = i;
1106 target->flags = entry.flags;
1107 target->size = entry.size;
1108 target->offset = entry.offset;
1110 /* figure out if the index is 0 based or relative to the MOVI start */
1112 if (target->offset < pos_before)
1113 avi->index_offset = pos_before + 8;
1115 avi->index_offset = 0;
1118 target->bytes_before = stream->total_bytes;
1119 target->frames_before = stream->total_frames;
1121 format = GST_FORMAT_TIME;
1122 if (stream->strh->type == GST_RIFF_FCC_auds) {
1123 /* all audio frames are keyframes */
1124 target->flags |= GST_RIFF_IF_KEYFRAME;
1127 if (stream->strh->samplesize && stream->strh->type == GST_RIFF_FCC_auds) {
1128 /* constant rate stream */
1129 gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
1130 stream->total_bytes, &format, &target->ts);
1133 gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
1134 stream->total_frames, &format, &target->ts);
1137 stream->total_bytes += target->size;
1138 stream->total_frames++;
1141 /* debug our indexes */
1142 for (i = 0; i < avi->num_streams; i++) {
1143 avi_stream_context *stream;
1145 stream = &avi->stream[i];
1146 GST_DEBUG ("stream %u: %u frames, %" G_GINT64_FORMAT " bytes",
1147 i, stream->total_frames, stream->total_bytes);
1152 gst_buffer_unref (buf);
1154 /* seek back to the data */
1155 if (!(event = gst_riff_read_seek (riff, pos_before)))
1157 gst_event_unref (event);
1163 * Scan the file for all chunks to "create" a new index.
1167 gst_avi_demux_stream_scan (GstAviDemux *avi)
1169 //GstRiffRead *riff = GST_RIFF_READ (avi);
1177 * Read full AVI headers.
1181 gst_avi_demux_stream_header (GstAviDemux *avi)
1183 GstRiffRead *riff = GST_RIFF_READ (avi);
1184 guint32 tag, flags, streams;
1186 /* the header consists of a 'hdrl' LIST tag */
1187 if (!(tag = gst_riff_peek_tag (riff, NULL)))
1189 if (tag != GST_RIFF_TAG_LIST) {
1190 GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1191 ("Invalid AVI header (no LIST at start): "
1192 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1195 if (!gst_riff_read_list (riff, &tag))
1197 if (tag != GST_RIFF_LIST_hdrl) {
1198 GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1199 ("Invalid AVI header (no hdrl at start): "
1200 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1204 /* the hdrl starts with a 'avih' header */
1205 if (!(tag = gst_riff_peek_tag (riff, NULL)))
1207 if (tag != GST_RIFF_TAG_avih) {
1208 GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1209 ("Invalid AVI header (no avih at start): "
1210 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1213 if (!gst_avi_demux_stream_avih (avi, &flags, &streams))
1216 /* now, read the elements from the header until the end */
1218 if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
1220 else if (avi->level_up) {
1226 case GST_RIFF_TAG_LIST:
1227 if (!(tag = gst_riff_peek_list (riff)))
1231 case GST_RIFF_LIST_strl:
1232 if (!gst_riff_read_list (riff, &tag) ||
1233 !gst_avi_demux_add_stream (avi))
1237 case GST_RIFF_LIST_odml:
1238 if (!gst_riff_read_list (riff, &tag) ||
1239 !gst_avi_demux_stream_odml (avi))
1244 GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " in AVI header",
1245 GST_FOURCC_ARGS (tag));
1248 case GST_RIFF_TAG_JUNK:
1249 if (!gst_riff_read_skip (riff))
1257 GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
1258 GST_FOURCC_ARGS (tag));
1261 case GST_RIFF_TAG_JUNK:
1262 if (!gst_riff_read_skip (riff))
1267 if (avi->level_up) {
1273 if (avi->num_streams != streams) {
1274 g_warning ("Stream header mentioned %d streams, but %d available",
1275 streams, avi->num_streams);
1278 /* we've got streaminfo now */
1279 g_object_notify (G_OBJECT(avi), "streaminfo");
1281 /* Now, find the data (i.e. skip all junk between header and data) */
1283 if (!(tag = gst_riff_peek_tag (riff, NULL)))
1285 if (tag != GST_RIFF_TAG_LIST) {
1286 if (!gst_riff_read_skip (riff))
1290 if (!(tag = gst_riff_peek_list (riff)))
1292 if (tag != GST_RIFF_LIST_movi) {
1293 if (tag == GST_RIFF_LIST_INFO) {
1294 if (!gst_riff_read_list (riff, &tag) ||
1295 !gst_riff_read_info (riff))
1297 } else if (!gst_riff_read_skip (riff)) {
1305 /* create or read stream index (for seeking) */
1306 if (flags & GST_RIFF_AVIH_HASINDEX) {
1307 if (!gst_avi_demux_stream_index (avi))
1310 if (!gst_avi_demux_stream_scan (avi))
1322 gst_avi_demux_handle_seek (GstAviDemux *avi)
1324 GstRiffRead *riff = GST_RIFF_READ (avi);
1328 /* FIXME: if we seek in an openDML file, we will have multiple
1329 * primary levels. Seeking in between those will cause havoc. */
1331 if (!(event = gst_riff_read_seek (riff, avi->seek_offset)))
1333 gst_event_unref (event);
1335 for (i = 0; i < avi->num_streams; i++) {
1336 avi_stream_context *stream = &avi->stream[i];
1338 if (GST_PAD_IS_USABLE (stream->pad)) {
1339 event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
1340 avi->last_seek + stream->delay , NULL);
1341 gst_pad_push (stream->pad, GST_DATA (event));
1353 gst_avi_demux_stream_data (GstAviDemux *avi)
1355 GstRiffRead *riff = GST_RIFF_READ (avi);
1358 gst_avi_index_entry *entry;
1360 if (avi->seek_offset != (guint64) -1) {
1361 if (!gst_avi_demux_handle_seek (avi))
1363 avi->seek_offset = (guint64) -1;
1366 /* peek first (for the end of this 'list/movi' section) */
1367 if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
1370 /* if we're at top-level, we didn't read the 'movi'
1371 * list tag yet. This can also be 'AVIX' in case of
1372 * openDML-2.0 AVI files. Lastly, it might be idx1,
1373 * in which case we skip it so we come at EOS. */
1374 while (g_list_length (riff->level) < 2) {
1375 if (!(tag = gst_riff_peek_tag (riff, NULL)))
1379 case GST_RIFF_TAG_LIST:
1380 if (!(tag = gst_riff_peek_list (riff)))
1384 case GST_RIFF_LIST_AVIX:
1385 case GST_RIFF_LIST_movi:
1386 if (!gst_riff_read_list (riff, &tag))
1388 /* we're now going to read buffers! */
1392 GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " before AVI data",
1393 GST_FOURCC_ARGS (tag));
1396 case GST_RIFF_TAG_JUNK:
1397 if (!gst_riff_read_skip (riff))
1405 GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " before AVI data",
1406 GST_FOURCC_ARGS (tag));
1409 case GST_RIFF_TAG_idx1:
1410 case GST_RIFF_TAG_JUNK:
1411 if (!gst_riff_read_skip (riff))
1417 /* And then, we get the data */
1418 if (!(tag = gst_riff_peek_tag (riff, NULL)))
1420 stream_nr = CHUNKID_TO_STREAMNR (tag);
1421 if (stream_nr < 0 || stream_nr >= avi->num_streams) {
1423 g_warning ("Invalid stream ID %d (" GST_FOURCC_FORMAT ")",
1424 stream_nr, GST_FOURCC_ARGS (tag));
1425 if (!gst_riff_read_skip (riff))
1428 avi_stream_context *stream;
1429 GstClockTime next_ts;
1434 if (!gst_riff_read_data (riff, &tag, &buf))
1437 /* get time of this buffer */
1438 stream = &avi->stream[stream_nr];
1439 entry = gst_avi_demux_index_next (avi, stream_nr,
1440 stream->current_entry + 1, 0);
1442 stream->current_entry = entry->index_nr;
1443 if (entry->flags & GST_RIFF_IF_KEYFRAME) {
1444 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_KEY_UNIT);
1447 format = GST_FORMAT_TIME;
1448 gst_pad_query (stream->pad, GST_QUERY_POSITION,
1451 /* set delay (if any) */
1452 if (stream->strh->init_frames == stream->current_frame &&
1454 stream->delay = next_ts;
1456 stream->current_frame++;
1457 stream->current_byte += GST_BUFFER_SIZE (buf);
1459 /* should we skip this data? */
1462 gst_buffer_unref (buf);
1464 if (!stream->pad || !GST_PAD_IS_USABLE (stream->pad)) {
1465 gst_buffer_unref (buf);
1467 GstClockTime dur_ts;
1469 GST_BUFFER_TIMESTAMP (buf) = next_ts;
1470 gst_pad_query (stream->pad, GST_QUERY_POSITION,
1472 GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
1474 gst_pad_push (stream->pad, GST_DATA (buf));
1483 gst_avi_demux_loop (GstElement *element)
1485 GstAviDemux *avi = GST_AVI_DEMUX (element);
1487 switch (avi->state) {
1488 case GST_AVI_DEMUX_START:
1489 if (!gst_avi_demux_stream_init (avi))
1491 avi->state = GST_AVI_DEMUX_HEADER;
1494 case GST_AVI_DEMUX_HEADER:
1495 if (!gst_avi_demux_stream_header (avi))
1497 avi->state = GST_AVI_DEMUX_MOVI;
1500 case GST_AVI_DEMUX_MOVI:
1501 if (!gst_avi_demux_stream_data (avi))
1510 static GstElementStateReturn
1511 gst_avi_demux_change_state (GstElement *element)
1513 GstAviDemux *avi = GST_AVI_DEMUX (element);
1515 switch (GST_STATE_TRANSITION (element)) {
1516 case GST_STATE_READY_TO_PAUSED:
1517 gst_avi_demux_streaminfo (avi);
1519 case GST_STATE_PAUSED_TO_READY:
1520 gst_avi_demux_reset (avi);
1526 if (GST_ELEMENT_CLASS (parent_class)->change_state)
1527 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1529 return GST_STATE_SUCCESS;
1533 gst_avi_demux_get_property (GObject *object,
1538 GstAviDemux *avi = GST_AVI_DEMUX (object);
1541 case ARG_STREAMINFO:
1542 g_value_set_boxed (value, avi->streaminfo);
1545 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);