summaryrefslogtreecommitdiffstats
path: root/gst/avi/gstavidemux.c
diff options
context:
space:
mode:
authorRonald S. Bultje <rbultje@ronald.bitfreak.net>2003-12-07 20:00:41 +0000
committerRonald S. Bultje <rbultje@ronald.bitfreak.net>2003-12-07 20:00:41 +0000
commit12e856c26d690c02cc05a2e945b49e2df538307a (patch)
treecbb1cf43fa0dcbb477775b3ade47e4b16e057b5e /gst/avi/gstavidemux.c
parent396a5c812901cfb1e16a8b4f55f122e229293b98 (diff)
Riff, EBML, fourcc etc. work. Not fully finished, but better than what we used to have and definately worth a first b...
Original commit message from CVS: Riff, EBML, fourcc etc. work. Not fully finished, but better than what we used to have and definately worth a first broad testing. I've revived rifflib. Rifflib used to be a bytestream-for-riff, which just dup'ed bytestream. I've rewritten rifflib to be a modern riff- chunk parser that uses bytestream fully, plus adds some extra functions so that riff file parsing becomes extremely easy. It also contains some small usability functions for strh/strf and metadata parsing. Note that it doesn't use the new tagging yet, that's a TODO. Avidemux has been rewritten to use this. I think we all agreed that avidemux was pretty much a big mess, which is because it used all sort of bytestream magic all around the place. It was just ugly. This is a lot nicer, very complete and safe. I think this is far more robust than what the old avidemux could ever have been. Of course, it might contain bugs, please let me know. EBML writing has also been implemented. This is useful for matroska. I'm intending to modify avidemux (with a riffwriter) similarly. Maybe I'll change wavparse/-enc too to use rifflib. Lastly, several plugins have been modified to use rifflib's fourcc parsing instead of their own. this puts fourcc parsing in one central place, which should make it a lot simpler to add new fourccs. We might want to move this to its own lib instead of rifflib. Enjoy!
Diffstat (limited to 'gst/avi/gstavidemux.c')
-rw-r--r--gst/avi/gstavidemux.c2460
1 files changed, 992 insertions, 1468 deletions
diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c
index ad4531a0..5f19fce5 100644
--- a/gst/avi/gstavidemux.c
+++ b/gst/avi/gstavidemux.c
@@ -17,15 +17,15 @@
* Boston, MA 02111-1307, USA.
*/
-
-/* #define GST_DEBUG_ENABLED */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+
#include <string.h>
+#include "gst/riff/riff-media.h"
#include "gstavidemux.h"
-#include "gstavimux.h"
+#include "avi-ids.h"
GST_DEBUG_CATEGORY_STATIC (avidemux_debug);
#define GST_CAT_DEFAULT avidemux_debug
@@ -38,8 +38,6 @@ enum {
enum {
ARG_0,
- ARG_BITRATE,
- ARG_METADATA,
ARG_STREAMINFO,
/* FILL ME */
};
@@ -55,10 +53,11 @@ GST_PAD_TEMPLATE_FACTORY (sink_templ,
)
);
-static void gst_avi_demux_base_init (gpointer g_class);
+static void gst_avi_demux_base_init (GstAviDemuxClass *klass);
static void gst_avi_demux_class_init (GstAviDemuxClass *klass);
-static void gst_avi_demux_init (GstAviDemux *avi_demux);
+static void gst_avi_demux_init (GstAviDemux *avi);
+static void gst_avi_demux_reset (GstAviDemux *avi);
static void gst_avi_demux_loop (GstElement *element);
static gboolean gst_avi_demux_send_event (GstElement *element,
@@ -90,15 +89,7 @@ static void gst_avi_demux_get_property (GObject *object,
GValue *value,
GParamSpec *pspec);
-static GstCaps * gst_avi_demux_audio_caps (guint16 codec_id,
- gst_riff_strf_auds *strf, GstAviDemux *avi_demux);
-static GstCaps * gst_avi_demux_video_caps (guint32 codec_fcc,
- gst_riff_strh *strh, gst_riff_strf_vids *strf,
- GstAviDemux *avi_demux);
-static GstCaps * gst_avi_demux_iavs_caps (void);
-
-static GstPadTemplate *videosrctempl, *audiosrctempl;
-static GstElementClass *parent_class = NULL;
+static GstRiffReadClass *parent_class = NULL;
/*static guint gst_avi_demux_signals[LAST_SIGNAL] = { 0 }; */
GType
@@ -108,88 +99,60 @@ gst_avi_demux_get_type(void)
if (!avi_demux_type) {
static const GTypeInfo avi_demux_info = {
- sizeof(GstAviDemuxClass),
- gst_avi_demux_base_init,
+ sizeof (GstAviDemuxClass),
+ (GBaseInitFunc) gst_avi_demux_base_init,
NULL,
- (GClassInitFunc)gst_avi_demux_class_init,
+ (GClassInitFunc) gst_avi_demux_class_init,
NULL,
NULL,
- sizeof(GstAviDemux),
+ sizeof (GstAviDemux),
0,
- (GInstanceInitFunc)gst_avi_demux_init,
+ (GInstanceInitFunc) gst_avi_demux_init,
};
- avi_demux_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviDemux", &avi_demux_info, 0);
+
+ avi_demux_type =
+ g_type_register_static (GST_TYPE_RIFF_READ,
+ "GstAviDemux",
+ &avi_demux_info, 0);
}
+
return avi_demux_type;
}
static void
-gst_avi_demux_base_init (gpointer g_class)
+gst_avi_demux_base_init (GstAviDemuxClass *klass)
{
static GstElementDetails gst_avi_demux_details = GST_ELEMENT_DETAILS (
"Avi demuxer",
"Codec/Demuxer",
"Demultiplex an avi file into audio and video",
"Erik Walthinsen <omega@cse.ogi.edu>\n"
- "Wim Taymans <wim.taymans@chello.be>"
+ "Wim Taymans <wim.taymans@chello.be>\n"
+ "Ronald Bultje <rbultje@ronald.bitfreak.net>"
);
- static guint32 vid_list[] = {
- GST_MAKE_FOURCC('I','4','2','0'),
- GST_MAKE_FOURCC('Y','U','Y','2'),
- GST_MAKE_FOURCC('M','J','P','G'),
- GST_MAKE_FOURCC('D','V','S','D'),
- GST_MAKE_FOURCC('W','M','V','1'),
- GST_MAKE_FOURCC('W','M','V','2'),
- GST_MAKE_FOURCC('M','P','G','4'),
- GST_MAKE_FOURCC('M','P','4','2'),
- GST_MAKE_FOURCC('M','P','4','3'),
- GST_MAKE_FOURCC('H','F','Y','U'),
- GST_MAKE_FOURCC('D','I','V','3'),
- GST_MAKE_FOURCC('M','P','E','G'),
- GST_MAKE_FOURCC('H','2','6','3'),
- GST_MAKE_FOURCC('D','I','V','X'),
- GST_MAKE_FOURCC('X','V','I','D'),
- GST_MAKE_FOURCC('3','I','V','1'),
- 0 /* end */
- };
- static gint aud_list[] = {
- GST_RIFF_WAVE_FORMAT_MPEGL3,
- GST_RIFF_WAVE_FORMAT_MPEGL12,
- GST_RIFF_WAVE_FORMAT_PCM,
- GST_RIFF_WAVE_FORMAT_VORBIS1,
- GST_RIFF_WAVE_FORMAT_A52,
- GST_RIFF_WAVE_FORMAT_ALAW,
- GST_RIFF_WAVE_FORMAT_MULAW,
- -1 /* end */
- };
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- gint i = 0;
- GstCaps *audcaps = NULL, *vidcaps = NULL, *temp;
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+ GstPadTemplate *videosrctempl, *audiosrctempl;
+ GstCaps *audcaps, *vidcaps;
- for (i = 0; aud_list[i] != -1; i++) {
- temp = gst_avi_demux_audio_caps (aud_list[i], NULL, NULL);
- audcaps = gst_caps_append (audcaps, temp);
- }
+ audcaps = gst_riff_create_audio_template_caps ();
audiosrctempl = gst_pad_template_new ("audio_%02d",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
audcaps, NULL);
- for (i = 0; vid_list[i] != 0; i++) {
- temp = gst_avi_demux_video_caps (vid_list[i], NULL, NULL, NULL);
- vidcaps = gst_caps_append (vidcaps, temp);
- }
- vidcaps = gst_caps_append (vidcaps,
- gst_avi_demux_iavs_caps ());
+
+ vidcaps = gst_caps_append (
+ gst_riff_create_video_template_caps (),
+ gst_riff_create_iavs_template_caps ());
videosrctempl = gst_pad_template_new ("video_%02d",
GST_PAD_SRC,
GST_PAD_SOMETIMES,
vidcaps, NULL);
+
gst_element_class_add_pad_template (element_class, audiosrctempl);
gst_element_class_add_pad_template (element_class, videosrctempl);
gst_element_class_add_pad_template (element_class,
GST_PAD_TEMPLATE_GET (sink_templ));
gst_element_class_set_details (element_class, &gst_avi_demux_details);
-
}
static void
@@ -201,17 +164,14 @@ gst_avi_demux_class_init (GstAviDemuxClass *klass)
gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
- g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_BITRATE,
- g_param_spec_long ("bitrate","bitrate","bitrate",
- G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); /* CHECKME */
- g_object_class_install_property (gobject_class, ARG_METADATA,
- g_param_spec_boxed ("metadata", "Metadata", "Metadata",
- GST_TYPE_CAPS, G_PARAM_READABLE));
g_object_class_install_property (gobject_class, ARG_STREAMINFO,
g_param_spec_boxed ("streaminfo", "Streaminfo", "Streaminfo",
GST_TYPE_CAPS, G_PARAM_READABLE));
- parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+ GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux",
+ 0, "Demuxer for AVI streams");
+
+ parent_class = g_type_class_ref (GST_TYPE_RIFF_READ);
gobject_class->get_property = gst_avi_demux_get_property;
@@ -220,295 +180,57 @@ gst_avi_demux_class_init (GstAviDemuxClass *klass)
}
static void
-gst_avi_demux_init (GstAviDemux *avi_demux)
+gst_avi_demux_init (GstAviDemux *avi)
{
- GST_FLAG_SET (avi_demux, GST_ELEMENT_EVENT_AWARE);
-
- avi_demux->sinkpad = gst_pad_new_from_template (
- GST_PAD_TEMPLATE_GET (sink_templ), "sink");
- gst_element_add_pad (GST_ELEMENT (avi_demux), avi_demux->sinkpad);
+ GST_FLAG_SET (avi, GST_ELEMENT_EVENT_AWARE);
- gst_element_set_loop_function (GST_ELEMENT (avi_demux), gst_avi_demux_loop);
-}
+ avi->sinkpad = gst_pad_new_from_template (
+ GST_PAD_TEMPLATE_GET (sink_templ), "sink");
+ gst_element_add_pad (GST_ELEMENT (avi), avi->sinkpad);
+ GST_RIFF_READ (avi)->sinkpad = avi->sinkpad;
-static gboolean
-gst_avi_demux_avih (GstAviDemux *avi_demux)
-{
- gst_riff_avih *avih;
- guint8 *avihdata;
- GstByteStream *bs = avi_demux->bs;
- guint32 got_bytes;
-
- got_bytes = gst_bytestream_peek_bytes (bs, &avihdata, sizeof (gst_riff_avih));
- avih = (gst_riff_avih *) avihdata;
-
- if (got_bytes == sizeof (gst_riff_avih)) {
- avi_demux->avih.us_frame = GUINT32_FROM_LE (avih->us_frame);
- avi_demux->avih.max_bps = GUINT32_FROM_LE (avih->max_bps);
- avi_demux->avih.pad_gran = GUINT32_FROM_LE (avih->pad_gran);
- avi_demux->avih.flags = GUINT32_FROM_LE (avih->flags);
- avi_demux->avih.tot_frames = GUINT32_FROM_LE (avih->tot_frames);
- avi_demux->avih.init_frames = GUINT32_FROM_LE (avih->init_frames);
- avi_demux->avih.streams = GUINT32_FROM_LE (avih->streams);
- avi_demux->avih.bufsize = GUINT32_FROM_LE (avih->bufsize);
- avi_demux->avih.width = GUINT32_FROM_LE (avih->width);
- avi_demux->avih.height = GUINT32_FROM_LE (avih->height);
- avi_demux->avih.scale = GUINT32_FROM_LE (avih->scale);
- avi_demux->avih.rate = GUINT32_FROM_LE (avih->rate);
- avi_demux->avih.start = GUINT32_FROM_LE (avih->start);
- avi_demux->avih.length = GUINT32_FROM_LE (avih->length);
-
- GST_INFO ( "gst_avi_demux: avih tag found");
- GST_INFO ( "gst_avi_demux: us_frame %d", avi_demux->avih.us_frame);
- GST_INFO ( "gst_avi_demux: max_bps %d", avi_demux->avih.max_bps);
- GST_INFO ( "gst_avi_demux: pad_gran %d", avi_demux->avih.pad_gran);
- GST_INFO ( "gst_avi_demux: flags 0x%08x", avi_demux->avih.flags);
- GST_INFO ( "gst_avi_demux: tot_frames %d", avi_demux->avih.tot_frames);
- GST_INFO ( "gst_avi_demux: init_frames %d", avi_demux->avih.init_frames);
- GST_INFO ( "gst_avi_demux: streams %d", avi_demux->avih.streams);
- GST_INFO ( "gst_avi_demux: bufsize %d", avi_demux->avih.bufsize);
- GST_INFO ( "gst_avi_demux: width %d", avi_demux->avih.width);
- GST_INFO ( "gst_avi_demux: height %d", avi_demux->avih.height);
- GST_INFO ( "gst_avi_demux: scale %d", avi_demux->avih.scale);
- GST_INFO ( "gst_avi_demux: rate %d", avi_demux->avih.rate);
- GST_INFO ( "gst_avi_demux: start %d", avi_demux->avih.start);
- GST_INFO ( "gst_avi_demux: length %d", avi_demux->avih.length);
-
- return TRUE;
- }
- return FALSE;
-}
-
-static gboolean
-gst_avi_demux_strh (GstAviDemux *avi_demux)
-{
- gst_riff_strh *strh;
- guint8 *strhdata;
- GstByteStream *bs = avi_demux->bs;
- guint32 got_bytes;
-
- got_bytes = gst_bytestream_peek_bytes (bs, &strhdata, sizeof (gst_riff_strh));
- strh = (gst_riff_strh *) strhdata;
-
- if (got_bytes == sizeof (gst_riff_strh)) {
- avi_stream_context *target;
-
- avi_demux->fcc_type = GUINT32_FROM_LE (strh->type);
-
- target = &avi_demux->stream[avi_demux->num_streams];
-
- target->num = avi_demux->num_streams;
-
- target->strh.type = avi_demux->fcc_type;
- target->strh.fcc_handler = GUINT32_FROM_LE (strh->fcc_handler);
- target->strh.flags = GUINT32_FROM_LE (strh->flags);
- target->strh.priority = GUINT32_FROM_LE (strh->priority);
- target->strh.init_frames = GUINT32_FROM_LE (strh->init_frames);
- target->strh.scale = GUINT32_FROM_LE (strh->scale);
- target->strh.rate = GUINT32_FROM_LE (strh->rate);
- target->strh.start = GUINT32_FROM_LE (strh->start);
- target->strh.length = GUINT32_FROM_LE (strh->length);
- target->strh.bufsize = GUINT32_FROM_LE (strh->bufsize);
- target->strh.quality = GUINT32_FROM_LE (strh->quality);
- target->strh.samplesize = GUINT32_FROM_LE (strh->samplesize);
-
- if (!target->strh.scale)
- target->strh.scale = 1; /* avoid division by zero */
- if (!target->strh.rate)
- target->strh.rate = 1; /* avoid division by zero */
-
- GST_INFO ( "gst_avi_demux: strh tag found");
- GST_INFO ( "gst_avi_demux: type 0x%08x (%s)",
- target->strh.type, gst_riff_id_to_fourcc (strh->type));
- GST_INFO ( "gst_avi_demux: fcc_handler 0x%08x (%s)",
- target->strh.fcc_handler, gst_riff_id_to_fourcc (strh->fcc_handler));
- GST_INFO ( "gst_avi_demux: flags 0x%08x", strh->flags);
- GST_INFO ( "gst_avi_demux: priority %d", target->strh.priority);
- GST_INFO ( "gst_avi_demux: init_frames %d", target->strh.init_frames);
- GST_INFO ( "gst_avi_demux: scale %d", target->strh.scale);
- GST_INFO ( "gst_avi_demux: rate %d", target->strh.rate);
- GST_INFO ( "gst_avi_demux: start %d", target->strh.start);
- GST_INFO ( "gst_avi_demux: length %d", target->strh.length);
- GST_INFO ( "gst_avi_demux: bufsize %d", target->strh.bufsize);
- GST_INFO ( "gst_avi_demux: quality %d", target->strh.quality);
- GST_INFO ( "gst_avi_demux: samplesize %d", target->strh.samplesize);
-
- target->delay = 0LL;
- target->total_bytes = 0LL;
- target->total_frames = 0;
- target->end_pos = -1;
- target->current_frame = 0;
- target->current_byte = 0;
- target->need_flush = FALSE;
- target->skip = 0;
-
- avi_demux->avih.bufsize = MAX (avi_demux->avih.bufsize, target->strh.bufsize);
-
- return TRUE;
- }
- return FALSE;
-}
-
-static void
-gst_avi_demux_dmlh (GstAviDemux *avi_demux)
-{
- gst_riff_dmlh *dmlh;
- guint8 *dmlhdata;
- GstByteStream *bs = avi_demux->bs;
- guint32 got_bytes;
+ gst_element_set_loop_function (GST_ELEMENT (avi), gst_avi_demux_loop);
+ gst_avi_demux_reset (avi);
- got_bytes = gst_bytestream_peek_bytes (bs, &dmlhdata, sizeof (gst_riff_dmlh));
- dmlh = (gst_riff_dmlh *) dmlhdata;
+ avi->streaminfo = NULL;
+ avi->index_entries = NULL;
+ memset (&avi->stream, 0, sizeof (avi->stream));
}
static void
-gst_avi_demux_strn (GstAviDemux *avi_demux, gint len)
+gst_avi_demux_reset (GstAviDemux *avi)
{
- gchar *name;
- guint8 *namedata;
- GstByteStream *bs = avi_demux->bs;
- guint32 got_bytes;
-
- got_bytes = gst_bytestream_peek_bytes (bs, &namedata, len);
- name = (gchar *) namedata;
- if (got_bytes != len)
- return;
-
- GST_DEBUG ("Stream name: \"%s\"", name);
-}
-
-static void
-gst_avi_demux_metadata (GstAviDemux *avi_demux, gint len)
-{
- guint32 got_bytes;
- GstByteStream *bs = avi_demux->bs;
- gst_riff_chunk *temp_chunk, chunk;
- guint8 *tempdata;
- gchar *name, *type;
- GstProps *props;
- GstPropsEntry *entry;
-
- props = gst_props_empty_new ();
-
- while (len > 0) {
- got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
- temp_chunk = (gst_riff_chunk *) tempdata;
-
- /* fixup for our big endian friends */
- chunk.id = GUINT32_FROM_LE (temp_chunk->id);
- chunk.size = GUINT32_FROM_LE (temp_chunk->size);
+ gint i;
- gst_bytestream_flush (bs, sizeof (gst_riff_chunk));
- if (got_bytes != sizeof (gst_riff_chunk))
- return;
- len -= sizeof (gst_riff_chunk);
+ for (i = 0; i < avi->num_streams; i++) {
+ g_free (avi->stream[i].strh);
+ gst_element_remove_pad (GST_ELEMENT (avi), avi->stream[i].pad);
+ }
+ memset (&avi->stream, 0, sizeof (avi->stream));
- /* don't care about empty entries - move on */
- if (chunk.size == 0)
- continue;
+ avi->num_streams = 0;
+ avi->num_v_streams = 0;
+ avi->num_a_streams = 0;
- got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, chunk.size);
- name = (gchar *) tempdata;
- gst_bytestream_flush (bs, (chunk.size + 1) & ~1);
- if (got_bytes != chunk.size)
- return;
- len -= ((chunk.size + 1) & ~1);
-
- /* we now have an info string in 'name' of type 'chunk.id' - find 'type' */
- switch (chunk.id) {
- case GST_RIFF_INFO_IARL:
- type = "Location";
- break;
- case GST_RIFF_INFO_IART:
- type = "Artist";
- break;
- case GST_RIFF_INFO_ICMS:
- type = "Commissioner";
- break;
- case GST_RIFF_INFO_ICMT:
- type = "Comment";
- break;
- case GST_RIFF_INFO_ICOP:
- type = "Copyright";
- break;
- case GST_RIFF_INFO_ICRD:
- type = "Creation Date";
- break;
- case GST_RIFF_INFO_ICRP:
- type = "Cropped";
- break;
- case GST_RIFF_INFO_IDIM:
- type = "Dimensions";
- break;
- case GST_RIFF_INFO_IDPI:
- type = "Dots per Inch";
- break;
- case GST_RIFF_INFO_IENG:
- type = "Engineer";
- break;
- case GST_RIFF_INFO_IGNR:
- type = "Genre";
- break;
- case GST_RIFF_INFO_IKEY:
- type = "Keywords";
- break;
- case GST_RIFF_INFO_ILGT:
- type = "Lightness";
- break;
- case GST_RIFF_INFO_IMED:
- type = "Medium";
- break;
- case GST_RIFF_INFO_INAM:
- type = "Title"; /* "Name" */
- break;
- case GST_RIFF_INFO_IPLT:
- type = "Palette";
- break;
- case GST_RIFF_INFO_IPRD:
- type = "Product";
- break;
- case GST_RIFF_INFO_ISBJ:
- type = "Subject";
- break;
- case GST_RIFF_INFO_ISFT:
- type = "Encoder"; /* "Software" */
- break;
- case GST_RIFF_INFO_ISHP:
- type = "Sharpness";
- break;
- case GST_RIFF_INFO_ISRC:
- type = "Source";
- break;
- case GST_RIFF_INFO_ISRF:
- type = "Source Form";
- break;
- case GST_RIFF_INFO_ITCH:
- type = "Technician";
- break;
- default:
- type = NULL;
- break;
- }
+ avi->state = GST_AVI_DEMUX_START;
+ avi->level_up = 0;
- if (type) {
- /* create props entry */
- entry = gst_props_entry_new (type, GST_PROPS_STRING (name));
- gst_props_add_entry (props, entry);
- }
+ if (avi->index_entries) {
+ g_free (avi->index_entries);
+ avi->index_entries = NULL;
}
+ avi->index_size = 0;
- gst_props_debug(props);
+ avi->num_frames = 0;
+ avi->us_per_frame = 0;
- gst_caps_replace_sink (&avi_demux->metadata,
- gst_caps_new("avi_metadata",
- "application/x-gst-metadata",
- props));
+ avi->seek_offset = (guint64) -1;
- g_object_notify(G_OBJECT(avi_demux), "metadata");
+ gst_caps_replace (&avi->streaminfo, NULL);
}
static void
-gst_avi_demux_streaminfo (GstAviDemux *avi_demux)
+gst_avi_demux_streaminfo (GstAviDemux *avi)
{
GstProps *props;
@@ -516,781 +238,110 @@ gst_avi_demux_streaminfo (GstAviDemux *avi_demux)
/* compression formats are added later - a bit hacky */
- gst_caps_replace_sink (&avi_demux->streaminfo,
- gst_caps_new("avi_streaminfo",
- "application/x-gst-streaminfo",
- props));
+ gst_caps_replace_sink (&avi->streaminfo,
+ gst_caps_new ("avi_streaminfo",
+ "application/x-gst-streaminfo",
+ props));
- /*g_object_notify(G_OBJECT(avi_demux), "streaminfo");*/
+ /*g_object_notify(G_OBJECT(avi), "streaminfo");*/
}
-/* video/audio pad/caps stuff */
-
-#ifdef G_HAVE_ISO_VARARGS
-
-#define GST_AVI_VID_CAPS_NEW(name, mimetype, ...) \
- (strf != NULL) ? \
- GST_CAPS_NEW (name, \
- mimetype, \
- "width", GST_PROPS_INT (width), \
- "height", GST_PROPS_INT (height), \
- "framerate", GST_PROPS_FLOAT (framerate), \
- __VA_ARGS__) \
- : \
- GST_CAPS_NEW (name, \
- mimetype, \
- "width", GST_PROPS_INT_RANGE (16, 4096), \
- "height", GST_PROPS_INT_RANGE (16, 4096), \
- "framerate", GST_PROPS_FLOAT_RANGE (0., G_MAXFLOAT), \
- __VA_ARGS__)
-
-#elif defined(G_HAVE_GNUC_VARARGS)
-
-#define GST_AVI_VID_CAPS_NEW(name, mimetype, props...) \
- (strf != NULL) ? \
- GST_CAPS_NEW (name, \
- mimetype, \
- "width", GST_PROPS_INT (width), \
- "height", GST_PROPS_INT (height), \
- "framerate", GST_PROPS_FLOAT (framerate), \
- ##props) \
- : \
- GST_CAPS_NEW (name, \
- mimetype, \
- "width", GST_PROPS_INT_RANGE (16, 4096), \
- "height", GST_PROPS_INT_RANGE (16, 4096), \
- "framerate", GST_PROPS_FLOAT_RANGE (0., G_MAXFLOAT), \
- ##props)
-#endif
-
-static GstCaps *
-gst_avi_demux_video_caps (guint32 codec_fcc,
- gst_riff_strh *strh,
- gst_riff_strf_vids *strf,
- GstAviDemux *avi_demux)
+static gst_avi_index_entry *
+gst_avi_demux_index_next (GstAviDemux *avi,
+ gint stream_nr,
+ gint start,
+ guint32 flags)
{
- GstCaps *caps = NULL;
- gchar *codecname = NULL;
- gint width = -1, height = -1;
- gdouble framerate = 0.;
-
- if (strf != NULL) {
- width = GUINT32_FROM_LE (strf->width);
- height = GUINT32_FROM_LE (strf->height);
- }
- if (strh != NULL) {
- framerate = 1. * GUINT32_FROM_LE (strh->rate) /
- GUINT32_FROM_LE (strh->scale); /* fps */
- }
-
- switch (codec_fcc) {
- case GST_MAKE_FOURCC('I','4','2','0'):
- case GST_MAKE_FOURCC('Y','U','Y','2'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src_raw",
- "video/x-raw-yuv",
- "format", GST_PROPS_FOURCC (codec_fcc)
- );
- codecname = g_strdup_printf("Raw Video (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('M','J','P','G'): /* YUY2 MJPEG */
- case GST_MAKE_FOURCC('J','P','E','G'): /* generic (mostly RGB) MJPEG */
- case GST_MAKE_FOURCC('P','I','X','L'): /* Miro/Pinnacle fourccs */
- case GST_MAKE_FOURCC('V','I','X','L'): /* Miro/Pinnacle fourccs */
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src_jpeg",
- "video/x-jpeg",
- NULL
- );
- codecname = g_strdup_printf("Motion-JPEG (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('H','F','Y','U'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src_hfyu",
- "video/x-huffyuv",
- NULL
- );
- codecname = g_strdup_printf("HuffYUV (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('M','P','E','G'):
- case GST_MAKE_FOURCC('M','P','G','I'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src_mpeg",
- "video/mpeg",
- "systemstream", GST_PROPS_BOOLEAN (FALSE),
- "mpegversion", GST_PROPS_BOOLEAN (1)
- );
- codecname = g_strdup_printf("MPEG-1 (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('H','2','6','3'):
- case GST_MAKE_FOURCC('i','2','6','3'):
- case GST_MAKE_FOURCC('L','2','6','3'):
- case GST_MAKE_FOURCC('M','2','6','3'):
- case GST_MAKE_FOURCC('V','D','O','W'):
- case GST_MAKE_FOURCC('V','I','V','O'):
- case GST_MAKE_FOURCC('x','2','6','3'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src_263",
- "video/x-h263",
- NULL
- );
- codecname = g_strdup_printf("H263-compatible (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('D','I','V','3'):
- case GST_MAKE_FOURCC('D','I','V','4'):
- case GST_MAKE_FOURCC('D','I','V','5'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src_divx3",
- "video/x-divx",
- "divxversion", GST_PROPS_INT(3)
- );
- codecname = g_strdup_printf("DivX-3.x (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('d','i','v','x'):
- case GST_MAKE_FOURCC('D','I','V','X'):
- case GST_MAKE_FOURCC('D','X','5','0'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src_divx5",
- "video/x-divx",
- "divxversion", GST_PROPS_INT(5)
- );
- codecname = g_strdup_printf("DivX 4.x/5.x (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('X','V','I','D'):
- case GST_MAKE_FOURCC('x','v','i','d'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src",
- "video/x-xvid",
- NULL
- );
- codecname = g_strdup_printf("XviD (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('M','P','G','4'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src",
- "video/x-msmpeg",
- "msmpegversion", GST_PROPS_INT (41)
- );
- codecname = g_strdup_printf("MS MPEG-4.1 (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('M','P','4','2'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src",
- "video/x-msmpeg",
- "msmpegversion", GST_PROPS_INT (42)
- );
- codecname = g_strdup_printf("MS MPEG-4.2 (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('M','P','4','3'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src",
- "video/x-msmpeg",
- "msmpegversion", GST_PROPS_INT (43)
- );
- codecname = g_strdup_printf("MS MPEG-4.3 (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('3','I','V','1'):
- case GST_MAKE_FOURCC('3','I','V','2'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src_3ivx",
- "video/x-3ivx",
- NULL
- );
- codecname = g_strdup_printf("3ivX (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('D','V','S','D'):
- case GST_MAKE_FOURCC('d','v','s','d'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src",
- "video/x-dv",
- "systemstream", GST_PROPS_BOOLEAN (FALSE)
- );
- codecname = g_strdup_printf("Digital Video type 2 (" GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('W','M','V','1'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src_wmv1",
- "video/x-wmv",
- "wmvversion", GST_PROPS_INT (1)
- );
- codecname = g_strdup_printf("Windows Media Format 1 ("
- GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- case GST_MAKE_FOURCC('W','M','V','2'):
- caps = GST_AVI_VID_CAPS_NEW (
- "avidemux_video_src_wmv2",
- "video/x-wmv",
- "wmvversion", GST_PROPS_INT (2)
- );
- codecname = g_strdup_printf("Windows Media Format 2 ("
- GST_FOURCC_FORMAT ")",
- GST_FOURCC_ARGS(codec_fcc));
- break;
-
- default:
- g_warning ("avidemux: unkown video format " GST_FOURCC_FORMAT,
- GST_FOURCC_ARGS(codec_fcc));
- break;
- }
-
- /* set video codec info on streaminfo caps */
- if (avi_demux != NULL && codecname != NULL) {
- GstPropsEntry *entry;
- entry = gst_props_entry_new("videocodec",
- GST_PROPS_STRING(codecname));
- gst_props_add_entry(avi_demux->streaminfo->properties, entry);
- }
- if (codecname != NULL) {
- g_free(codecname);
- }
-
- return caps;
-}
-
-static void
-gst_avi_demux_strf_vids (GstAviDemux *avi_demux)
-{
- gst_riff_strf_vids *strf;
- gst_riff_strh *strh;
- guint8 *strfdata;
- GstPad *srcpad;
- GstCaps *caps = NULL;
- avi_stream_context *stream;
- GstByteStream *bs = avi_demux->bs;
- guint32 got_bytes;
- gchar *padname;
-
- got_bytes = gst_bytestream_peek_bytes (bs, &strfdata, sizeof (gst_riff_strf_vids));
- strf = (gst_riff_strf_vids *) strfdata;
- if (got_bytes != sizeof (gst_riff_strf_vids))
- return;
-
- padname = g_strdup_printf ("video_%02d", avi_demux->num_v_streams);
- srcpad = gst_pad_new_from_template (videosrctempl, padname);
- g_free (padname);
-
- /* let's try some gstreamer-like mime-type caps */
- strh = &avi_demux->stream[avi_demux->num_streams].strh;
- caps = gst_avi_demux_video_caps (GUINT32_FROM_LE(strf->compression),
- strh, strf, avi_demux);
-
- if (caps != NULL) {
- gst_pad_try_set_caps (srcpad, caps);
- }
- gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
- gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
- gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
- gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
- gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
- gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
-
- stream = &avi_demux->stream[avi_demux->num_streams];
- stream->pad = srcpad;
- gst_pad_set_element_private (srcpad, stream);
- avi_demux->num_streams++;
- avi_demux->num_v_streams++;
-
- gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
-}
-
-#ifdef G_HAVE_ISO_VARARGS
-
-#define GST_AVI_AUD_CAPS_NEW(name, mimetype, ...) \
- (strf != NULL) ? \
- GST_CAPS_NEW (name, \
- mimetype, \
- "rate", GST_PROPS_INT (rate), \
- "channels", GST_PROPS_INT (channels), \
- __VA_ARGS__) \
- : \
- GST_CAPS_NEW (name, \
- mimetype, \
- "rate", GST_PROPS_INT_RANGE (8000, 96000), \
- "channels", GST_PROPS_INT_RANGE (1, 2), \
- __VA_ARGS__)
-
-
-#elif defined(G_HAVE_GNUC_VARARGS)
-
-#define GST_AVI_AUD_CAPS_NEW(name, mimetype, props...) \
- (strf != NULL) ? \
- GST_CAPS_NEW (name, \
- mimetype, \
- "rate", GST_PROPS_INT (rate), \
- "channels", GST_PROPS_INT (channels), \
- ##props) \
- : \
- GST_CAPS_NEW (name, \
- mimetype, \
- "rate", GST_PROPS_INT_RANGE (8000, 96000), \
- "channels", GST_PROPS_INT_RANGE (1, 2), \
- ##props)
-#endif
-
-static GstCaps *
-gst_avi_demux_audio_caps (guint16 codec_id,
- gst_riff_strf_auds *strf,
- GstAviDemux *avi_demux)
-{
- GstCaps *caps = NULL;
- gchar *codecname = NULL;
- gint rate = -1, channels = -1;
-
- if (strf != NULL) {
- rate = GUINT32_FROM_LE (strf->rate);
- channels = GUINT16_FROM_LE (strf->channels);
- }
+ gint i;
+ gst_avi_index_entry *entry = NULL;
- switch (codec_id) {
- case GST_RIFF_WAVE_FORMAT_MPEGL3: /* mp3 */
- caps = GST_AVI_AUD_CAPS_NEW ("avi_demux_audio_src_mp3",
- "audio/mpeg",
- "layer", GST_PROPS_INT (3));
- codecname = g_strdup_printf("MPEG-1 layer 3 audio (0x%04x)",
- codec_id);
- break;
+ for (i = start; i < avi->index_size; i++) {
+ entry = &avi->index_entries[i];
- case GST_RIFF_WAVE_FORMAT_MPEGL12: /* mp1 or mp2 */
- caps = GST_AVI_AUD_CAPS_NEW ("avi_demux_audio_src_mp12",
- "audio/mpeg",
- "layer", GST_PROPS_INT (2));
- codecname = g_strdup_printf("MPEG-1 layer 1/2 audio (0x%04x)",
- codec_id);
+ if (entry->stream_nr == stream_nr && (entry->flags & flags) == flags) {
break;
-
- case GST_RIFF_WAVE_FORMAT_PCM: /* PCM/wav */ {
- GstPropsEntry *width = NULL, *depth = NULL, *signedness = NULL;
-
- if (strf != NULL) {
- gint ba = GUINT16_FROM_LE (strf->blockalign);
- gint ch = GUINT16_FROM_LE (strf->channels);
- gint ws = GUINT16_FROM_LE (strf->size);
-
- width = gst_props_entry_new ("width",
- GST_PROPS_INT (ba * 8 / ch));
- depth = gst_props_entry_new ("depth",
- GST_PROPS_INT (ws));
- signedness = gst_props_entry_new ("signed",
- GST_PROPS_BOOLEAN (ws != 8));
- } else {
- signedness = gst_props_entry_new ("signed",
- GST_PROPS_LIST (
- GST_PROPS_BOOLEAN (TRUE),
- GST_PROPS_BOOLEAN (FALSE)));
- width = gst_props_entry_new ("width",
- GST_PROPS_LIST (
- GST_PROPS_INT (8),
- GST_PROPS_INT (16)));
- depth = gst_props_entry_new ("depth",
- GST_PROPS_LIST (
- GST_PROPS_INT (8),
- GST_PROPS_INT (16)));
- }
-
- caps = GST_AVI_AUD_CAPS_NEW ("avi_demux_audio_src_pcm",
- "audio/x-raw-int",
- "endianness",
- GST_PROPS_INT (G_LITTLE_ENDIAN));
- gst_props_add_entry (caps->properties, width);
- gst_props_add_entry (caps->properties, depth);
- gst_props_add_entry (caps->properties, signedness);
-
- codecname = g_strdup_printf("Raw PCM/WAV (0x%04x)",
- codec_id);
}
- break;
-
- case GST_RIFF_WAVE_FORMAT_MULAW:
- if (strf != NULL && strf->size != 8) {
- g_warning ("invalid depth (%d) of mulaw audio, overwriting.",
- strf->size);
- }
- caps = GST_AVI_AUD_CAPS_NEW ("avidemux_audio_src",
- "audio/x-mulaw",
- NULL);
- codecname = g_strdup_printf("A-law encoded (0x%04x)",
- codec_id);
- break;
-
- case GST_RIFF_WAVE_FORMAT_ALAW:
- if (strf != NULL && strf->size != 8) {
- g_warning ("invalid depth (%d) of alaw audio, overwriting.",
- strf->size);
- }
- caps = GST_AVI_AUD_CAPS_NEW ("avidemux_audio_src",
- "audio/x-alaw",
- NULL);
- codecname = g_strdup_printf("A-law encoded (0x%04x)",
- codec_id);
- break;
-
- case GST_RIFF_WAVE_FORMAT_VORBIS1: /* ogg/vorbis mode 1 */
- case GST_RIFF_WAVE_FORMAT_VORBIS2: /* ogg/vorbis mode 2 */
- case GST_RIFF_WAVE_FORMAT_VORBIS3: /* ogg/vorbis mode 3 */
- case GST_RIFF_WAVE_FORMAT_VORBIS1PLUS: /* ogg/vorbis mode 1+ */
- case GST_RIFF_WAVE_FORMAT_VORBIS2PLUS: /* ogg/vorbis mode 2+ */
- case GST_RIFF_WAVE_FORMAT_VORBIS3PLUS: /* ogg/vorbis mode 3+ */
- caps = GST_AVI_AUD_CAPS_NEW ("asf_demux_audio_src_vorbis",
- "audio/x-vorbis",
- NULL);
- codecname = g_strdup_printf("Vorbis (0x%04x)",
- codec_id);
- break;
-
- case GST_RIFF_WAVE_FORMAT_A52:
- caps = GST_AVI_AUD_CAPS_NEW ("asf_demux_audio_src_ac3",
- "audio/x-ac3",
- NULL);
- codecname = g_strdup_printf("AC-3 (0x%04x)",
- codec_id);
- break;
-
- default:
- g_warning ("avidemux: unkown audio format 0x%04x",
- codec_id);
- break;
- }
-
- if (avi_demux != NULL && codecname != NULL) {
- /* set audio codec in streaminfo */
- GstPropsEntry *entry;
- entry = gst_props_entry_new("audiocodec",
- GST_PROPS_STRING(codecname));
- gst_props_add_entry(avi_demux->streaminfo->properties, entry);
- }
- if (codecname != NULL) {
- g_free (codecname);
- }
-
- return caps;
-}
-
-static void
-gst_avi_demux_strf_auds (GstAviDemux *avi_demux)
-{
- gst_riff_strf_auds *strf;
- guint8 *strfdata;
- GstPad *srcpad;
- GstCaps *caps = NULL;
- avi_stream_context *stream;
- GstByteStream *bs = avi_demux->bs;
- guint32 got_bytes;
- gchar *padname;
-
- got_bytes = gst_bytestream_peek_bytes (bs, &strfdata, sizeof (gst_riff_strf_auds));
- strf = (gst_riff_strf_auds *) strfdata;
- if (got_bytes != sizeof (gst_riff_strf_auds))
- return;
-
- GST_INFO ( "gst_avi_demux: strf tag found in context auds");
- GST_INFO ( "gst_avi_demux: format %d", GUINT16_FROM_LE (strf->format));
- GST_INFO ( "gst_avi_demux: channels %d", GUINT16_FROM_LE (strf->channels));
- GST_INFO ( "gst_avi_demux: rate %d", GUINT32_FROM_LE (strf->rate));
- GST_INFO ( "gst_avi_demux: av_bps %d", GUINT32_FROM_LE (strf->av_bps));
- GST_INFO ( "gst_avi_demux: blockalign %d", GUINT16_FROM_LE (strf->blockalign));
- GST_INFO ( "gst_avi_demux: size %d", GUINT16_FROM_LE (strf->size));
-
- padname = g_strdup_printf ("audio_%02d",
- avi_demux->num_a_streams);
- srcpad = gst_pad_new_from_template (audiosrctempl, padname);
- g_free (padname);
-
- caps = gst_avi_demux_audio_caps (GUINT16_FROM_LE (strf->format),
- strf, avi_demux);
-
- if (caps != NULL) {
- gst_pad_try_set_caps(srcpad, caps);
}
- gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
- gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
- gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
- gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
- gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
- gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
-
- stream = &avi_demux->stream[avi_demux->num_streams];
- stream->pad = srcpad;
- gst_pad_set_element_private (srcpad, stream);
- avi_demux->num_streams++;
- avi_demux->num_a_streams++;
-
- gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
-}
-
-static GstCaps *
-gst_avi_demux_iavs_caps (void)
-{
- return GST_CAPS_NEW ("avi_type_dv",
- "video/x-dv",
- "systemstream", GST_PROPS_BOOLEAN (TRUE));
-}
-static void
-gst_avi_demux_strf_iavs (GstAviDemux *avi_demux)
-{
- gst_riff_strf_iavs *strf;
- guint8 *strfdata;
- GstPad *srcpad;
- GstCaps *caps = NULL;
- avi_stream_context *stream;
- GstByteStream *bs = avi_demux->bs;
- guint32 got_bytes;
- gchar *padname;
- GstPropsEntry *entry;
-
- got_bytes = gst_bytestream_peek_bytes (bs, &strfdata, sizeof (gst_riff_strf_iavs));
- strf = (gst_riff_strf_iavs *) strfdata;
- if (got_bytes != sizeof (gst_riff_strf_iavs))
- return;
-
- GST_INFO ( "gst_avi_demux: strf tag found in context iavs");
- GST_INFO ( "gst_avi_demux: DVAAuxSrc %08x", GUINT32_FROM_LE (strf->DVAAuxSrc));
- GST_INFO ( "gst_avi_demux: DVAAuxCtl %08x", GUINT32_FROM_LE (strf->DVAAuxCtl));
- GST_INFO ( "gst_avi_demux: DVAAuxSrc1 %08x", GUINT32_FROM_LE (strf->DVAAuxSrc1));
- GST_INFO ( "gst_avi_demux: DVAAuxCtl1 %08x", GUINT32_FROM_LE (strf->DVAAuxCtl1));
- GST_INFO ( "gst_avi_demux: DVVAuxSrc %08x", GUINT32_FROM_LE (strf->DVVAuxSrc));
- GST_INFO ( "gst_avi_demux: DVVAuxCtl %08x", GUINT32_FROM_LE (strf->DVVAuxCtl));
- GST_INFO ( "gst_avi_demux: DVReserved1 %08x", GUINT32_FROM_LE (strf->DVReserved1));
- GST_INFO ( "gst_avi_demux: DVReserved2 %08x", GUINT32_FROM_LE (strf->DVReserved2));
-
- padname = g_strdup_printf ("video_%02d",
- avi_demux->num_v_streams);
- srcpad = gst_pad_new_from_template (videosrctempl, padname);
- g_free (padname);
-
- caps = gst_avi_demux_iavs_caps ();
- entry = gst_props_entry_new("videocodec",
- GST_PROPS_STRING("Digital Video type 1"));
- gst_props_add_entry(avi_demux->streaminfo->properties, entry);
-
- if (caps != NULL) {
- gst_pad_try_set_caps(srcpad, caps);
- }
- gst_pad_set_formats_function (srcpad, gst_avi_demux_get_src_formats);
- gst_pad_set_event_mask_function (srcpad, gst_avi_demux_get_event_mask);
- gst_pad_set_event_function (srcpad, gst_avi_demux_handle_src_event);
- gst_pad_set_query_type_function (srcpad, gst_avi_demux_get_src_query_types);
- gst_pad_set_query_function (srcpad, gst_avi_demux_handle_src_query);
- gst_pad_set_convert_function (srcpad, gst_avi_demux_src_convert);
-
- stream = &avi_demux->stream[avi_demux->num_streams];
- stream->pad = srcpad;
- gst_pad_set_element_private (srcpad, stream);
- avi_demux->num_streams++;
- avi_demux->num_v_streams++;
-
- gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad);
-}
-
-static void
-gst_avi_debug_entry (const gchar *prefix, gst_avi_index_entry *entry)
-{
- GST_DEBUG ("%s: %05d %d %08llx %05d %14" G_GINT64_FORMAT " %08x %08x (%d) %08x",
- prefix, entry->index_nr, entry->stream_nr,
- (unsigned long long)entry->bytes_before,
- entry->frames_before, entry->ts, entry->flags, entry->offset,
- entry->offset, entry->size);
+ return entry;
}
-static void
-gst_avi_demux_parse_index (GstAviDemux *avi_demux,
- gulong filepos, gulong offset)
+static gst_avi_index_entry *
+gst_avi_demux_index_entry_for_time (GstAviDemux *avi,
+ gint stream_nr,
+ guint64 time,
+ guint32 flags)
{
- GstBuffer *buf;
- gulong index_size;
- guint32 got_bytes;
+ gst_avi_index_entry *entry = NULL, *last_entry = NULL;
gint i;
- gst_riff_index_entry *entry;
- guint32 id;
- if (!gst_bytestream_seek (avi_demux->bs, filepos + offset, GST_SEEK_METHOD_SET)) {
- GST_INFO ( "avidemux: could not seek to index");
- return;
- }
+ i = -1;
do {
- guint32 remaining;
- GstEvent *event;
-
- got_bytes = gst_bytestream_read (avi_demux->bs, &buf, 8);
- if (got_bytes == 8)
- break;
-
- gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
- gst_event_unref (event);
- } while (TRUE);
-
- if (GST_BUFFER_OFFSET (buf) != filepos + offset || GST_BUFFER_SIZE (buf) != 8) {
- GST_INFO ( "avidemux: could not get index, got %" G_GINT64_FORMAT " %d, expected %ld",
- GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf), filepos + offset);
- goto end;
- }
-
- id = GUINT32_FROM_LE (*(guint32 *)GST_BUFFER_DATA (buf));
-
- if (id != GST_RIFF_TAG_idx1) {
- GST_INFO ( "avidemux: no index found");
- goto end;
- }
-
- index_size = GUINT32_FROM_LE(*(guint32 *)(GST_BUFFER_DATA (buf) + 4));
- gst_buffer_unref (buf);
-
- gst_bytestream_size_hint (avi_demux->bs, index_size);
-
- got_bytes = gst_bytestream_read (avi_demux->bs, &buf, index_size);
- if (got_bytes < index_size) {
- GST_INFO ( "avidemux: error reading index");
- goto end;
- }
-
- avi_demux->index_size = index_size/sizeof(gst_riff_index_entry);
- GST_INFO ( "avidemux: index size %lu", avi_demux->index_size);
-
- avi_demux->index_entries = g_malloc (avi_demux->index_size * sizeof (gst_avi_index_entry));
-
- entry = (gst_riff_index_entry *) GST_BUFFER_DATA (buf);
-
- for (i = 0; i < avi_demux->index_size; i++) {
- avi_stream_context *stream;
- gint stream_nr;
- gst_avi_index_entry *target = &avi_demux->index_entries[i];
- GstFormat format;
- guint32 id;
-
- id = GUINT32_FROM_LE (entry[i].id);
- stream_nr = CHUNKID_TO_STREAMNR (id);
- if (stream_nr > avi_demux->num_streams || stream_nr < 0) {
- avi_demux->index_entries[i].stream_nr = -1;
- continue;
- }
-
- target->stream_nr = stream_nr;
- stream = &avi_demux->stream[stream_nr];
-
- target->index_nr = i;
- target->flags = GUINT32_FROM_LE (entry[i].flags);
- target->size = GUINT32_FROM_LE (entry[i].size);
- target->offset = GUINT32_FROM_LE (entry[i].offset);
-
- /* figure out if the index is 0 based or relative to the MOVI start */
- if (i == 0) {
- if (target->offset < filepos)
- avi_demux->index_offset = filepos - 4;
- else
- avi_demux->index_offset = 0;
- }
+ entry = gst_avi_demux_index_next (avi, stream_nr, i + 1, flags);
+ if (!entry)
+ return NULL;
- target->bytes_before = stream->total_bytes;
- target->frames_before = stream->total_frames;
+ i = entry->index_nr;
- format = GST_FORMAT_TIME;
- if (stream->strh.type == GST_RIFF_FCC_auds) {
- /* all audio frames are keyframes */
- target->flags |= GST_RIFF_IF_KEYFRAME;
- }
-
- /* constant rate stream */
- if (stream->strh.samplesize && stream->strh.type == GST_RIFF_FCC_auds) {
- gst_pad_convert (stream->pad, GST_FORMAT_BYTES, stream->total_bytes,
- &format, &target->ts);
- }
- /* VBR stream */
- else {
- gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT, stream->total_frames,
- &format, &target->ts);
+ if (entry->ts <= time) {
+ last_entry = entry;
}
- gst_avi_debug_entry ("index", target);
-
- stream->total_bytes += target->size;
- stream->total_frames++;
- }
- for (i = 0; i < avi_demux->num_streams; i++) {
- avi_stream_context *stream;
-
- stream = &avi_demux->stream[i];
- GST_DEBUG ("stream %i: %d frames, %" G_GINT64_FORMAT " bytes",
- i, stream->total_frames, stream->total_bytes);
- }
- gst_buffer_unref (buf);
+ } while (entry->ts <= time);
-end:
- GST_DEBUG ("index offset at %08lx", filepos);
-
- if (!gst_bytestream_seek (avi_demux->bs, filepos, GST_SEEK_METHOD_SET)) {
- GST_INFO ( "avidemux: could not seek back to movi");
- return;
- }
+ return last_entry;
}
-static gst_avi_index_entry*
-gst_avi_demux_index_next (GstAviDemux *avi_demux, gint stream_nr, gint start, guint32 flags)
+static gst_avi_index_entry *
+gst_avi_demux_index_entry_for_byte (GstAviDemux *avi,
+ gint stream_nr,
+ guint64 byte,
+ guint32 flags)
{
+ gst_avi_index_entry *entry = NULL, *last_entry = NULL;
gint i;
- gst_avi_index_entry *entry = NULL;
- for (i = start; i < avi_demux->index_size; i++) {
- entry = &avi_demux->index_entries[i];
+ i = -1;
+ do {
+ entry = gst_avi_demux_index_next (avi, stream_nr, i + 1, flags);
+ if (!entry)
+ return NULL;
- if (entry->stream_nr == stream_nr && (entry->flags & flags) == flags) {
- break;
+ i = entry->index_nr;
+
+ if (entry->bytes_before <= byte) {
+ last_entry = entry;
}
- }
+ } while (entry->bytes_before <= byte);
- return entry;
+ return last_entry;
}
-static gst_avi_index_entry*
-gst_avi_demux_index_entry_for_time (GstAviDemux *avi_demux, gint stream_nr, guint64 time, guint32 flags)
+static gst_avi_index_entry *
+gst_avi_demux_index_entry_for_frame (GstAviDemux *avi,
+ gint stream_nr,
+ guint32 frame,
+ guint32 flags)
{
gst_avi_index_entry *entry = NULL, *last_entry = NULL;
gint i;
i = -1;
do {
- entry = gst_avi_demux_index_next (avi_demux, stream_nr, i + 1, flags);
+ entry = gst_avi_demux_index_next (avi, stream_nr, i + 1, flags);
if (!entry)
return NULL;
i = entry->index_nr;
- if (entry->ts <= time) {
+ if (entry->frames_before <= frame) {
last_entry = entry;
}
- }
- while (entry->ts <= time);
+ } while (entry->frames_before <= frame);
return last_entry;
}
-static const GstFormat*
+static const GstFormat *
gst_avi_demux_get_src_formats (GstPad *pad)
{
avi_stream_context *stream = gst_pad_get_element_private (pad);
@@ -1307,28 +358,36 @@ gst_avi_demux_get_src_formats (GstPad *pad)
0
};
- return (stream->strh.type == GST_RIFF_FCC_auds ? src_a_formats : src_v_formats);
+ return (stream->strh->type == GST_RIFF_FCC_auds ?
+ src_a_formats : src_v_formats);
}
static gboolean
-gst_avi_demux_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
- GstFormat *dest_format, gint64 *dest_value)
+gst_avi_demux_src_convert (GstPad *pad,
+ GstFormat src_format,
+ gint64 src_value,
+ GstFormat *dest_format,
+ gint64 *dest_value)
{
gboolean res = TRUE;
+ /*GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));*/
avi_stream_context *stream = gst_pad_get_element_private (pad);
- if (stream->strh.type != GST_RIFF_FCC_auds &&
- (src_format == GST_FORMAT_BYTES || *dest_format == GST_FORMAT_BYTES))
+ if (stream->strh->type != GST_RIFF_FCC_auds &&
+ (src_format == GST_FORMAT_BYTES ||
+ *dest_format == GST_FORMAT_BYTES))
return FALSE;
switch (src_format) {
case GST_FORMAT_TIME:
switch (*dest_format) {
case GST_FORMAT_BYTES:
- *dest_value = src_value * stream->strh.rate / (stream->strh.scale * GST_SECOND);
+ *dest_value = src_value * stream->strh->rate /
+ (stream->strh->scale * GST_SECOND);
break;
case GST_FORMAT_DEFAULT:
- *dest_value = src_value * stream->strh.rate / (stream->strh.scale * GST_SECOND);
+ *dest_value = src_value * stream->strh->rate /
+ (stream->strh->scale * GST_SECOND);
break;
default:
res = FALSE;
@@ -1338,7 +397,7 @@ gst_avi_demux_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
case GST_FORMAT_BYTES:
switch (*dest_format) {
case GST_FORMAT_TIME:
- *dest_value = ((gfloat)src_value) * GST_SECOND / stream->strh.rate;
+ *dest_value = ((gfloat) src_value) * GST_SECOND / stream->strh->rate;
break;
default:
res = FALSE;
@@ -1348,7 +407,8 @@ gst_avi_demux_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
case GST_FORMAT_DEFAULT:
switch (*dest_format) {
case GST_FORMAT_TIME:
- *dest_value = ((((gfloat)src_value) * stream->strh.scale) / stream->strh.rate) * GST_SECOND;
+ *dest_value = ((((gfloat) src_value) * stream->strh->scale) /
+ stream->strh->rate) * GST_SECOND;
break;
default:
res = FALSE;
@@ -1362,7 +422,7 @@ gst_avi_demux_src_convert (GstPad *pad, GstFormat src_format, gint64 src_value,
return res;
}
-static const GstQueryType*
+static const GstQueryType *
gst_avi_demux_get_src_query_types (GstPad *pad)
{
static const GstQueryType src_types[] = {
@@ -1375,31 +435,34 @@ gst_avi_demux_get_src_query_types (GstPad *pad)
}
static gboolean
-gst_avi_demux_handle_src_query (GstPad *pad, GstQueryType type,
- GstFormat *format, gint64 *value)
+gst_avi_demux_handle_src_query (GstPad *pad,
+ GstQueryType type,
+ GstFormat *format,
+ gint64 *value)
{
gboolean res = TRUE;
- //GstAviDemux *avi_demux = GST_AVI_DEMUX (gst_pad_get_parent (pad));
+ /*GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));*/
avi_stream_context *stream = gst_pad_get_element_private (pad);
switch (type) {
case GST_QUERY_TOTAL:
switch (*format) {
case GST_FORMAT_TIME:
- *value = (((gfloat)stream->strh.scale) * stream->strh.length / stream->strh.rate) * GST_SECOND;
+ *value = (((gfloat) stream->strh->scale) * stream->strh->length /
+ stream->strh->rate) * GST_SECOND;
break;
case GST_FORMAT_BYTES:
- if (stream->strh.type == GST_RIFF_FCC_auds) {
+ if (stream->strh->type == GST_RIFF_FCC_auds) {
*value = stream->total_bytes;
}
else
res = FALSE;
break;
case GST_FORMAT_DEFAULT:
- if (stream->strh.type == GST_RIFF_FCC_auds)
- *value = stream->strh.length * stream->strh.samplesize;
- else if (stream->strh.type == GST_RIFF_FCC_vids)
- *value = stream->strh.length;
+ if (stream->strh->type == GST_RIFF_FCC_auds)
+ *value = stream->strh->length * stream->strh->samplesize;
+ else if (stream->strh->type == GST_RIFF_FCC_vids)
+ *value = stream->strh->length;
else
res = FALSE;
break;
@@ -1411,20 +474,23 @@ gst_avi_demux_handle_src_query (GstPad *pad, GstQueryType type,
case GST_QUERY_POSITION:
switch (*format) {
case GST_FORMAT_TIME:
- if (stream->strh.samplesize && stream->strh.type == GST_RIFF_FCC_auds) {
- //*value = (((gfloat)stream->current_byte) * stream->strh.scale / stream->strh.rate) * GST_SECOND;
- *value = ((gfloat)stream->current_byte) * GST_SECOND / stream->strh.rate;
+ if (stream->strh->samplesize &&
+ stream->strh->type == GST_RIFF_FCC_auds) {
+ *value = ((gfloat) stream->current_byte) * GST_SECOND /
+ stream->strh->rate;
}
else {
- *value = (((gfloat)stream->current_frame) * stream->strh.scale / stream->strh.rate) * GST_SECOND;
+ *value = (((gfloat) stream->current_frame) * stream->strh->scale /
+ stream->strh->rate) * GST_SECOND;
}
break;
case GST_FORMAT_BYTES:
*value = stream->current_byte;
break;
case GST_FORMAT_DEFAULT:
- if (stream->strh.samplesize && stream->strh.type == GST_RIFF_FCC_auds)
- *value = stream->current_byte * stream->strh.samplesize;
+ if (stream->strh->samplesize &&
+ stream->strh->type == GST_RIFF_FCC_auds)
+ *value = stream->current_byte * stream->strh->samplesize;
else
*value = stream->current_frame;
break;
@@ -1442,22 +508,22 @@ gst_avi_demux_handle_src_query (GstPad *pad, GstQueryType type,
}
static gint32
-gst_avi_demux_sync_streams (GstAviDemux *avi_demux, guint64 time)
+gst_avi_demux_sync_streams (GstAviDemux *avi,
+ guint64 time)
{
gint i;
guint32 min_index = G_MAXUINT;
avi_stream_context *stream;
gst_avi_index_entry *entry;
- for (i = 0; i < avi_demux->num_streams; i++) {
- stream = &avi_demux->stream[i];
+ for (i = 0; i < avi->num_streams; i++) {
+ stream = &avi->stream[i];
GST_DEBUG ("finding %d for time %" G_GINT64_FORMAT, i, time);
- entry = gst_avi_demux_index_entry_for_time (avi_demux, stream->num, time, GST_RIFF_IF_KEYFRAME);
+ entry = gst_avi_demux_index_entry_for_time (avi, stream->num, time,
+ GST_RIFF_IF_KEYFRAME);
if (entry) {
- gst_avi_debug_entry ("sync entry", entry);
-
min_index = MIN (entry->index_nr, min_index);
}
}
@@ -1465,15 +531,16 @@ gst_avi_demux_sync_streams (GstAviDemux *avi_demux, guint64 time)
/* now we know the entry we need to sync on. calculate number of frames to
* skip fro there on and the stream stats */
- for (i = 0; i < avi_demux->num_streams; i++) {
+ for (i = 0; i < avi->num_streams; i++) {
gst_avi_index_entry *next_entry;
- stream = &avi_demux->stream[i];
+ stream = &avi->stream[i];
/* next entry */
- next_entry = gst_avi_demux_index_next (avi_demux, stream->num, min_index, 0);
+ next_entry = gst_avi_demux_index_next (avi, stream->num,
+ min_index, 0);
/* next entry with keyframe */
- entry = gst_avi_demux_index_next (avi_demux, stream->num, min_index, GST_RIFF_IF_KEYFRAME);
- gst_avi_debug_entry ("final sync", entry);
+ entry = gst_avi_demux_index_next (avi, stream->num, min_index,
+ GST_RIFF_IF_KEYFRAME);
stream->current_byte = next_entry->bytes_before;
stream->current_frame = next_entry->frames_before;
@@ -1481,13 +548,15 @@ gst_avi_demux_sync_streams (GstAviDemux *avi_demux, guint64 time)
GST_DEBUG ("%d skip %d", stream->num, stream->skip);
}
+
GST_DEBUG ("final index at %d", min_index);
return min_index;
}
static gboolean
-gst_avi_demux_send_event (GstElement *element, GstEvent *event)
+gst_avi_demux_send_event (GstElement *element,
+ GstEvent *event)
{
const GList *pads;
@@ -1502,6 +571,7 @@ gst_avi_demux_send_event (GstElement *element, GstEvent *event)
gst_event_ref (event);
if (gst_avi_demux_handle_src_event (pad, event)) {
gst_event_unref (event);
+
return TRUE;
}
}
@@ -1510,15 +580,15 @@ gst_avi_demux_send_event (GstElement *element, GstEvent *event)
}
gst_event_unref (event);
+
return FALSE;
}
-static const GstEventMask*
+static const GstEventMask *
gst_avi_demux_get_event_mask (GstPad *pad)
{
static const GstEventMask masks[] = {
{ GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
- { GST_EVENT_SEEK_SEGMENT, GST_SEEK_METHOD_SET | GST_SEEK_FLAG_KEY_UNIT },
{ 0, }
};
@@ -1526,54 +596,65 @@ gst_avi_demux_get_event_mask (GstPad *pad)
}
static gboolean
-gst_avi_demux_handle_src_event (GstPad *pad, GstEvent *event)
+gst_avi_demux_handle_src_event (GstPad *pad,
+ GstEvent *event)
{
gboolean res = TRUE;
- GstAviDemux *avi_demux = GST_AVI_DEMUX (gst_pad_get_parent (pad));
+ GstAviDemux *avi = GST_AVI_DEMUX (gst_pad_get_parent (pad));
avi_stream_context *stream;
stream = gst_pad_get_element_private (pad);
switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK_SEGMENT:
- stream->end_pos = GST_EVENT_SEEK_ENDOFFSET (event);
case GST_EVENT_SEEK:
- GST_DEBUG ("seek format %d, %08x", GST_EVENT_SEEK_FORMAT (event), stream->strh.type);
+ GST_DEBUG ("seek format %d, %08x", GST_EVENT_SEEK_FORMAT (event),
+ stream->strh->type);
+
switch (GST_EVENT_SEEK_FORMAT (event)) {
case GST_FORMAT_BYTES:
case GST_FORMAT_DEFAULT:
- break;
- case GST_FORMAT_TIME:
- {
- gst_avi_index_entry *seek_entry, *entry;
+ case GST_FORMAT_TIME: {
+ gst_avi_index_entry *seek_entry, *entry = NULL;
gint64 desired_offset = GST_EVENT_SEEK_OFFSET (event);
guint32 flags;
guint64 min_index;
-
/* no seek on audio yet */
- if (stream->strh.type == GST_RIFF_FCC_auds) {
+ if (stream->strh->type == GST_RIFF_FCC_auds) {
res = FALSE;
goto done;
}
GST_DEBUG ("seeking to %" G_GINT64_FORMAT, desired_offset);
flags = GST_RIFF_IF_KEYFRAME;
+ switch (GST_EVENT_SEEK_FORMAT (event)) {
+ case GST_FORMAT_BYTES:
+ entry = gst_avi_demux_index_entry_for_byte (avi, stream->num,
+ desired_offset,
+ flags);
+ break;
+ case GST_FORMAT_DEFAULT:
+ entry = gst_avi_demux_index_entry_for_frame (avi, stream->num,
+ desired_offset,
+ flags);
+ break;
+ case GST_FORMAT_TIME:
+ entry = gst_avi_demux_index_entry_for_time (avi, stream->num,
+ desired_offset,
+ flags);
+ break;
+ }
- entry = gst_avi_demux_index_entry_for_time (avi_demux, stream->num, desired_offset, GST_RIFF_IF_KEYFRAME);
if (entry) {
- desired_offset = entry->ts;
- min_index = gst_avi_demux_sync_streams (avi_demux, desired_offset);
- seek_entry = &avi_demux->index_entries[min_index];
-
- gst_avi_debug_entry ("syncing to entry", seek_entry);
-
- avi_demux->seek_offset = seek_entry->offset + avi_demux->index_offset;
- avi_demux->seek_pending = TRUE;
- avi_demux->last_seek = seek_entry->ts;
- }
- else {
- GST_DEBUG ("no index entry found for time %" G_GINT64_FORMAT, desired_offset);
+ min_index = gst_avi_demux_sync_streams (avi, entry->ts);
+ seek_entry = &avi->index_entries[min_index];
+
+ avi->seek_offset = seek_entry->offset + avi->index_offset;
+ avi->last_seek = entry->ts;
+ } else {
+ GST_DEBUG ("no index entry found for format=%d value=%"
+ G_GINT64_FORMAT, GST_EVENT_SEEK_FORMAT (event),
+ desired_offset);
res = FALSE;
}
break;
@@ -1594,408 +675,851 @@ done:
return res;
}
-static gboolean
-gst_avi_demux_handle_sink_event (GstAviDemux *avi_demux)
+/*
+ * "Open" a RIFF file.
+ */
+
+gboolean
+gst_avi_demux_stream_init (GstAviDemux *avi)
{
- guint32 remaining;
- GstEvent *event;
- GstEventType type;
- gboolean res = TRUE;
-
- gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
+ GstRiffRead *riff = GST_RIFF_READ (avi);
+ guint32 doctype;
- type = event? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN;
- GST_DEBUG ("avidemux: event %p %d", event, type);
+ if (!gst_riff_read_header (riff, &doctype))
+ return FALSE;
+ if (doctype != GST_RIFF_RIFF_AVI) {
+ gst_element_error (GST_ELEMENT (avi), "Not an AVI file");
+ return FALSE;
+ }
- switch (type) {
- case GST_EVENT_EOS:
- gst_bytestream_flush (avi_demux->bs, remaining);
- gst_pad_event_default (avi_demux->sinkpad, event);
- res = FALSE;
- goto done;
- case GST_EVENT_FLUSH:
- g_warning ("flush event");
+ return TRUE;
+}
+
+/*
+ * Read 'avih' header.
+ */
+
+gboolean
+gst_avi_demux_stream_avih (GstAviDemux *avi,
+ guint32 *flags,
+ guint32 *streams)
+{
+ GstRiffRead *riff = GST_RIFF_READ (avi);
+ guint32 tag;
+ GstBuffer *buf;
+ gst_riff_avih *avih;
+
+ if (!gst_riff_read_data (riff, &tag, &buf))
+ return FALSE;
+
+ if (tag != GST_RIFF_TAG_avih) {
+ g_warning ("Not a avih chunk");
+ gst_buffer_unref (buf);
+ return FALSE;
+ }
+ if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_avih)) {
+ g_warning ("Too small avih (%d available, %d needed)",
+ GST_BUFFER_SIZE (buf), sizeof (gst_riff_avih));
+ gst_buffer_unref (buf);
+ return FALSE;
+ }
+
+ avih = (gst_riff_avih *) GST_BUFFER_DATA (buf);
+
+#if (G_BYTE_ORDER == G_BIG_ENDIAN)
+ avih->us_frame = GUINT32_FROM_LE (avih->us_frame);
+ avih->max_bps = GUINT32_FROM_LE (avih->max_bps);
+ avih->pad_gran = GUINT32_FROM_LE (avih->pad_gran);
+ avih->flags = GUINT32_FROM_LE (avih->flags);
+ avih->tot_frames = GUINT32_FROM_LE (avih->tot_frames);
+ avih->init_frames = GUINT32_FROM_LE (avih->init_frames);
+ avih->streams = GUINT32_FROM_LE (avih->streams);
+ avih->bufsize = GUINT32_FROM_LE (avih->bufsize);
+ avih->width = GUINT32_FROM_LE (avih->width);
+ avih->height = GUINT32_FROM_LE (avih->height);
+ avih->scale = GUINT32_FROM_LE (avih->scale);
+ avih->rate = GUINT32_FROM_LE (avih->rate);
+ avih->start = GUINT32_FROM_LE (avih->start);
+ avih->length = GUINT32_FROM_LE (avih->length);
+#endif
+
+ /* debug stuff */
+ GST_INFO ("avih tag found:");
+ GST_INFO (" us_frame %u", avih->us_frame);
+ GST_INFO (" max_bps %u", avih->max_bps);
+ GST_INFO (" pad_gran %u", avih->pad_gran);
+ GST_INFO (" flags 0x%08x", avih->flags);
+ GST_INFO (" tot_frames %u", avih->tot_frames);
+ GST_INFO (" init_frames %u", avih->init_frames);
+ GST_INFO (" streams %u", avih->streams);
+ GST_INFO (" bufsize %u", avih->bufsize);
+ GST_INFO (" width %u", avih->width);
+ GST_INFO (" height %u", avih->height);
+ GST_INFO (" scale %u", avih->scale);
+ GST_INFO (" rate %u", avih->rate);
+ GST_INFO (" start %u", avih->start);
+ GST_INFO (" length %u", avih->length);
+
+ avi->num_frames = avih->tot_frames;
+ avi->us_per_frame = avih->us_frame;
+ *streams = avih->streams;
+ *flags = avih->flags;
+
+ gst_buffer_unref (buf);
+
+ return TRUE;
+}
+
+/*
+ * Add a stream.
+ */
+
+static gboolean
+gst_avi_demux_add_stream (GstAviDemux *avi)
+{
+ GstElementClass *klass = GST_ELEMENT_GET_CLASS (avi);
+ GstRiffRead *riff = GST_RIFF_READ (avi);
+ guint32 tag;
+ gst_riff_strh *strh;
+ gchar *name = NULL, *padname = NULL;
+ GstCaps *caps = NULL;
+ GstPadTemplate *templ = NULL;
+ GstPad *pad;
+ avi_stream_context *stream;
+ union {
+ gst_riff_strf_vids *vids;
+ gst_riff_strf_auds *auds;
+ gst_riff_strf_iavs *iavs;
+ } strf;
+
+ /* the stream starts with a 'strh' header */
+ if (!(tag = gst_riff_peek_tag (riff, NULL)))
+ return FALSE;
+ if (tag != GST_RIFF_TAG_strh) {
+ g_warning ("Invalid stream header (no strh at begin)");
+ goto skip_stream;
+ }
+ if (!gst_riff_read_strh (riff, &strh))
+ return FALSE;
+
+ /* then comes a 'strf' of that specific type */
+ if (!(tag = gst_riff_peek_tag (riff, NULL)))
+ return FALSE;
+ if (tag != GST_RIFF_TAG_strf) {
+ gst_element_error (GST_ELEMENT (avi),
+ "Invalid AVI header (no strf as second tag)");
+ goto skip_stream;
+ }
+ switch (strh->type) {
+ case GST_RIFF_FCC_vids:
+ if (!gst_riff_read_strf_vids (riff, &strf.vids))
+ return FALSE;
+ break;
+ case GST_RIFF_FCC_auds:
+ if (!gst_riff_read_strf_auds (riff, &strf.auds))
+ return FALSE;
+ break;
+ case GST_RIFF_FCC_iavs:
+ if (!gst_riff_read_strf_iavs (riff, &strf.iavs))
+ return FALSE;
break;
- case GST_EVENT_DISCONTINUOUS:
- {
- gint i;
- GstEvent *discont;
+ default:
+ g_warning ("Unknown stream type " GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (strh->type));
+ goto skip_stream;
+ }
- for (i = 0; i < avi_demux->num_streams; i++) {
- avi_stream_context *stream = &avi_demux->stream[i];
+ /* read other things */
+ while (TRUE) {
+ if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
+ return FALSE;
+ else if (avi->level_up) {
+ avi->level_up--;
+ break;
+ }
- if (GST_PAD_IS_USABLE (stream->pad)) {
- GST_DEBUG ("sending discont on %d %" G_GINT64_FORMAT " + %" G_GINT64_FORMAT " = %" G_GINT64_FORMAT,
- i, avi_demux->last_seek, stream->delay, avi_demux->last_seek + stream->delay);
+ switch (tag) {
+ case GST_RIFF_TAG_strn:
+ if (name)
+ g_free (name);
+ if (!gst_riff_read_ascii (riff, &tag, &name))
+ return FALSE;
+ break;
- discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
- avi_demux->last_seek + stream->delay , NULL);
+ default:
+ GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
+ GST_FOURCC_ARGS (tag));
+ /* fall-through */
+
+ case GST_RIFF_TAG_strd: /* what is this? */
+ case GST_RIFF_TAG_JUNK:
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
+ break;
+ }
- gst_pad_push (stream->pad, GST_DATA (discont));
- }
- }
+ if (avi->level_up) {
+ avi->level_up--;
break;
}
+ }
+
+ /* create stream name + pad */
+ switch (strh->type) {
+ case GST_RIFF_FCC_vids:
+ padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
+ templ = gst_element_class_get_pad_template (klass, "video_%02d");
+ caps = gst_riff_create_video_caps (strf.vids->compression, strh, strf.vids);
+ g_free (strf.vids);
+ avi->num_v_streams++;
+ break;
+ case GST_RIFF_FCC_auds:
+ padname = g_strdup_printf ("audio_%02d", avi->num_a_streams);
+ templ = gst_element_class_get_pad_template (klass, "audio_%02d");
+ caps = gst_riff_create_audio_caps (strf.auds->format, strh, strf.auds);
+ g_free (strf.auds);
+ avi->num_a_streams++;
+ break;
+ case GST_RIFF_FCC_iavs:
+ padname = g_strdup_printf ("video_%02d", avi->num_v_streams);
+ templ = gst_element_class_get_pad_template (klass, "video_%02d");
+ caps = gst_riff_create_iavs_caps (strh->fcc_handler, strh, strf.iavs);
+ g_free (strf.iavs);
+ avi->num_v_streams++;
+ break;
default:
- g_warning ("unhandled event %d", type);
+ g_assert (0);
+ }
+
+ /* set proper settings and add it */
+ pad = gst_pad_new_from_template (templ, padname);
+ g_free (padname);
+ if (caps != NULL)
+ gst_pad_try_set_caps (pad, caps);
+
+ gst_pad_set_formats_function (pad, gst_avi_demux_get_src_formats);
+ gst_pad_set_event_mask_function (pad, gst_avi_demux_get_event_mask);
+ gst_pad_set_event_function (pad, gst_avi_demux_handle_src_event);
+ gst_pad_set_query_type_function (pad, gst_avi_demux_get_src_query_types);
+ gst_pad_set_query_function (pad, gst_avi_demux_handle_src_query);
+ gst_pad_set_convert_function (pad, gst_avi_demux_src_convert);
+
+ stream = &avi->stream[avi->num_streams];
+ stream->pad = pad;
+ stream->strh = strh;
+ stream->num = avi->num_streams;
+ stream->delay = 0LL;
+ stream->total_bytes = 0LL;
+ stream->total_frames = 0;
+ stream->current_frame = 0;
+ stream->current_byte = 0;
+ stream->current_entry = -1;
+ stream->skip = 0;
+ gst_pad_set_element_private (pad, stream);
+ avi->num_streams++;
+
+ gst_element_add_pad (GST_ELEMENT (avi), pad);
+
+ return TRUE;
+
+skip_stream:
+ while (TRUE) {
+ if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
+ return FALSE;
+ if (avi->level_up) {
+ avi->level_up--;
+ break;
+ }
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
+ }
+
+ /* add a "NULL" stream */
+ avi->num_streams++;
+
+ return TRUE; /* recoverable */
+}
+
+/*
+ * Read an openDML-2.0 extension header.
+ */
+
+static gboolean
+gst_avi_demux_stream_odml (GstAviDemux *avi)
+{
+ GstRiffRead *riff = GST_RIFF_READ (avi);
+ guint32 tag;
+
+ /* read contents */
+ while (TRUE) {
+ if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
+ return FALSE;
+ else if (avi->level_up) {
+ avi->level_up--;
+ break;
+ }
+
+ switch (tag) {
+ case GST_RIFF_TAG_dmlh: {
+ gst_riff_dmlh *dmlh;
+ GstBuffer *buf;
+
+ if (!gst_riff_read_data (riff, &tag, &buf))
+ return FALSE;
+ if (GST_BUFFER_SIZE (buf) < sizeof (gst_riff_dmlh)) {
+ g_warning ("DMLH entry is too small (%d bytes, %d needed)",
+ GST_BUFFER_SIZE (buf), sizeof (gst_riff_dmlh));
+ gst_buffer_unref (buf);
+ break;
+ }
+ dmlh = (gst_riff_dmlh *) GST_BUFFER_DATA (buf);
+
+#if (G_BYTE_ORDER == G_BIG_ENDIAN)
+ dmlh->totalframes = GUINT32_FROM_LE (dmlh->totalframes);
+#endif
+
+ GST_INFO ("dmlh tag found:");
+ GST_INFO (" totalframes: %u", dmlh->totalframes);
+
+ avi->num_frames = dmlh->totalframes;
+ gst_buffer_unref (buf);
+ break;
+ }
+
+ default:
+ GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
+ GST_FOURCC_ARGS (tag));
+ /* fall-through */
+
+ case GST_RIFF_TAG_JUNK:
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
+ break;
+ }
+
+ if (avi->level_up) {
+ avi->level_up--;
break;
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * Seek to index, read it, seek back.
+ */
+
+gboolean
+gst_avi_demux_stream_index (GstAviDemux *avi)
+{
+ GstBuffer *buf = NULL;
+ guint i;
+ GstEvent *event;
+ GstRiffRead *riff = GST_RIFF_READ (avi);
+ guint64 pos_before, pos_after, length;
+ guint32 tag;
+
+ /* first, we need to know the current position (to seek back
+ * when we're done) and the total length of the file. */
+ length = gst_bytestream_length (riff->bs);
+ pos_before = gst_bytestream_tell (riff->bs);
+
+ /* skip movi */
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
+
+ /* assure that we've got data left */
+ pos_after = gst_bytestream_tell (riff->bs);
+ if (pos_after + 8 > length) {
+ g_warning ("File said that it has an index, but there is no index data!");
+ goto end;
+ }
+
+ /* assure that it's an index */
+ if (!(tag = gst_riff_peek_tag (riff, NULL)))
+ return FALSE;
+ if (tag != GST_RIFF_TAG_idx1) {
+ g_warning ("No index after data, but " GST_FOURCC_FORMAT,
+ GST_FOURCC_ARGS (tag));
+ goto end;
+ }
+
+ /* read index */
+ if (!gst_riff_read_data (riff, &tag, &buf))
+ return FALSE;
+
+ /* parse all entries */
+ avi->index_size = GST_BUFFER_SIZE (buf) / sizeof (gst_riff_index_entry);
+ avi->index_entries = g_malloc (avi->index_size * sizeof (gst_avi_index_entry));
+ GST_INFO ("%u index entries", avi->index_size);
+
+ for (i = 0; i < avi->index_size; i++) {
+ gst_riff_index_entry *entry;
+ avi_stream_context *stream;
+ gint stream_nr;
+ gst_avi_index_entry *target;
+ GstFormat format;
+
+ entry = &((gst_riff_index_entry *) GST_BUFFER_DATA (buf))[i];
+ entry->id = GUINT32_FROM_LE (entry->id);
+ entry->offset = GUINT32_FROM_LE (entry->offset);
+ entry->flags = GUINT32_FROM_LE (entry->flags);
+ entry->size = GUINT32_FROM_LE (entry->size);
+ target = &avi->index_entries[i];
+
+ stream_nr = CHUNKID_TO_STREAMNR (entry->id);
+ if (stream_nr >= avi->num_streams || stream_nr < 0) {
+ g_warning ("Index entry %d has invalid stream nr %d",
+ i, stream_nr);
+ target->stream_nr = -1;
+ continue;
+ }
+ target->stream_nr = stream_nr;
+ stream = &avi->stream[stream_nr];
+
+ target->index_nr = i;
+ target->flags = entry->flags;
+ target->size = entry->size;
+ target->offset = entry->offset;
+
+ /* figure out if the index is 0 based or relative to the MOVI start */
+ if (i == 0) {
+ if (target->offset < pos_before)
+ avi->index_offset = pos_before + 8;
+ else
+ avi->index_offset = 0;
+ }
+
+ target->bytes_before = stream->total_bytes;
+ target->frames_before = stream->total_frames;
+
+ format = GST_FORMAT_TIME;
+ if (stream->strh->type == GST_RIFF_FCC_auds) {
+ /* all audio frames are keyframes */
+ target->flags |= GST_RIFF_IF_KEYFRAME;
+ }
+
+ if (stream->strh->samplesize && stream->strh->type == GST_RIFF_FCC_auds) {
+ /* constant rate stream */
+ gst_pad_convert (stream->pad, GST_FORMAT_BYTES,
+ stream->total_bytes, &format, &target->ts);
+ } else {
+ /* VBR stream */
+ gst_pad_convert (stream->pad, GST_FORMAT_DEFAULT,
+ stream->total_frames, &format, &target->ts);
+ }
+
+ stream->total_bytes += target->size;
+ stream->total_frames++;
+ }
+
+ /* debug our indexes */
+ for (i = 0; i < avi->num_streams; i++) {
+ avi_stream_context *stream;
+
+ stream = &avi->stream[i];
+ GST_DEBUG ("stream %u: %u frames, %" G_GINT64_FORMAT " bytes",
+ i, stream->total_frames, stream->total_bytes);
}
+end:
+ if (buf)
+ gst_buffer_unref (buf);
+
+ /* seek back to the data */
+ if (!(event = gst_riff_read_seek (riff, pos_before)))
+ return FALSE;
gst_event_unref (event);
-done:
+ return TRUE;
+}
- return res;
+/*
+ * Scan the file for all chunks to "create" a new index.
+ */
+
+gboolean
+gst_avi_demux_stream_scan (GstAviDemux *avi)
+{
+ //GstRiffRead *riff = GST_RIFF_READ (avi);
+
+ /* FIXME */
+
+ return TRUE;
}
+/*
+ * Read full AVI headers.
+ */
-static void
-gst_avi_demux_loop (GstElement *element)
+gboolean
+gst_avi_demux_stream_header (GstAviDemux *avi)
{
- GstAviDemux *avi_demux;
- gst_riff_riff chunk;
- guint32 flush = 0;
- guint32 got_bytes;
- GstByteStream *bs;
- guint64 pos;
-
- avi_demux = GST_AVI_DEMUX (element);
-
- bs = avi_demux->bs;
-
- if (avi_demux->seek_pending) {
- GST_DEBUG ("avidemux: seek pending to %" G_GINT64_FORMAT " %08llx",
- avi_demux->seek_offset, (unsigned long long)avi_demux->seek_offset);
-
- if (!gst_bytestream_seek (avi_demux->bs,
- avi_demux->seek_offset,
- GST_SEEK_METHOD_SET))
- {
- GST_INFO ( "avidemux: could not seek");
+ GstRiffRead *riff = GST_RIFF_READ (avi);
+ guint32 tag, flags, streams;
+
+ /* the header consists of a 'hdrl' LIST tag */
+ if (!(tag = gst_riff_peek_tag (riff, NULL)))
+ return FALSE;
+ if (tag != GST_RIFF_TAG_LIST) {
+ gst_element_error (GST_ELEMENT (avi),
+ "Invalid AVI header (no LIST at start): "
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag));
+ return FALSE;
+ }
+ if (!gst_riff_read_list (riff, &tag))
+ return FALSE;
+ if (tag != GST_RIFF_LIST_hdrl) {
+ gst_element_error (GST_ELEMENT (avi),
+ "Invalid AVI header (no hdrl at start): "
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag));
+ return FALSE;
+ }
+
+ /* the hdrl starts with a 'avih' header */
+ if (!(tag = gst_riff_peek_tag (riff, NULL)))
+ return FALSE;
+ if (tag != GST_RIFF_TAG_avih) {
+ gst_element_error (GST_ELEMENT (avi),
+ "Invalid AVI header (no avih at start): "
+ GST_FOURCC_FORMAT, GST_FOURCC_ARGS (tag));
+ return FALSE;
+ }
+ if (!gst_avi_demux_stream_avih (avi, &flags, &streams))
+ return FALSE;
+
+ /* now, read the elements from the header until the end */
+ while (TRUE) {
+ if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
+ return FALSE;
+ else if (avi->level_up) {
+ avi->level_up--;
+ break;
+ }
+
+ switch (tag) {
+ case GST_RIFF_TAG_LIST:
+ if (!(tag = gst_riff_peek_list (riff)))
+ return FALSE;
+
+ switch (tag) {
+ case GST_RIFF_LIST_strl:
+ if (!gst_riff_read_list (riff, &tag) ||
+ !gst_avi_demux_add_stream (avi))
+ return FALSE;
+ break;
+
+ case GST_RIFF_LIST_odml:
+ if (!gst_riff_read_list (riff, &tag) ||
+ !gst_avi_demux_stream_odml (avi))
+ return FALSE;
+ break;
+
+ case GST_RIFF_LIST_INFO:
+ if (!gst_riff_read_list (riff, &tag) ||
+ !gst_riff_read_info (riff))
+ return FALSE;
+ break;
+
+ default:
+ GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " in AVI header",
+ GST_FOURCC_ARGS (tag));
+ /* fall-through */
+
+ case GST_RIFF_TAG_JUNK:
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
+ break;
+ }
+
+ break;
+
+ default:
+ GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " in AVI header",
+ GST_FOURCC_ARGS (tag));
+ /* fall-through */
+
+ case GST_RIFF_TAG_JUNK:
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
+ break;
+ }
+
+ if (avi->level_up) {
+ avi->level_up--;
+ break;
}
- avi_demux->seek_pending = FALSE;
}
- pos = gst_bytestream_tell (bs);
- do {
- gst_riff_riff *temp_chunk;
- guint8 *tempdata;
- guint32 skipsize;
-
- /* read first two dwords to get chunktype and size */
- while (TRUE) {
- got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_chunk));
- temp_chunk = (gst_riff_riff *) tempdata;
- if (got_bytes < sizeof (gst_riff_chunk)) {
- if (!gst_avi_demux_handle_sink_event (avi_demux))
- return;
- }
- else break;
+ if (avi->num_streams != streams) {
+ g_warning ("Stream header mentioned %d streams, but %d available",
+ streams, avi->num_streams);
+ }
+
+ /* we've got streaminfo now */
+ g_object_notify (G_OBJECT(avi), "streaminfo");
+
+ /* Now, find the data (i.e. skip all junk between header and data) */
+ while (1) {
+ if (!(tag = gst_riff_peek_tag (riff, NULL)))
+ return FALSE;
+ if (tag != GST_RIFF_TAG_LIST) {
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
+ continue;
+ }
+ if (!(tag = gst_riff_peek_list (riff)))
+ return FALSE;
+ if (tag != GST_RIFF_LIST_movi) {
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
+ continue;
}
+ break;
+ }
+
+ /* create or read stream index (for seeking) */
+ if (flags & GST_RIFF_AVIH_HASINDEX) {
+ if (!gst_avi_demux_stream_index (avi))
+ return FALSE;
+ } else {
+ if (!gst_avi_demux_stream_scan (avi))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Handle seek.
+ */
+
+static gboolean
+gst_avi_demux_handle_seek (GstAviDemux *avi)
+{
+ GstRiffRead *riff = GST_RIFF_READ (avi);
+ guint i;
+ GstEvent *event;
+
+ /* FIXME: if we seek in an openDML file, we will have multiple
+ * primary levels. Seeking in between those will cause havoc. */
+
+ if (!(event = gst_riff_read_seek (riff, avi->seek_offset)))
+ return FALSE;
+ gst_event_unref (event);
+
+ for (i = 0; i < avi->num_streams; i++) {
+ avi_stream_context *stream = &avi->stream[i];
+
+ if (GST_PAD_IS_USABLE (stream->pad)) {
+ event = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME,
+ avi->last_seek + stream->delay , NULL);
+ gst_pad_push (stream->pad, GST_DATA (event));
+ }
+ }
+
+ return TRUE;
+}
+
+/*
+ * Read data.
+ */
- chunk.id = GUINT32_FROM_LE (temp_chunk->id);
- chunk.size = GUINT32_FROM_LE (temp_chunk->size);
+gboolean
+gst_avi_demux_stream_data (GstAviDemux *avi)
+{
+ GstRiffRead *riff = GST_RIFF_READ (avi);
+ guint32 tag;
+ guint stream_nr;
+ gst_avi_index_entry *entry;
+
+ if (avi->seek_offset != (guint64) -1) {
+ if (!gst_avi_demux_handle_seek (avi))
+ return FALSE;
+ avi->seek_offset = (guint64) -1;
+ }
- switch (chunk.id) {
- case GST_RIFF_TAG_RIFF:
+ /* peek first (for the end of this 'list/movi' section) */
+ if (!(tag = gst_riff_peek_tag (riff, &avi->level_up)))
+ return FALSE;
+
+ /* if we're at top-level, we didn't read the 'movi'
+ * list tag yet. This can also be 'AVIX' in case of
+ * openDML-2.0 AVI files. Lastly, it might be idx1,
+ * in which case we skip it so we come at EOS. */
+ while (g_list_length (riff->level) < 2) {
+ if (!(tag = gst_riff_peek_tag (riff, NULL)))
+ return FALSE;
+
+ switch (tag) {
case GST_RIFF_TAG_LIST:
- /* read complete list chunk */
- while (TRUE) {
- got_bytes = gst_bytestream_peek_bytes (bs, &tempdata, sizeof (gst_riff_list));
- temp_chunk = (gst_riff_riff *) tempdata;
- if (got_bytes < sizeof (gst_riff_list)) {
- if (!gst_avi_demux_handle_sink_event (avi_demux))
- return;
- }
- else break;
+ if (!(tag = gst_riff_peek_list (riff)))
+ return FALSE;
+
+ switch (tag) {
+ case GST_RIFF_LIST_AVIX:
+ case GST_RIFF_LIST_movi:
+ if (!gst_riff_read_list (riff, &tag))
+ return FALSE;
+ /* we're now going to read buffers! */
+ break;
+
+ default:
+ GST_WARNING ("Unknown list " GST_FOURCC_FORMAT " before AVI data",
+ GST_FOURCC_ARGS (tag));
+ /* fall-through */
+
+ case GST_RIFF_TAG_JUNK:
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
+ break;
}
- chunk.type = GUINT32_FROM_LE (temp_chunk->type);
- skipsize = sizeof (gst_riff_list);
+
break;
+
default:
- skipsize = sizeof (gst_riff_chunk);
+ GST_WARNING ("Unknown tag " GST_FOURCC_FORMAT " before AVI data",
+ GST_FOURCC_ARGS (tag));
+ /* fall-through */
+
+ case GST_RIFF_TAG_idx1:
+ case GST_RIFF_TAG_JUNK:
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
break;
}
- gst_bytestream_flush_fast (bs, skipsize);
- }
- while (FALSE);
+ }
+
+ /* And then, we get the data */
+ if (!(tag = gst_riff_peek_tag (riff, NULL)))
+ return FALSE;
+ stream_nr = CHUNKID_TO_STREAMNR (tag);
+ if (stream_nr < 0 || stream_nr >= avi->num_streams) {
+ /* recoverable */
+ g_warning ("Invalid stream ID %d (" GST_FOURCC_FORMAT ")",
+ stream_nr, GST_FOURCC_ARGS (tag));
+ if (!gst_riff_read_skip (riff))
+ return FALSE;
+ } else {
+ avi_stream_context *stream;
+ GstClockTime next_ts;
+ GstFormat format;
+ GstBuffer *buf;
- /* need to flush an even number of bytes at the end */
- flush = (chunk.size + 1) & ~1;
+ /* get buffer */
+ if (!gst_riff_read_data (riff, &tag, &buf))
+ return FALSE;
- switch (avi_demux->state) {
- case GST_AVI_DEMUX_START:
- if (chunk.id != GST_RIFF_TAG_RIFF &&
- chunk.type != GST_RIFF_RIFF_AVI) {
- gst_element_error (element, "This doesn't appear to be an AVI file %08x %08x", chunk.id, chunk.type);
- return;
- }
- avi_demux->state = GST_AVI_DEMUX_HEADER;
- /* we are not going to flush lists */
- flush = 0;
- break;
- case GST_AVI_DEMUX_HEADER:
- GST_DEBUG ("riff tag: %4.4s %08x", (gchar *)&chunk.id, chunk.size);
- switch (chunk.id) {
- case GST_RIFF_TAG_LIST:
- GST_DEBUG ("list type: %4.4s", (gchar *)&chunk.type);
- switch (chunk.type) {
- case GST_RIFF_LIST_movi:
- {
- guint64 filepos;
-
- filepos = gst_bytestream_tell (bs);
-
- gst_avi_demux_parse_index (avi_demux, filepos , chunk.size - 4);
-
- if (avi_demux->avih.bufsize) {
- gst_bytestream_size_hint (avi_demux->bs, avi_demux->avih.bufsize);
- }
-
- avi_demux->state = GST_AVI_DEMUX_MOVI;
- /* and tell the bastards that we have stream info too */
- gst_props_debug(avi_demux->streaminfo->properties);
- g_object_notify(G_OBJECT(avi_demux), "streaminfo");
- break;
- }
- case GST_RIFF_LIST_INFO:
- gst_avi_demux_metadata (avi_demux, chunk.size);
- break;
- default:
- break;
- }
- flush = 0;
- break;
- case GST_RIFF_TAG_avih:
- gst_avi_demux_avih (avi_demux);
- break;
- case GST_RIFF_TAG_strh:
- gst_avi_demux_strh (avi_demux);
- break;
- case GST_RIFF_TAG_strf:
- switch (avi_demux->fcc_type) {
- case GST_RIFF_FCC_vids:
- gst_avi_demux_strf_vids (avi_demux);
- break;
- case GST_RIFF_FCC_auds:
- gst_avi_demux_strf_auds (avi_demux);
- break;
- case GST_RIFF_FCC_iavs:
- gst_avi_demux_strf_iavs (avi_demux);
- break;
- case GST_RIFF_FCC_pads:
- case GST_RIFF_FCC_txts:
- default:
- GST_INFO ( "gst_avi_demux_chain: strh type %s not supported",
- gst_riff_id_to_fourcc (avi_demux->fcc_type));
- break;
- }
- break;
- case GST_RIFF_TAG_strn:
- gst_avi_demux_strn (avi_demux, chunk.size);
- break;
- case GST_RIFF_TAG_dmlh:
- gst_avi_demux_dmlh (avi_demux);
- break;
- case GST_RIFF_TAG_JUNK:
- case GST_RIFF_ISFT:
- break;
- default:
- GST_DEBUG (" ***** unknown chunkid %08x", chunk.id);
- break;
+ /* get time of this buffer */
+ stream = &avi->stream[stream_nr];
+ entry = gst_avi_demux_index_next (avi, stream_nr,
+ stream->current_entry + 1, 0);
+ if (entry) {
+ stream->current_entry = entry->index_nr;
+ if (entry->flags & GST_RIFF_IF_KEYFRAME) {
+ GST_BUFFER_FLAG_SET (buf, GST_BUFFER_KEY_UNIT);
}
- break;
- case GST_AVI_DEMUX_MOVI:
- switch (chunk.id) {
- case GST_RIFF_00dc:
- case GST_RIFF_00db:
- case GST_RIFF_00__:
- case GST_RIFF_01wb:
- {
- gint stream_id;
- avi_stream_context *stream;
- gint64 next_ts;
- GstFormat format;
-
- stream_id = CHUNKID_TO_STREAMNR (chunk.id);
-
- stream = &avi_demux->stream[stream_id];
-
- GST_LOG_OBJECT (avi_demux, "gst_avi_demux_chain: tag found %08x size %08x stream_id %d",
- chunk.id, chunk.size, stream_id);
-
- format = GST_FORMAT_TIME;
- gst_pad_query (stream->pad, GST_QUERY_POSITION, &format, &next_ts);
-
- if (stream->strh.init_frames == stream->current_frame && stream->delay == 0)
- stream->delay = next_ts;
-
- stream->current_frame++;
- stream->current_byte += chunk.size;
-
- if (stream->skip) {
- stream->skip--;
- }
- else {
- if (GST_PAD_IS_USABLE (stream->pad)) {
- if (next_ts >= stream->end_pos) {
- gst_pad_push (stream->pad, GST_DATA (gst_event_new (GST_EVENT_EOS)));
- GST_DEBUG ("end stream %d: %" G_GINT64_FORMAT " %d %" G_GINT64_FORMAT,
- stream_id, next_ts, stream->current_frame - 1,
- stream->end_pos);
- }
- else {
- GstBuffer *buf;
- guint32 got_bytes;
-
- if (chunk.size) {
- GstClockTime dur_ts;
- got_bytes = gst_bytestream_peek (avi_demux->bs, &buf, chunk.size);
-
- GST_BUFFER_TIMESTAMP (buf) = next_ts;
-
- gst_pad_query (stream->pad, GST_QUERY_POSITION, &format, &dur_ts);
- GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
-
- if (stream->need_flush) {
- /* FIXME, do some flush event here */
- stream->need_flush = FALSE;
- }
- GST_LOG_OBJECT (avi_demux, "send stream %d: %"
- G_GINT64_FORMAT " %d %" G_GINT64_FORMAT " %08x",
- stream_id, next_ts, stream->current_frame - 1,
- stream->delay, chunk.size);
-
- gst_pad_push(stream->pad, GST_DATA (buf));
- }
- }
- }
- }
- break;
- }
- default:
- GST_DEBUG (" ***** unknown chunkid %08x", chunk.id);
- break;
+ }
+ format = GST_FORMAT_TIME;
+ gst_pad_query (stream->pad, GST_QUERY_POSITION,
+ &format, &next_ts);
+
+ /* set delay (if any) */
+ if (stream->strh->init_frames == stream->current_frame &&
+ stream->delay == 0)
+ stream->delay = next_ts;
+
+ stream->current_frame++;
+ stream->current_byte += GST_BUFFER_SIZE (buf);
+
+ /* should we skip this data? */
+ if (stream->skip) {
+ stream->skip--;
+ gst_buffer_unref (buf);
+ } else {
+ if (!stream->pad || !GST_PAD_IS_USABLE (stream->pad)) {
+ gst_buffer_unref (buf);
+ } else {
+ GstClockTime dur_ts;
+
+ GST_BUFFER_TIMESTAMP (buf) = next_ts;
+ gst_pad_query (stream->pad, GST_QUERY_POSITION,
+ &format, &dur_ts);
+ GST_BUFFER_DURATION (buf) = dur_ts - next_ts;
+
+ gst_pad_push (stream->pad, GST_DATA (buf));
}
- break;
+ }
}
- while (flush) {
- gboolean res;
-
- res = gst_bytestream_flush (avi_demux->bs, flush);
- if (!res) {
- guint32 remaining;
- GstEvent *event;
+ return TRUE;
+}
- gst_bytestream_get_status (avi_demux->bs, &remaining, &event);
- gst_event_unref (event);
- }
- else
+static void
+gst_avi_demux_loop (GstElement *element)
+{
+ GstAviDemux *avi = GST_AVI_DEMUX (element);
+
+ switch (avi->state) {
+ case GST_AVI_DEMUX_START:
+ if (!gst_avi_demux_stream_init (avi))
+ return;
+ avi->state = GST_AVI_DEMUX_HEADER;
+ /* fall-through */
+
+ case GST_AVI_DEMUX_HEADER:
+ if (!gst_avi_demux_stream_header (avi))
+ return;
+ avi->state = GST_AVI_DEMUX_MOVI;
+ /* fall-through */
+
+ case GST_AVI_DEMUX_MOVI:
+ if (!gst_avi_demux_stream_data (avi))
+ return;
break;
+
+ default:
+ g_assert (0);
}
}
static GstElementStateReturn
gst_avi_demux_change_state (GstElement *element)
{
- GstAviDemux *avi_demux = GST_AVI_DEMUX (element);
+ GstAviDemux *avi = GST_AVI_DEMUX (element);
switch (GST_STATE_TRANSITION (element)) {
- case GST_STATE_NULL_TO_READY:
- break;
case GST_STATE_READY_TO_PAUSED:
- avi_demux->bs = gst_bytestream_new (avi_demux->sinkpad);
- avi_demux->last_seek = 0;
- avi_demux->state = GST_AVI_DEMUX_START;
- avi_demux->num_streams = 0;
- avi_demux->num_v_streams = 0;
- avi_demux->num_a_streams = 0;
- avi_demux->index_entries = NULL;
- avi_demux->index_size = 0;
- avi_demux->seek_pending = 0;
- avi_demux->metadata = NULL;
- gst_avi_demux_streaminfo(avi_demux);
- break;
- case GST_STATE_PAUSED_TO_PLAYING:
- break;
- case GST_STATE_PLAYING_TO_PAUSED:
+ gst_avi_demux_streaminfo (avi);
break;
case GST_STATE_PAUSED_TO_READY:
- gst_bytestream_destroy (avi_demux->bs);
- gst_caps_replace (&avi_demux->metadata, NULL);
- gst_caps_replace (&avi_demux->streaminfo, NULL);
- break;
- case GST_STATE_READY_TO_NULL:
+ gst_avi_demux_reset (avi);
break;
default:
break;
}
- parent_class->change_state (element);
+ if (GST_ELEMENT_CLASS (parent_class)->change_state)
+ return GST_ELEMENT_CLASS (parent_class)->change_state (element);
return GST_STATE_SUCCESS;
}
static void
-gst_avi_demux_get_property (GObject *object, guint prop_id, GValue *value,
+gst_avi_demux_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
GParamSpec *pspec)
{
- GstAviDemux *src;
-
- g_return_if_fail (GST_IS_AVI_DEMUX (object));
-
- src = GST_AVI_DEMUX (object);
+ GstAviDemux *avi = GST_AVI_DEMUX (object);
switch (prop_id) {
- case ARG_BITRATE:
- break;
- case ARG_METADATA:
- g_value_set_boxed(value, src->metadata);
- break;
case ARG_STREAMINFO:
- g_value_set_boxed(value, src->streaminfo);
+ g_value_set_boxed (value, avi->streaminfo);
break;
default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
-
-static gboolean
-plugin_init (GstPlugin *plugin)
-{
- if (!gst_library_load ("gstbytestream"))
- return FALSE;
- if (!gst_library_load ("gstriff"))
- return FALSE;
- if (!gst_library_load("gstvideo"))
- return FALSE;
-
- GST_DEBUG_CATEGORY_INIT (avidemux_debug, "avidemux", 0, "Demuxer for AVI video");
-
- if (!gst_element_register (plugin, "avidemux", GST_RANK_PRIMARY,
- GST_TYPE_AVI_DEMUX)) {
- return FALSE;
- }
-
- if (!gst_element_register (plugin, "avimux", GST_RANK_PRIMARY,
- GST_TYPE_AVIMUX)) {
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-GST_PLUGIN_DEFINE (
- GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "avimux",
- "AVI stream handling",
- plugin_init,
- VERSION,
- GST_LICENSE,
- GST_PACKAGE,
- GST_ORIGIN
-)
-