diff options
author | Andy Wingo <wingo@pobox.com> | 2001-12-22 23:22:30 +0000 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2001-12-22 23:22:30 +0000 |
commit | 61a50361fbb2b0166ce9ffa8a471b45b482b6eec (patch) | |
tree | 9e3b1428b9e2d1a0d404b501f2329911bc6f0a50 /gst/avi/gstavidemux.c | |
parent | a2c423bbad0ef5dbc7698c2e27221594d296018d (diff) |
Initial revision
Original commit message from CVS:
Initial revision
Diffstat (limited to 'gst/avi/gstavidemux.c')
-rw-r--r-- | gst/avi/gstavidemux.c | 757 |
1 files changed, 757 insertions, 0 deletions
diff --git a/gst/avi/gstavidemux.c b/gst/avi/gstavidemux.c new file mode 100644 index 00000000..1aca1ad2 --- /dev/null +++ b/gst/avi/gstavidemux.c @@ -0,0 +1,757 @@ +/* Gnome-Streamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +//#define GST_DEBUG_ENABLED +#include <string.h> + +#include "gstavidemux.h" + + +/* elementfactory information */ +static GstElementDetails gst_avi_demux_details = { + ".avi parser", + "Parser/Video", + "Parse a .avi file into audio and video", + VERSION, + "Erik Walthinsen <omega@cse.ogi.edu>\n" + "Wim Taymans <wim.taymans@tvd.be>", + "(C) 1999", +}; + +static GstCaps* avi_typefind (GstBuffer *buf, gpointer private); + +/* typefactory for 'avi' */ +static GstTypeDefinition avidefinition = { + "avidemux_video/avi", + "video/avi", + ".avi", + avi_typefind, +}; + +/* AviDemux signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_BITRATE, + ARG_MEDIA_TIME, + ARG_CURRENT_TIME, + /* FILL ME */ +}; + +GST_PADTEMPLATE_FACTORY (sink_templ, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "avidemux_sink", + "video/avi", + NULL + ) +) + +GST_PADTEMPLATE_FACTORY (src_video_templ, + "video_[00-32]", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "src_video", + "video/avi", + "format", GST_PROPS_LIST ( + GST_PROPS_STRING ("strf_vids"), + GST_PROPS_STRING ("strf_iavs") + ) + ) +) + +GST_PADTEMPLATE_FACTORY (src_audio_templ, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "src_audio", + "video/avi", + "format", GST_PROPS_STRING ("strf_auds") + ) +) + +static void gst_avi_demux_class_init (GstAviDemuxClass *klass); +static void gst_avi_demux_init (GstAviDemux *avi_demux); + +static void gst_avi_demux_loop (GstElement *element); + +static void gst_avi_demux_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec); + + +static GstElementClass *parent_class = NULL; +//static guint gst_avi_demux_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_avi_demux_get_type(void) +{ + static GType avi_demux_type = 0; + + if (!avi_demux_type) { + static const GTypeInfo avi_demux_info = { + sizeof(GstAviDemuxClass), + NULL, + NULL, + (GClassInitFunc)gst_avi_demux_class_init, + NULL, + NULL, + sizeof(GstAviDemux), + 0, + (GInstanceInitFunc)gst_avi_demux_init, + }; + avi_demux_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviDemux", &avi_demux_info, 0); + } + return avi_demux_type; +} + +static void +gst_avi_demux_class_init (GstAviDemuxClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + 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 (G_OBJECT_CLASS(klass), ARG_MEDIA_TIME, + g_param_spec_long ("media_time","media_time","media_time", + G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); // CHECKME + g_object_class_install_property (G_OBJECT_CLASS(klass), ARG_CURRENT_TIME, + g_param_spec_long ("current_time","current_time","current_time", + G_MINLONG, G_MAXLONG, 0, G_PARAM_READABLE)); // CHECKME + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + gobject_class->get_property = gst_avi_demux_get_property; +} + +static void +gst_avi_demux_init (GstAviDemux *avi_demux) +{ + guint i; + + GST_FLAG_SET (avi_demux, GST_ELEMENT_EVENT_AWARE); + + avi_demux->sinkpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (sink_templ), "sink"); + gst_element_add_pad (GST_ELEMENT (avi_demux), avi_demux->sinkpad); + + gst_element_set_loop_function (GST_ELEMENT (avi_demux), gst_avi_demux_loop); + + avi_demux->state = GST_AVI_DEMUX_UNKNOWN; + avi_demux->num_audio_pads = 0; + avi_demux->num_video_pads = 0; + avi_demux->next_time = 0; + avi_demux->flags = 0; + avi_demux->index_entries = NULL; + avi_demux->index_size = 0; + avi_demux->resync_offset = 0; + + //GST_FLAG_SET( GST_OBJECT (avi_demux), GST_ELEMENT_NO_SEEK); + + for(i=0; i<GST_AVI_DEMUX_MAX_AUDIO_PADS; i++) + avi_demux->audio_pad[i] = NULL; + + for(i=0; i<GST_AVI_DEMUX_MAX_VIDEO_PADS; i++) + avi_demux->video_pad[i] = NULL; + +} + +static GstCaps* +avi_typefind (GstBuffer *buf, + gpointer private) +{ + gchar *data = GST_BUFFER_DATA (buf); + GstCaps *new; + + GST_DEBUG (0,"avi_demux: typefind\n"); + + if (GUINT32_FROM_LE (((guint32 *)data)[0]) != GST_RIFF_TAG_RIFF) + return NULL; + if (GUINT32_FROM_LE (((guint32 *)data)[2]) != GST_RIFF_RIFF_AVI) + return NULL; + + new = gst_caps_new ("avi_typefind","video/avi", NULL); + + return new; +} + +static gboolean +gst_avi_demux_avih (GstAviDemux *avi_demux) +{ + gst_riff_avih *avih; + GstByteStream *bs = avi_demux->bs; + + avih = (gst_riff_avih *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_avih)); + if (avih) { + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: avih tag found"); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: us_frame %d", GUINT32_FROM_LE (avih->us_frame)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: max_bps %d", GUINT32_FROM_LE (avih->max_bps)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: pad_gran %d", GUINT32_FROM_LE (avih->pad_gran)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: flags 0x%08x", GUINT32_FROM_LE (avih->flags)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: tot_frames %d", GUINT32_FROM_LE (avih->tot_frames)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: init_frames %d", GUINT32_FROM_LE (avih->init_frames)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: streams %d", GUINT32_FROM_LE (avih->streams)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: bufsize %d", GUINT32_FROM_LE (avih->bufsize)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: width %d", GUINT32_FROM_LE (avih->width)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: height %d", GUINT32_FROM_LE (avih->height)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: scale %d", GUINT32_FROM_LE (avih->scale)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: rate %d", GUINT32_FROM_LE (avih->rate)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: start %d", GUINT32_FROM_LE (avih->start)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: length %d", GUINT32_FROM_LE (avih->length)); + + avi_demux->time_interval = GUINT32_FROM_LE (avih->us_frame); + avi_demux->tot_frames = GUINT32_FROM_LE (avih->tot_frames); + avi_demux->flags = GUINT32_FROM_LE (avih->flags); + + return TRUE; + } + return FALSE; +} + +static gboolean +gst_avi_demux_strh (GstAviDemux *avi_demux) +{ + gst_riff_strh *strh; + GstByteStream *bs = avi_demux->bs; + + strh = (gst_riff_strh *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_strh)); + if (strh) { + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strh tag found"); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: type 0x%08x (%s)", + GUINT32_FROM_LE (strh->type), gst_riff_id_to_fourcc (strh->type)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: fcc_handler 0x%08x (%s)", + GUINT32_FROM_LE (strh->fcc_handler), gst_riff_id_to_fourcc (strh->fcc_handler)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: flags 0x%08x", GUINT32_FROM_LE (strh->flags)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: priority %d", GUINT32_FROM_LE (strh->priority)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: init_frames %d", GUINT32_FROM_LE (strh->init_frames)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: scale %d", GUINT32_FROM_LE (strh->scale)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: rate %d", GUINT32_FROM_LE (strh->rate)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: start %d", GUINT32_FROM_LE (strh->start)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: length %d", GUINT32_FROM_LE (strh->length)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: bufsize %d", GUINT32_FROM_LE (strh->bufsize)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: quality %d", GUINT32_FROM_LE (strh->quality)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: samplesize %d", GUINT32_FROM_LE (strh->samplesize)); + + avi_demux->fcc_type = GUINT32_FROM_LE (strh->type); + + return TRUE; + } + return FALSE; +} + +static void +gst_avi_demux_strf_vids (GstAviDemux *avi_demux) +{ + gst_riff_strf_vids *strf; + GstPad *srcpad; + GstByteStream *bs = avi_demux->bs; + + strf = (gst_riff_strf_vids *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_strf_vids)); + + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context vids"); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: size %d", GUINT32_FROM_LE (strf->size)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: width %d", GUINT32_FROM_LE (strf->width)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: height %d", GUINT32_FROM_LE (strf->height)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: planes %d", GUINT16_FROM_LE (strf->planes)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: bit_cnt %d", GUINT16_FROM_LE (strf->bit_cnt)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: compression 0x%08x (%s)", + GUINT32_FROM_LE (strf->compression), gst_riff_id_to_fourcc (strf->compression)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: image_size %d", GUINT32_FROM_LE (strf->image_size)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: xpels_meter %d", GUINT32_FROM_LE (strf->xpels_meter)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: ypels_meter %d", GUINT32_FROM_LE (strf->ypels_meter)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: num_colors %d", GUINT32_FROM_LE (strf->num_colors)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: imp_colors %d", GUINT32_FROM_LE (strf->imp_colors)); + + srcpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (src_video_templ), g_strdup_printf ("video_%02d", + avi_demux->num_video_pads)); + + gst_pad_set_caps (srcpad, gst_caps_new ( + "avidec_video_src", + "video/avi", + gst_props_new ( + "format", GST_PROPS_STRING ("strf_vids"), + "size", GST_PROPS_INT (GUINT32_FROM_LE (strf->size)), + "width", GST_PROPS_INT (GUINT32_FROM_LE (strf->width)), + "height", GST_PROPS_INT (GUINT32_FROM_LE (strf->height)), + "planes", GST_PROPS_INT (GUINT16_FROM_LE (strf->planes)), + "bit_cnt", GST_PROPS_INT (GUINT16_FROM_LE (strf->bit_cnt)), + "compression", GST_PROPS_FOURCC (GUINT32_FROM_LE (strf->compression)), + "image_size", GST_PROPS_INT (GUINT32_FROM_LE (strf->image_size)), + "xpels_meter", GST_PROPS_INT (GUINT32_FROM_LE (strf->xpels_meter)), + "ypels_meter", GST_PROPS_INT (GUINT32_FROM_LE (strf->ypels_meter)), + "num_colors", GST_PROPS_INT (GUINT32_FROM_LE (strf->num_colors)), + "imp_colors", GST_PROPS_INT (GUINT32_FROM_LE (strf->imp_colors)), + NULL))); + + avi_demux->video_pad[avi_demux->num_video_pads++] = srcpad; + gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad); +} + +static void +gst_avi_demux_strf_auds (GstAviDemux *avi_demux) +{ + gst_riff_strf_auds *strf; + GstPad *srcpad; + GstByteStream *bs = avi_demux->bs; + + strf = (gst_riff_strf_auds *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_strf_auds)); + + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context auds"); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: format %d", GUINT16_FROM_LE (strf->format)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: channels %d", GUINT16_FROM_LE (strf->channels)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: rate %d", GUINT32_FROM_LE (strf->rate)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: av_bps %d", GUINT32_FROM_LE (strf->av_bps)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: blockalign %d", GUINT16_FROM_LE (strf->blockalign)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: size %d", GUINT16_FROM_LE (strf->size)); + + srcpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (src_audio_templ), g_strdup_printf ("audio_%02d", + avi_demux->num_audio_pads)); + + gst_pad_set_caps (srcpad, gst_caps_new ( + "avidec_audio_src", + "video/avi", + gst_props_new ( + "format", GST_PROPS_STRING ("strf_auds"), + "fmt", GST_PROPS_INT (GUINT16_FROM_LE (strf->format)), + "channels", GST_PROPS_INT (GUINT16_FROM_LE (strf->channels)), + "rate", GST_PROPS_INT (GUINT32_FROM_LE (strf->rate)), + "av_bps", GST_PROPS_INT (GUINT32_FROM_LE (strf->av_bps)), + "blockalign", GST_PROPS_INT (GUINT16_FROM_LE (strf->blockalign)), + "size", GST_PROPS_INT (GUINT16_FROM_LE (strf->size)), + NULL))); + + avi_demux->audio_pad[avi_demux->num_audio_pads++] = srcpad; + gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad); +} + +static void +gst_avi_demux_strf_iavs (GstAviDemux *avi_demux) +{ + gst_riff_strf_iavs *strf; + GstPad *srcpad; + GstByteStream *bs = avi_demux->bs; + + strf = (gst_riff_strf_iavs *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_strf_iavs)); + + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: strf tag found in context iavs"); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVAAuxSrc %08x", GUINT32_FROM_LE (strf->DVAAuxSrc)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVAAuxCtl %08x", GUINT32_FROM_LE (strf->DVAAuxCtl)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVAAuxSrc1 %08x", GUINT32_FROM_LE (strf->DVAAuxSrc1)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVAAuxCtl1 %08x", GUINT32_FROM_LE (strf->DVAAuxCtl1)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVVAuxSrc %08x", GUINT32_FROM_LE (strf->DVVAuxSrc)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVVAuxCtl %08x", GUINT32_FROM_LE (strf->DVVAuxCtl)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVReserved1 %08x", GUINT32_FROM_LE (strf->DVReserved1)); + GST_INFO (GST_CAT_PLUGIN_INFO, "gst_avi_demux: DVReserved2 %08x", GUINT32_FROM_LE (strf->DVReserved2)); + + srcpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (src_video_templ), g_strdup_printf ("video_%02d", + avi_demux->num_video_pads)); + + gst_pad_set_caps (srcpad, gst_caps_new ( + "avidec_iav_src", + "video/avi", + gst_props_new ( + "format", GST_PROPS_STRING ("strf_iavs"), + "DVAAuxSrc", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxSrc)), + "DVAAuxCtl", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxCtl)), + "DVAAuxSrc1", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxSrc1)), + "DVAAuxCtl1", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVAAuxCtl1)), + "DVVAuxSrc", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVVAuxSrc)), + "DVVAuxCtl", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVVAuxCtl)), + "DVReserved1", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVReserved1)), + "DVReserved2", GST_PROPS_INT (GUINT32_FROM_LE (strf->DVReserved2)), + NULL))); + + avi_demux->video_pad[avi_demux->num_video_pads++] = srcpad; + gst_element_add_pad (GST_ELEMENT (avi_demux), srcpad); +} + +static void +gst_avidemux_parse_index (GstAviDemux *avi_demux, + gulong offset) +{ + GstBuffer *buf; + gulong index_size; + + buf = gst_pad_pullregion (avi_demux->sinkpad, GST_REGION_OFFSET_LEN, offset, 8); + + if (!buf || GST_BUFFER_OFFSET (buf) != offset || GST_BUFFER_SIZE (buf) != 8) { + GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: could not get index"); + return; + } + + if (gst_riff_fourcc_to_id (GST_BUFFER_DATA (buf)) != GST_RIFF_TAG_idx1) { + GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: no index found"); + return; + } + + index_size = GUINT32_FROM_LE(*(guint32 *)(GST_BUFFER_DATA (buf) + 4)); + + buf = gst_pad_pullregion(avi_demux->sinkpad, GST_REGION_OFFSET_LEN, offset+8, index_size); + + avi_demux->index_size = index_size/sizeof(gst_riff_index_entry); + + GST_INFO (GST_CAT_PLUGIN_INFO, "avidemux: index size %lu", avi_demux->index_size); + + avi_demux->index_entries = g_malloc (GST_BUFFER_SIZE (buf)); + memcpy (avi_demux->index_entries, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf)); + + buf = gst_pad_pullregion(avi_demux->sinkpad, GST_REGION_OFFSET_LEN, avi_demux->index_offset, 0); +} + +static inline gboolean +gst_avidemux_read_chunk (GstByteStream *bs, guint32 *id, guint32 *size) +{ + gst_riff_chunk *chunk; + + chunk = (gst_riff_chunk *) gst_bytestream_peek_bytes (bs, sizeof (gst_riff_chunk)); + if (chunk) { + *id = GUINT32_FROM_LE (chunk->id); + *size = GUINT32_FROM_LE (chunk->size); + + gst_bytestream_flush (bs, sizeof (gst_riff_chunk)); + + return TRUE; + } + return FALSE; +} + +static void +gst_avidemux_forall_pads (GstAviDemux *avi_demux, GFunc func, gpointer user_data) +{ + gint i; + GstPad *pad; + + for(i=0; i<GST_AVI_DEMUX_MAX_AUDIO_PADS; i++) { + pad = avi_demux->audio_pad[i]; + if (pad && GST_PAD_CONNECTED (pad)) { + (*func) (pad, user_data); + } + } + + for(i=0; i<GST_AVI_DEMUX_MAX_VIDEO_PADS; i++) { + pad = avi_demux->video_pad[i]; + if (pad && GST_PAD_CONNECTED (pad)) { + (*func) (pad, user_data); + } + } +} + +static void +gst_avidemux_queue_event_func (GstPad *pad, gpointer user_data) +{ + GstEventType type = GPOINTER_TO_INT (user_data); + + gst_pad_push (pad, GST_BUFFER (gst_event_new (type))); +} + +static gboolean +gst_avidemux_handle_event (GstAviDemux *avi_demux) +{ + guint32 remaining; + GstEvent *event; + GstEventType type; + + gst_bytestream_get_status (avi_demux->bs, &remaining, &event); + + type = event? GST_EVENT_TYPE (event) : GST_EVENT_UNKNOWN; + + switch (type) { + case GST_EVENT_EOS: + gst_element_set_state (GST_ELEMENT (avi_demux), GST_STATE_PAUSED); + g_warning ("eos event\n"); + gst_avidemux_forall_pads (avi_demux, (GFunc) gst_avidemux_queue_event_func, GINT_TO_POINTER (GST_EVENT_EOS)); + break; + case GST_EVENT_SEEK: + g_warning ("seek event\n"); + break; + case GST_EVENT_FLUSH: + g_warning ("flush event\n"); + break; + case GST_EVENT_DISCONTINUOUS: + g_warning ("discont event\n"); + break; + default: + g_warning ("unhandled event %d\n", type); + break; + } + + return TRUE; +} + +static gboolean +gst_avidemux_process_chunk (GstAviDemux *avi_demux, guint64 filepos, + guint32 desired_tag, + gint rec_depth, guint32 *chunksize) +{ + guint32 chunkid; + guint64 datapos; + GstByteStream *bs = avi_demux->bs; + + if (!gst_avidemux_read_chunk (bs, &chunkid, chunksize)) { + printf (" ***** Error reading chunk at filepos 0x%08llx\n", filepos); + return FALSE; + } + if (desired_tag) { /* do we have to test identity? */ + if (desired_tag != chunkid) { + printf ("\n\n *** Error: Expected chunk '%08x', found '%08x'\n", + desired_tag, chunkid); + return FALSE; + } + } + + GST_INFO (GST_CAT_PLUGIN_INFO, "chunkid %s, size %08x, filepos %08llx", + gst_riff_id_to_fourcc (chunkid), *chunksize, filepos); + + datapos = filepos + sizeof (guint32) + sizeof (guint32); + + switch (chunkid) { + case GST_RIFF_TAG_RIFF: + case GST_RIFF_TAG_LIST: + { + guint32 datashowed; + guint32 subchunksize; /* size of a read subchunk */ + + // flush the form type + if (!gst_bytestream_flush (bs, sizeof (guint32))) + return FALSE; + + datashowed = sizeof (guint32); /* we showed the form type */ + datapos += datashowed; /* for the rest of the routine */ + + while (datashowed < *chunksize) { /* while not showed all: */ + + guint32 subchunklen; /* complete size of a subchunk */ + + /* recurse for subchunks of RIFF and LIST chunks: */ + if (!gst_avidemux_process_chunk (avi_demux, datapos, 0, + rec_depth + 1, &subchunksize)) + return FALSE; + + subchunklen = sizeof (guint32) + sizeof (guint32) + ((subchunksize + 1) & ~1); + + datashowed += subchunklen; + datapos += subchunklen; + } + *chunksize -= datashowed; + 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_CAT_PLUGIN_INFO, "gst_avi_demux_chain: strh type %s not supported", gst_riff_id_to_fourcc (avi_demux->fcc_type)); + break; + } + break; + case GST_RIFF_00dc: + case GST_RIFF_00db: + case GST_RIFF_00__: + { + GST_DEBUG (0,"gst_avi_demux_chain: tag found %08x size %08x\n", + chunkid, *chunksize); + + if (GST_PAD_CONNECTED (avi_demux->video_pad[0])) { + GstBuffer *buf; + + if (*chunksize) { + buf = gst_bytestream_peek (bs, *chunksize); + } + else { + buf = gst_buffer_new (); + } + GST_BUFFER_TIMESTAMP (buf) = avi_demux->next_time; + avi_demux->next_time += avi_demux->time_interval; + + if (avi_demux->video_need_flush[0]) { + avi_demux->video_need_flush[0] = FALSE; + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLUSH); + } + + GST_DEBUG (0,"gst_avi_demux_chain: send video buffer %08x\n", *chunksize); + gst_pad_push(avi_demux->video_pad[0], buf); + GST_DEBUG (0,"gst_avi_demux_chain: sent video buffer %08x %p\n", + *chunksize, &avi_demux->video_pad[0]); + avi_demux->current_frame++; + } + *chunksize = (*chunksize + 1) & ~1; + break; + } + case GST_RIFF_01wb: + { + GST_DEBUG (0,"gst_avi_demux_chain: tag found %08x size %08x\n", + chunkid, *chunksize); + + if (GST_PAD_CONNECTED (avi_demux->audio_pad[0])) { + GstBuffer *buf; + + if (*chunksize) { + buf = gst_bytestream_peek (bs, *chunksize); + } + else { + buf = gst_buffer_new (); + } + + if (avi_demux->audio_need_flush[0]) { + GST_DEBUG (0,"audio flush\n"); + avi_demux->audio_need_flush[0] = FALSE; + GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLUSH); + } + + GST_DEBUG (0,"gst_avi_demux_chain: send audio buffer %08x\n", *chunksize); + gst_pad_push (avi_demux->audio_pad[0], buf); + GST_DEBUG (0,"gst_avi_demux_chain: sent audio buffer %08x\n", *chunksize); + } + *chunksize = (*chunksize + 1) & ~1; + break; + } + default: + printf (" ***** unknown chunkid %08x (%s)\n", chunkid, gst_riff_id_to_fourcc (chunkid)); + break; + } + GST_INFO (GST_CAT_PLUGIN_INFO, "chunkid %s, flush %08x, filepos %08llx", + gst_riff_id_to_fourcc (chunkid), *chunksize, filepos); + + if (!gst_bytestream_flush (bs, *chunksize)) { + return gst_avidemux_handle_event (avi_demux); + } + + return TRUE; +} + +static void +gst_avi_demux_loop (GstElement *element) +{ + GstAviDemux *avi_demux; + guint32 chunksize; + + g_return_if_fail (element != NULL); + g_return_if_fail (GST_IS_AVI_DEMUX (element)); + + avi_demux = GST_AVI_DEMUX (element); + + avi_demux->bs = gst_bytestream_new (avi_demux->sinkpad); + + do { + if (!gst_avidemux_process_chunk (avi_demux, 0, GST_RIFF_TAG_RIFF, 0, &chunksize)) { + GST_INFO (GST_CAT_PLUGIN_INFO, "sorry, isn't AVI"); + break; + } + } while (!GST_ELEMENT_IS_COTHREAD_STOPPING(element)); + + gst_bytestream_destroy (avi_demux->bs); +} + +static void +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); + + switch (prop_id) { + case ARG_BITRATE: + break; + case ARG_MEDIA_TIME: + g_value_set_long (value, (src->tot_frames * src->time_interval) / 1000000); + break; + case ARG_CURRENT_TIME: + g_value_set_long (value, (src->current_frame * src->time_interval) / 1000000); + break; + default: + break; + } +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + GstTypeFactory *type; + + /* this filter needs the riff parser */ + if (!gst_library_load ("gstbytestream")) { + gst_info("avidemux: could not load support library: 'gstbytestream'\n"); + return FALSE; + } + if (!gst_library_load ("gstriff")) { + gst_info("avidemux: could not load support library: 'gstriff'\n"); + return FALSE; + } + + /* create an elementfactory for the avi_demux element */ + factory = gst_elementfactory_new ("avidemux",GST_TYPE_AVI_DEMUX, + &gst_avi_demux_details); + g_return_val_if_fail (factory != NULL, FALSE); + + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_audio_templ)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_video_templ)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sink_templ)); + + type = gst_typefactory_new (&avidefinition); + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "avidemux", + plugin_init +}; + |