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), 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:
866 padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
867 templ = gst_element_class_get_pad_template (klass, "video_%02d");
868 caps = gst_riff_create_video_caps (strf.vids->compression, strh, strf.vids);
870 avi->num_v_streams++;
872 case GST_RIFF_FCC_auds:
873 padname = g_strdup_printf ("audio_%02d", avi->num_a_streams);
874 templ = gst_element_class_get_pad_template (klass, "audio_%02d");
875 caps = gst_riff_create_audio_caps (strf.auds->format, strh, strf.auds);
877 avi->num_a_streams++;
879 case GST_RIFF_FCC_iavs:
880 padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
881 templ = gst_element_class_get_pad_template (klass, "video_%02d");
882 caps = gst_riff_create_iavs_caps (strh->fcc_handler, strh, strf.iavs);
884 avi->num_v_streams++;
890 /* set proper settings and add it */
891 pad = gst_pad_new_from_template (templ, padname);
894 gst_pad_set_formats_function (pad, gst_avi_demux_get_src_formats);
895 gst_pad_set_event_mask_function (pad, gst_avi_demux_get_event_mask);
896 gst_pad_set_event_function (pad, gst_avi_demux_handle_src_event);
897 gst_pad_set_query_type_function (pad, gst_avi_demux_get_src_query_types);
898 gst_pad_set_query_function (pad, gst_avi_demux_handle_src_query);
899 gst_pad_set_convert_function (pad, gst_avi_demux_src_convert);
900 gst_pad_set_getcaps_function (pad, gst_avi_demux_src_getcaps);
902 stream = &avi->stream[avi->num_streams];
903 stream->caps = caps ? caps : gst_caps_new_empty ();
906 stream->num = avi->num_streams;
908 stream->total_bytes = 0LL;
909 stream->total_frames = 0;
910 stream->current_frame = 0;
911 stream->current_byte = 0;
912 stream->current_entry = -1;
914 gst_pad_set_element_private (pad, stream);
917 /* auto-negotiates */
918 gst_element_add_pad (GST_ELEMENT (avi), pad);
924 if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
930 if (!gst_riff_read_skip (riff))
934 /* add a "NULL" stream */
937 return TRUE; /* recoverable */
941 * Read an openDML-2.0 extension header.
945 gst_avi_demux_stream_odml (GstAviDemux *avi)
947 GstRiffRead *riff = GST_RIFF_READ (avi);
952 if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
954 else if (avi->level_up) {
960 case GST_RIFF_TAG_dmlh: {
961 gst_riff_dmlh dmlh, *_dmlh;
964 if (!gst_riff_read_data (riff, &tag, &buf))
966 if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_dmlh)) {
967 g_warning ("DMLH entry is too small (%d bytes, %d needed)",
968 GST_BUFFER_SIZE (buf), sizeof (gst_riff_dmlh));
969 gst_buffer_unref (buf);
972 _dmlh = (gst_riff_dmlh *) GST_BUFFER_DATA (buf);
973 dmlh.totalframes = GUINT32_FROM_LE (_dmlh->totalframes);
975 GST_INFO ("dmlh tag found:");
976 GST_INFO (" totalframes: %u", dmlh.totalframes);
978 avi->num_frames = dmlh.totalframes;
979 gst_buffer_unref (buf);
984 GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
985 GST_FOURCC_ARGS (tag));
988 case GST_RIFF_TAG_JUNK:
989 if (!gst_riff_read_skip (riff))
1004 * Seek to index, read it, seek back.
1008 gst_avi_demux_stream_index (GstAviDemux *avi)
1010 GstBuffer *buf = NULL;
1013 GstRiffRead *riff = GST_RIFF_READ (avi);
1014 guint64 pos_before, pos_after, length;
1017 /* first, we need to know the current position (to seek back
1018 * when we're done) and the total length of the file. */
1019 length = gst_bytestream_length (riff->bs);
1020 pos_before = gst_bytestream_tell (riff->bs);
1023 if (!gst_riff_read_skip (riff))
1026 /* assure that we've got data left */
1027 pos_after = gst_bytestream_tell (riff->bs);
1028 if (pos_after + 8 > length) {
1029 g_warning ("File said that it has an index, but there is no index data!");
1033 /* assure that it's an index */
1034 if (!(tag = gst_riff_peek_tag (riff, NULL)))
1036 if (tag != GST_RIFF_TAG_idx1) {
1037 g_warning ("No index after data, but " GST_FOURCC_FORMAT,
1038 GST_FOURCC_ARGS (tag));
1043 if (!gst_riff_read_data (riff, &tag, &buf))
1046 /* parse all entries */
1047 avi->index_size = GST_BUFFER_SIZE (buf) / sizeof (gst_riff_index_entry);
1048 avi->index_entries = g_malloc (avi->index_size * sizeof (gst_avi_index_entry));
1049 GST_INFO ("%u index entries", avi->index_size);
1051 for (i = 0; i < avi->index_size; i++) {
1052 gst_riff_index_entry entry, *_entry;
1053 avi_stream_context *stream;
1055 gst_avi_index_entry *target;
1058 _entry = &((gst_riff_index_entry *) GST_BUFFER_DATA (buf))[i];
1059 entry.id = GUINT32_FROM_LE (_entry->id);
1060 entry.offset = GUINT32_FROM_LE (_entry->offset);
1061 entry.flags = GUINT32_FROM_LE (_entry->flags);
1062 entry.size = GUINT32_FROM_LE (_entry->size);
1063 target = &avi->index_entries[i];
1065 stream_nr = CHUNKID_TO_STREAMNR (entry.id);
1066 if (stream_nr >= avi->num_streams || stream_nr < 0) {
1067 g_warning ("Index entry %d has invalid stream nr %d",
1069 target->stream_nr = -1;
1072 target->stream_nr = stream_nr;
1073 stream = &avi->stream[stream_nr];
1075 target->index_nr = i;
1076 target->flags = entry.flags;
1077 target->size = entry.size;
1078 target->offset = entry.offset;
1080 /* figure out if the index is 0 based or relative to the MOVI start */
1082 if (target->offset < pos_before)
1083 avi->index_offset = pos_before + 8;
1085 avi->index_offset = 0;
1088 target->bytes_before = stream->total_bytes;
1089 target->frames_before = stream->total_frames;
1091 format = GST_FORMAT_TIME;
1092 if (stream->strh->type == GST_RIFF_FCC_auds) {
1093 /* all audio frames are keyframes */
1094 target->flags |= GST_RIFF_IF_KEYFRAME;
1097 if (stream->strh->samplesize && stream->strh->type == GST_RIFF_FCC_auds) {
1098 /* constant rate stream */
1099 gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
1100 stream->total_bytes, &format, &target->ts);
1103 gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
1104 stream->total_frames, &format, &target->ts);
1107 stream->total_bytes += target->size;
1108 stream->total_frames++;
1111 /* debug our indexes */
1112 for (i = 0; i < avi->num_streams; i++) {
1113 avi_stream_context *stream;
1115 stream = &avi->stream[i];
1116 GST_DEBUG ("stream %u: %u frames, %" G_GINT64_FORMAT " bytes",
1117 i, stream->total_frames, stream->total_bytes);
1122 gst_buffer_unref (buf);
1124 /* seek back to the data */
1125 if (!(event = gst_riff_read_seek (riff, pos_before)))
1127 gst_event_unref (event);
1133 * Scan the file for all chunks to "create" a new index.
1137 gst_avi_demux_stream_scan (GstAviDemux *avi)
1139 //GstRiffRead *riff = GST_RIFF_READ (avi);
1147 * Read full AVI headers.
1151 gst_avi_demux_stream_header (GstAviDemux *avi)
1153 GstRiffRead *riff = GST_RIFF_READ (avi);
1154 guint32 tag, flags, streams;
1156 /* the header consists of a 'hdrl' LIST tag */
1157 if (!(tag = gst_riff_peek_tag (riff, NULL)))
1159 if (tag != GST_RIFF_TAG_LIST) {
1160 GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1161 ("Invalid AVI header (no LIST at start): "
1162 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1165 if (!gst_riff_read_list (riff, &tag))
1167 if (tag != GST_RIFF_LIST_hdrl) {
1168 GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1169 ("Invalid AVI header (no hdrl at start): "
1170 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1174 /* the hdrl starts with a 'avih' header */
1175 if (!(tag = gst_riff_peek_tag (riff, NULL)))
1177 if (tag != GST_RIFF_TAG_avih) {
1178 GST_ELEMENT_ERROR (avi, STREAM, DEMUX, (NULL),
1179 ("Invalid AVI header (no avih at start): "
1180 GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag)));
1183 if (!gst_avi_demux_stream_avih (avi, &flags, &streams))
1186 /* now, read the elements from the header until the end */
1188 if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
1190 else if (avi->level_up) {
1196 case GST_RIFF_TAG_LIST:
1197 if (!(tag = gst_riff_peek_list (riff)))
1201 case GST_RIFF_LIST_strl:
1202 if (!gst_riff_read_list (riff, &tag) ||
1203 !gst_avi_demux_add_stream (avi))
1207 case GST_RIFF_LIST_odml:
1208 if (!gst_riff_read_list (riff, &tag) ||
1209 !gst_avi_demux_stream_odml (avi))
1214 GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " in AVI header",
1215 GST_FOURCC_ARGS (tag));
1218 case GST_RIFF_TAG_JUNK:
1219 if (!gst_riff_read_skip (riff))
1227 GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
1228 GST_FOURCC_ARGS (tag));
1231 case GST_RIFF_TAG_JUNK:
1232 if (!gst_riff_read_skip (riff))
1237 if (avi->level_up) {
1243 if (avi->num_streams != streams) {
1244 g_warning ("Stream header mentioned %d streams, but %d available",
1245 streams, avi->num_streams);
1248 /* we've got streaminfo now */
1249 g_object_notify (G_OBJECT(avi), "streaminfo");
1251 /* Now, find the data (i.e. skip all junk between header and data) */
1253 if (!(tag = gst_riff_peek_tag (riff, NULL)))
1255 if (tag != GST_RIFF_TAG_LIST) {
1256 if (!gst_riff_read_skip (riff))
1260 if (!(tag = gst_riff_peek_list (riff)))
1262 if (tag != GST_RIFF_LIST_movi) {
1263 if (tag == GST_RIFF_LIST_INFO) {
1264 if (!gst_riff_read_list (riff, &tag) ||
1265 !gst_riff_read_info (riff))
1267 } else if (!gst_riff_read_skip (riff)) {
1275 /* create or read stream index (for seeking) */
1276 if (flags & GST_RIFF_AVIH_HASINDEX) {
1277 if (!gst_avi_demux_stream_index (avi))
1280 if (!gst_avi_demux_stream_scan (avi))
1292 gst_avi_demux_handle_seek (GstAviDemux *avi)
1294 GstRiffRead *riff = GST_RIFF_READ (avi);
1298 /* FIXME: if we seek in an openDML file, we will have multiple
1299 * primary levels. Seeking in between those will cause havoc. */
1301 if (!(event = gst_riff_read_seek (riff, avi->seek_offset)))
1303 gst_event_unref (event);
1305 for (i = 0; i < avi->num_streams; i++) {
1306 avi_stream_context *stream = &avi->stream[i];
1308 if (GST_PAD_IS_USABLE (stream->pad)) {
1309 event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
1310 avi->last_seek + stream->delay , NULL);
1311 gst_pad_push (stream->pad, GST_DATA (event));
1323 gst_avi_demux_stream_data (GstAviDemux *avi)
1325 GstRiffRead *riff = GST_RIFF_READ (avi);
1328 gst_avi_index_entry *entry;
1330 if (avi->seek_offset != (guint64) -1) {
1331 if (!gst_avi_demux_handle_seek (avi))
1333 avi->seek_offset = (guint64) -1;
1336 /* peek first (for the end of this 'list/movi' section) */
1337 if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
1340 /* if we're at top-level, we didn't read the 'movi'
1341 * list tag yet. This can also be 'AVIX' in case of
1342 * openDML-2.0 AVI files. Lastly, it might be idx1,
1343 * in which case we skip it so we come at EOS. */
1344 while (g_list_length (riff->level) < 2) {
1345 if (!(tag = gst_riff_peek_tag (riff, NULL)))
1349 case GST_RIFF_TAG_LIST:
1350 if (!(tag = gst_riff_peek_list (riff)))
1354 case GST_RIFF_LIST_AVIX:
1355 case GST_RIFF_LIST_movi:
1356 if (!gst_riff_read_list (riff, &tag))
1358 /* we're now going to read buffers! */
1362 GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " before AVI data",
1363 GST_FOURCC_ARGS (tag));
1366 case GST_RIFF_TAG_JUNK:
1367 if (!gst_riff_read_skip (riff))
1375 GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " before AVI data",
1376 GST_FOURCC_ARGS (tag));
1379 case GST_RIFF_TAG_idx1:
1380 case GST_RIFF_TAG_JUNK:
1381 if (!gst_riff_read_skip (riff))
1387 /* And then, we get the data */
1388 if (!(tag = gst_riff_peek_tag (riff, NULL)))
1390 stream_nr = CHUNKID_TO_STREAMNR (tag);
1391 if (stream_nr < 0 || stream_nr >= avi->num_streams) {
1393 g_warning ("Invalid stream ID %d (" GST_FOURCC_FORMAT ")",
1394 stream_nr, GST_FOURCC_ARGS (tag));
1395 if (!gst_riff_read_skip (riff))
1398 avi_stream_context *stream;
1399 GstClockTime next_ts;
1404 if (!gst_riff_read_data (riff, &tag, &buf))
1407 /* get time of this buffer */
1408 stream = &avi->stream[stream_nr];
1409 entry = gst_avi_demux_index_next (avi, stream_nr,
1410 stream->current_entry + 1, 0);
1412 stream->current_entry = entry->index_nr;
1413 if (entry->flags & GST_RIFF_IF_KEYFRAME) {
1414 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_KEY_UNIT);
1417 format = GST_FORMAT_TIME;
1418 gst_pad_query (stream->pad, GST_QUERY_POSITION,
1421 /* set delay (if any) */
1422 if (stream->strh->init_frames == stream->current_frame &&
1424 stream->delay = next_ts;
1426 stream->current_frame++;
1427 stream->current_byte += GST_BUFFER_SIZE (buf);
1429 /* should we skip this data? */
1432 gst_buffer_unref (buf);
1434 if (!stream->pad || !GST_PAD_IS_USABLE (stream->pad)) {
1435 gst_buffer_unref (buf);
1437 GstClockTime dur_ts;
1439 GST_BUFFER_TIMESTAMP (buf) = next_ts;
1440 gst_pad_query (stream->pad, GST_QUERY_POSITION,
1442 GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
1444 gst_pad_push (stream->pad, GST_DATA (buf));
1453 gst_avi_demux_loop (GstElement *element)
1455 GstAviDemux *avi = GST_AVI_DEMUX (element);
1457 switch (avi->state) {
1458 case GST_AVI_DEMUX_START:
1459 if (!gst_avi_demux_stream_init (avi))
1461 avi->state = GST_AVI_DEMUX_HEADER;
1464 case GST_AVI_DEMUX_HEADER:
1465 if (!gst_avi_demux_stream_header (avi))
1467 avi->state = GST_AVI_DEMUX_MOVI;
1470 case GST_AVI_DEMUX_MOVI:
1471 if (!gst_avi_demux_stream_data (avi))
1480 static GstElementStateReturn
1481 gst_avi_demux_change_state (GstElement *element)
1483 GstAviDemux *avi = GST_AVI_DEMUX (element);
1485 switch (GST_STATE_TRANSITION (element)) {
1486 case GST_STATE_READY_TO_PAUSED:
1487 gst_avi_demux_streaminfo (avi);
1489 case GST_STATE_PAUSED_TO_READY:
1490 gst_avi_demux_reset (avi);
1496 if (GST_ELEMENT_CLASS (parent_class)->change_state)
1497 return GST_ELEMENT_CLASS (parent_class)->change_state (element);
1499 return GST_STATE_SUCCESS;
1503 gst_avi_demux_get_property (GObject *object,
1508 GstAviDemux *avi = GST_AVI_DEMUX (object);
1511 case ARG_STREAMINFO:
1512 g_value_set_boxed (value, avi->streaminfo);
1515 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);