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 | |
parent | a2c423bbad0ef5dbc7698c2e27221594d296018d (diff) |
Initial revision
Original commit message from CVS:
Initial revision
Diffstat (limited to 'gst/avi')
-rw-r--r-- | gst/avi/.gitignore | 8 | ||||
-rw-r--r-- | gst/avi/Makefile.am | 31 | ||||
-rw-r--r-- | gst/avi/README | 72 | ||||
-rw-r--r-- | gst/avi/README_win32dll | 3 | ||||
-rw-r--r-- | gst/avi/audiocodecs.c | 189 | ||||
-rw-r--r-- | gst/avi/gstaviaudiodecoder.c | 195 | ||||
-rw-r--r-- | gst/avi/gstaviaudiodecoder.h | 65 | ||||
-rw-r--r-- | gst/avi/gstavidecoder.c | 367 | ||||
-rw-r--r-- | gst/avi/gstavidecoder.h | 67 | ||||
-rw-r--r-- | gst/avi/gstavidemux.c | 757 | ||||
-rw-r--r-- | gst/avi/gstavidemux.h | 109 | ||||
-rw-r--r-- | gst/avi/gstavimux.c | 376 | ||||
-rw-r--r-- | gst/avi/gstavimux.h | 93 | ||||
-rw-r--r-- | gst/avi/gstavitypes.c | 323 | ||||
-rw-r--r-- | gst/avi/gstavitypes.h | 65 |
15 files changed, 2720 insertions, 0 deletions
diff --git a/gst/avi/.gitignore b/gst/avi/.gitignore new file mode 100644 index 00000000..3df96ad8 --- /dev/null +++ b/gst/avi/.gitignore @@ -0,0 +1,8 @@ +Makefile +Makefile.in +*.o +*.lo +*.la +.deps +.libs +codectest diff --git a/gst/avi/Makefile.am b/gst/avi/Makefile.am new file mode 100644 index 00000000..16ef66e3 --- /dev/null +++ b/gst/avi/Makefile.am @@ -0,0 +1,31 @@ +if HAVE_AVIFILE +ARCHSUBDIRS = wincodec +else +ARCHSUBDIRS = +endif + +SUBDIRS = $(ARCHSUBDIRS) winaudio +DIST_SUBDIRS = wincodec winaudio + +filterdir = $(libdir)/gst + +filter_LTLIBRARIES = libgstavimux.la libgstavidecoder.la libgstavidemux.la libgstavitypes.la libgstaviaudiodecoder.la + +libgstavidemux_la_SOURCES = gstavidemux.c +libgstavitypes_la_SOURCES = gstavitypes.c +libgstavidecoder_la_SOURCES = gstavidecoder.c +libgstavimux_la_SOURCES = gstavimux.c +libgstaviaudiodecoder_la_SOURCES = gstaviaudiodecoder.c + +noinst_HEADERS = gstavidecoder.h gstavimux.h gstavitypes.h gstavidemux.h gstaviaudiodecoder.h + +#CFLAGS += -Wall -O3 -fomit-frame-pointer -funroll-all-loops -finline-functions -ffast-math -DNDEBUG +libgstavidecoder_la_CFLAGS = -O2 -ffast-math $(GST_CFLAGS) +libgstavidemux_la_CFLAGS = -O2 -ffast-math $(GST_CFLAGS) +libgstavitypes_la_CFLAGS = -O2 -ffast-math $(GST_CFLAGS) +libgstavimux_la_CFLAGS = -O2 -ffast-math $(GST_CFLAGS) +libgstaviaudiodecoder_la_CFLAGS = -O2 -ffast-math $(GST_CFLAGS) + +EXTRA_DIST = README_win32dll README + +noinst_HEADERS = aviaudiodecoder.h diff --git a/gst/avi/README b/gst/avi/README new file mode 100644 index 00000000..7ccd6206 --- /dev/null +++ b/gst/avi/README @@ -0,0 +1,72 @@ +The avi decoder plugins +----------------------- + +The avi decoder consists of a set of gstreamer plugins: + + - demuxer (avidemux) + - avi to gstreamer type converter (avitypes) + - windows dlls wrappers. + +the avidecoder element uses the above plugins to perform the avi +decoding. It is constructed as a custom bin which initially only has +the demuxer element in it. The demuxer has a set of padtemplates for +raw audio and video. + + (------------------------------------) + ! avidecoder ! + ! (video/raw)... + ! (----------) ! + ! ! demuxer (video/avi, auds).. ! + ! ! ! ! + ! -src ! ! + ! / ! (video/avi, vids).. ! + - src ! ! ! + ! (----------) (audio/raw)... + ! ! + (------------------------------------) + +the demuxer has a set of padtemplates for the raw avi header properties. + +The avi decoder will act on the new_pad signal of the demuxer element +and will attach an avitype plugin to the new pad. Caps negotiation will +convert the raw avi caps to the gstreamer caps. If the src pad of the +avitypes plugin are compatible with the avidecoder padtemplate, the +avitype pad is ghosted to the avidecoder bin, this is the case where no +codec is needed (for raw PCM samples, for example). + +When the avitypes caps are not compatible with one of the avidecoder +templates, a static autoplugger is used the find an element to connect +the demuxers pad to the decoders padtemplate. + +When no element could be found, an windec plugin is attached to the +demuxers pad and the avitypes plugin is removed from the decoder. + + +example: +-------- + + An avidecoder that has a video pad (decoded with windows dlls) and an + audio pad (raw PCM). + + (----------------------------------------------------------------) + ! avidecoder (--------) (------) ! + ! !avitypes! !windec! /-- (video/raw) + ! (----------) /-sink src--sink src ----- ! + ! !demuxer (video/avi, ! ! ! ! ! + ! ! ! auds).. (--------) (------) ! + ! -sink ! (--------) ! + ! / ! (video/avi, !avitypes! ! + -sink ! ! vids).. ! ! ! + ! (----------) \-sink src -------------------- (audio/raw) + ! (--------) ! + (----------------------------------------------------------------) + + + +TODO +---- + +automatically generate the padtemplates from all possible avi types +found in the registry. + + diff --git a/gst/avi/README_win32dll b/gst/avi/README_win32dll new file mode 100644 index 00000000..ed34a3bd --- /dev/null +++ b/gst/avi/README_win32dll @@ -0,0 +1,3 @@ +The current win32 dll loader don't work with all versions availble +out there. Make sure to get the windows dll where divxc32.dll has the date +older than 24 january 2000. The 24 january one does currently not work. diff --git a/gst/avi/audiocodecs.c b/gst/avi/audiocodecs.c new file mode 100644 index 00000000..9415055c --- /dev/null +++ b/gst/avi/audiocodecs.c @@ -0,0 +1,189 @@ +/* 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 DEBUG_ENABLED + + +#include <wine/winbase.h> +#include <wine/winerror.h> +#include <wine/driver.h> +#include <wine/msacm.h> +#define WIN32 +#include <gstavidecoder.h> + +typedef struct _GstWinLoaderAudioData GstWinLoaderAudioData; + +struct _GstWinLoaderAudioData { + guchar ext_info[64]; + WAVEFORMATEX wf; + HACMSTREAM srcstream; + GstPad *out; +}; + + +static GstPad *gst_avi_decoder_get_audio_srcpad_MPEG(GstAviDecoder *avi_decoder, guint pad_nr, GstPadTemplate *temp); +static GstPad *gst_avi_decoder_get_audio_srcpad_winloader(GstAviDecoder *avi_decoder, guint pad_nr, gst_riff_strf_auds *strf, GstPadTemplate *temp); +static void gst_avi_decoder_winloader_audio_chain(GstPad *pad, GstBuffer *buf); + +GstPad *gst_avi_decoder_get_audio_srcpad(GstAviDecoder *avi_decoder, guint pad_nr, gst_riff_strf_auds *strf, GstPadTemplate *temp) +{ + GstPad *newpad; + + switch (strf->format) { + case GST_RIFF_WAVE_FORMAT_PCM: + newpad = gst_pad_new("audio_00", GST_PAD_SRC); + gst_pad_set_caps (newpad, gst_caps_new ( + "avidecoder_caps", + "audio/raw", + gst_props_new ( + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_BOOLEAN (TRUE), + "width", GST_PROPS_INT ((gint)strf->size), + "depth", GST_PROPS_INT ((gint)strf->size), + "rate", GST_PROPS_INT ((gint)strf->rate), + "channels", GST_PROPS_INT ((gint)strf->channels), + NULL))); + + avi_decoder->audio_pad[pad_nr] = newpad; + return newpad; + case GST_RIFF_WAVE_FORMAT_MPEGL12: + case GST_RIFF_WAVE_FORMAT_MPEGL3: + return gst_avi_decoder_get_audio_srcpad_MPEG(avi_decoder, pad_nr, temp); + default: + newpad = gst_avi_decoder_get_audio_srcpad_winloader(avi_decoder, pad_nr, strf, temp); + if (newpad) return newpad; + printf("audio format %04x not supported\n", strf->format); + break; + } + return NULL; +} + +static GstPad *gst_avi_decoder_get_audio_srcpad_MPEG(GstAviDecoder *avi_decoder, guint pad_nr, GstPadTemplate *temp) +{ + GstElement *parse_audio, *decode; + GstPad *srcpad, *sinkpad, *newpad; + + parse_audio = gst_elementfactory_make("mp3parse", "parse_audio"); + g_return_val_if_fail(parse_audio != NULL, NULL); + decode = gst_elementfactory_make("mpg123", "decode_audio"); + g_return_val_if_fail(decode != NULL, NULL); + + gst_element_set_state(GST_ELEMENT(gst_object_get_parent(GST_OBJECT(avi_decoder))), GST_STATE_PAUSED); + + gst_bin_add(GST_BIN(gst_object_get_parent(GST_OBJECT(avi_decoder))), parse_audio); + gst_bin_add(GST_BIN(gst_object_get_parent(GST_OBJECT(avi_decoder))), decode); + + newpad = gst_pad_new("video", GST_PAD_SRC); + gst_pad_set_parent(newpad, GST_OBJECT(avi_decoder)); + + sinkpad = gst_element_get_pad(parse_audio,"sink"); + gst_pad_connect(gst_element_get_pad(parse_audio,"src"), + gst_element_get_pad(decode,"sink")); + gst_pad_set_chain_function (gst_element_get_pad(parse_audio,"src"), + GST_RPAD_CHAINFUNC (gst_element_get_pad(decode,"sink"))); + srcpad = gst_element_get_pad(decode,"src"); + + gst_pad_connect(newpad, sinkpad); + gst_pad_set_name(srcpad, "audio_00"); + gst_pad_set_chain_function (newpad, GST_RPAD_CHAINFUNC (sinkpad)); + + avi_decoder->audio_pad[pad_nr] = newpad; + gst_element_set_state(GST_ELEMENT(gst_object_get_parent(GST_OBJECT(avi_decoder))), GST_STATE_PLAYING); + + return srcpad; +} + +static GstPad *gst_avi_decoder_get_audio_srcpad_winloader(GstAviDecoder *avi_decoder, guint pad_nr, gst_riff_strf_auds *strf, GstPadTemplate *temp) +{ + HRESULT h; + GstWinLoaderAudioData *data; + GstPad *sinkpad, *newpad; + + if (!gst_library_load("winloader")) { + gst_info("audiocodecs: could not load support library: 'winloader'\n"); + return NULL; + } + gst_info("audiocodecs: winloader loaded\n"); + + avi_decoder->extra_data = g_malloc0(sizeof(GstWinLoaderAudioData)); + + data = (GstWinLoaderAudioData *)avi_decoder->extra_data; + + memcpy(data->ext_info, strf, sizeof(WAVEFORMATEX)); + memset(data->ext_info+18, 0, 32); + + if (strf->rate == 0) + return NULL; + + data->wf.nChannels=strf->channels; + data->wf.nSamplesPerSec=strf->rate; + data->wf.nAvgBytesPerSec=2*data->wf.nSamplesPerSec*data->wf.nChannels; + data->wf.wFormatTag=strf->format; + data->wf.nBlockAlign=strf->blockalign; + data->wf.wBitsPerSample=strf->av_bps; + data->wf.cbSize=0; + + gst_info("audiocodecs: trying to open library %p\n", data); + h = acmStreamOpen( + &data->srcstream, + (HACMDRIVER)NULL, + (WAVEFORMATEX*)data->ext_info, + (WAVEFORMATEX*)&data->wf, + NULL, + 0, + 0, + 0); + + if(h != S_OK) + { + if(h == ACMERR_NOTPOSSIBLE) { + printf("audiocodecs:: Unappropriate audio format\n"); + } + printf("audiocodecs:: acmStreamOpen error\n"); + return NULL; + } + + newpad = gst_pad_new("audio", GST_PAD_SINK); + gst_pad_set_parent(newpad, GST_OBJECT(avi_decoder)); + gst_pad_set_chain_function(newpad, gst_avi_decoder_winloader_audio_chain); + + sinkpad = gst_pad_new("audio_00", GST_PAD_SRC); + gst_pad_set_parent(sinkpad, GST_OBJECT(avi_decoder)); + gst_pad_connect(newpad, sinkpad); + gst_pad_set_chain_function (newpad, GST_RPAD_CHAINFUNC (sinkpad)); + + //gst_pad_connect(newpad, sinkpad); + avi_decoder->audio_pad[pad_nr] = newpad; + + data->out = sinkpad; + + GST_DEBUG (0,"gst_avi_decoder: pads created\n"); + return sinkpad; +} + +static void gst_avi_decoder_winloader_audio_chain(GstPad *pad, GstBuffer *buf) +{ + + GST_DEBUG (0,"gst_avi_decoder: got buffer %08lx %p\n", *(gulong *)GST_BUFFER_DATA(buf), GST_BUFFER_DATA(buf)); + gst_buffer_unref(buf); +} diff --git a/gst/avi/gstaviaudiodecoder.c b/gst/avi/gstaviaudiodecoder.c new file mode 100644 index 00000000..0626774d --- /dev/null +++ b/gst/avi/gstaviaudiodecoder.c @@ -0,0 +1,195 @@ +/* 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 "gstaviaudiodecoder.h" + + + +/* elementfactory information */ +static GstElementDetails gst_avi_audio_decoder_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", +}; + +/* AviAudioDecoder signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + /* FILL ME */ +}; + +GST_PADTEMPLATE_FACTORY (sink_templ, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "avidecoder_sink", + "video/avi", + "format", GST_PROPS_STRING ("strf_auds") + ) +) + +GST_PADTEMPLATE_FACTORY (src_audio_templ, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "src_audio", + "audio/raw", + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_BOOLEAN (TRUE), + "width", GST_PROPS_INT (16), + "depth", GST_PROPS_INT (16), + "rate", GST_PROPS_INT_RANGE (11025, 44100), + "channels", GST_PROPS_INT_RANGE (1, 2) + ) +) + +static void gst_avi_audio_decoder_class_init (GstAviAudioDecoderClass *klass); +static void gst_avi_audio_decoder_init (GstAviAudioDecoder *avi_audio_decoder); + +static void gst_avi_audio_decoder_chain (GstPad *pad, GstBuffer *buf); + +static void gst_avi_audio_decoder_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + + + +static GstElementClass *parent_class = NULL; +//static guint gst_avi_audio_decoder_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_avi_audio_decoder_get_type(void) +{ + static GType avi_audio_decoder_type = 0; + + if (!avi_audio_decoder_type) { + static const GTypeInfo avi_audio_decoder_info = { + sizeof(GstAviAudioDecoderClass), + NULL, + NULL, + (GClassInitFunc)gst_avi_audio_decoder_class_init, + NULL, + NULL, + sizeof(GstAviAudioDecoder), + 0, + (GInstanceInitFunc)gst_avi_audio_decoder_init, + }; + avi_audio_decoder_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviAudioDecoder", &avi_audio_decoder_info, 0); + } + return avi_audio_decoder_type; +} + +static void +gst_avi_audio_decoder_class_init (GstAviAudioDecoderClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref (GST_TYPE_BIN); + + gobject_class->get_property = gst_avi_audio_decoder_get_property; +} + +static void +gst_avi_audio_decoder_init (GstAviAudioDecoder *avi_audio_decoder) +{ +} + +static void +gst_avi_audio_decoder_chain (GstPad *pad, + GstBuffer *buf) +{ + GstAviAudioDecoder *avi_audio_decoder; + guchar *data; + gulong size; + + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_PAD(pad)); + g_return_if_fail (buf != NULL); + g_return_if_fail (GST_BUFFER_DATA(buf) != NULL); + + avi_audio_decoder = GST_AVI_AUDIO_DECODER (gst_pad_get_parent (pad)); + GST_DEBUG (0,"gst_avi_audio_decoder_chain: got buffer in %u\n", GST_BUFFER_OFFSET (buf)); + g_print ("gst_avi_audio_decoder_chain: got buffer in %u\n", GST_BUFFER_OFFSET (buf)); + data = (guchar *)GST_BUFFER_DATA (buf); + size = GST_BUFFER_SIZE (buf); + + gst_buffer_unref (buf); +} + +static void +gst_avi_audio_decoder_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstAviAudioDecoder *src; + + g_return_if_fail (GST_IS_AVI_AUDIO_DECODER (object)); + + src = GST_AVI_AUDIO_DECODER (object); + + switch(prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + /* create an elementfactory for the avi_audio_decoder element */ + factory = gst_elementfactory_new ("aviaudiodecoder",GST_TYPE_AVI_AUDIO_DECODER, + &gst_avi_audio_decoder_details); + g_return_val_if_fail (factory != NULL, FALSE); + + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sink_templ)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_audio_templ)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "aviaudiodecoder", + plugin_init +}; + diff --git a/gst/avi/gstaviaudiodecoder.h b/gst/avi/gstaviaudiodecoder.h new file mode 100644 index 00000000..0f98c236 --- /dev/null +++ b/gst/avi/gstaviaudiodecoder.h @@ -0,0 +1,65 @@ +/* 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. + */ + + +#ifndef __GST_AVI_AUDIO_DECODER_H__ +#define __GST_AVI_AUDIO_DECODER_H__ + + +#include <config.h> +#include <gst/gst.h> +#include <libs/riff/gstriff.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GST_TYPE_AVI_AUDIO_DECODER \ + (gst_avi_audio_decoder_get_type()) +#define GST_AVI_AUDIO_DECODER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVI_AUDIO_DECODER,GstAviAudioDecoder)) +#define GST_AVI_AUDIO_DECODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVI_AUDIO_DECODER,GstAviAudioDecoder)) +#define GST_IS_AVI_AUDIO_DECODER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVI_AUDIO_DECODER)) +#define GST_IS_AVI_AUDIO_DECODER_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVI_AUDIO_DECODER)) + + +typedef struct _GstAviAudioDecoder GstAviAudioDecoder; +typedef struct _GstAviAudioDecoderClass GstAviAudioDecoderClass; + +struct _GstAviAudioDecoder { + GstBin bin; + +}; + +struct _GstAviAudioDecoderClass { + GstBinClass parent_class; +}; + +GType gst_avi_audio_decoder_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_AVI_AUDIO_DECODER_H__ */ diff --git a/gst/avi/gstavidecoder.c b/gst/avi/gstavidecoder.c new file mode 100644 index 00000000..e9210a75 --- /dev/null +++ b/gst/avi/gstavidecoder.c @@ -0,0 +1,367 @@ +/* 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 "gstavidecoder.h" + + + +/* elementfactory information */ +static GstElementDetails gst_avi_decoder_details = { + ".avi decoder", + "Decoder/Video", + "Decodes 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 = { + "avidecoder_video/avi", + "video/avi", + ".avi", + avi_typefind, +}; + +/* AviDecoder 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 ( + "avidecoder_sink", + "video/avi", + NULL + ) +) + +GST_PADTEMPLATE_FACTORY (src_video_templ, + "video_src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "wincodec_src", + "video/raw", + "format", GST_PROPS_LIST ( + GST_PROPS_FOURCC (GST_MAKE_FOURCC ('Y','U','Y','2')), + GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')), + GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R','G','B',' ')) + ), + "width", GST_PROPS_INT_RANGE (16, 4096), + "height", GST_PROPS_INT_RANGE (16, 4096) + ) +) + +GST_PADTEMPLATE_FACTORY (src_audio_templ, + "audio_src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "src_audio", + "audio/raw", + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_LIST ( + GST_PROPS_BOOLEAN (TRUE), + GST_PROPS_BOOLEAN (FALSE) + ), + "width", GST_PROPS_LIST ( + GST_PROPS_INT (8), + GST_PROPS_INT (16) + ), + "depth", GST_PROPS_LIST ( + GST_PROPS_INT (8), + GST_PROPS_INT (16) + ), + "rate", GST_PROPS_INT_RANGE (11025, 48000), + "channels", GST_PROPS_INT_RANGE (1, 2) + ) +) + +static void gst_avi_decoder_class_init (GstAviDecoderClass *klass); +static void gst_avi_decoder_init (GstAviDecoder *avi_decoder); + +static void gst_avi_decoder_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + + + +static GstElementClass *parent_class = NULL; +//static guint gst_avi_decoder_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_avi_decoder_get_type(void) +{ + static GType avi_decoder_type = 0; + + if (!avi_decoder_type) { + static const GTypeInfo avi_decoder_info = { + sizeof(GstAviDecoderClass), + NULL, + NULL, + (GClassInitFunc)gst_avi_decoder_class_init, + NULL, + NULL, + sizeof(GstAviDecoder), + 0, + (GInstanceInitFunc)gst_avi_decoder_init, + }; + avi_decoder_type = g_type_register_static(GST_TYPE_BIN, "GstAviDecoder", &avi_decoder_info, 0); + } + return avi_decoder_type; +} + +static void +gst_avi_decoder_class_init (GstAviDecoderClass *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_BIN); + + gobject_class->get_property = gst_avi_decoder_get_property; +} + +static void +gst_avi_decoder_new_pad (GstElement *element, GstPad *pad, GstAviDecoder *avi_decoder) +{ + GstCaps *caps; + GstCaps *targetcaps = NULL; + const gchar *format; + gboolean type_found; + GstElement *type; + GstElement *new_element = NULL; + gchar *padname = NULL; + gchar *gpadname = NULL; +#define AVI_TYPE_VIDEO 1 +#define AVI_TYPE_AUDIO 2 + gint media_type = 0; + + GST_DEBUG (0, "avidecoder: new pad for element \"%s\"\n", gst_element_get_name (element)); + + caps = gst_pad_get_caps (pad); + format = gst_caps_get_string (caps, "format"); + + if (!strcmp (format, "strf_vids")) { + targetcaps = gst_padtemplate_get_caps (GST_PADTEMPLATE_GET (src_video_templ)); + media_type = AVI_TYPE_VIDEO; + gpadname = g_strdup_printf ("video_%02d", avi_decoder->count); + } + else if (!strcmp (format, "strf_auds")) { + targetcaps = gst_padtemplate_get_caps (GST_PADTEMPLATE_GET (src_audio_templ)); + media_type = AVI_TYPE_AUDIO; + gpadname = g_strdup_printf ("audio_%02d", avi_decoder->count); + } + else if (!strcmp (format, "strf_iavs")) { + targetcaps = gst_padtemplate_get_caps (GST_PADTEMPLATE_GET (src_video_templ)); + media_type = AVI_TYPE_VIDEO; + gpadname = g_strdup_printf ("video_%02d", avi_decoder->count); + } + else { + g_assert_not_reached (); + } + + gst_element_set_state (GST_ELEMENT (avi_decoder), GST_STATE_PAUSED); + + type = gst_elementfactory_make ("avitypes", + g_strdup_printf ("typeconvert%d", avi_decoder->count)); + + gst_pad_connect (pad, gst_element_get_pad (type, "sink")); + type_found = gst_util_get_bool_arg (G_OBJECT (type), "type_found"); + + if (type_found) { + + gst_bin_add (GST_BIN (avi_decoder), type); + + pad = gst_element_get_pad (type, "src"); + caps = gst_pad_get_caps (pad); + + if (gst_caps_check_compatibility (caps, targetcaps)) { + gst_element_add_ghost_pad (GST_ELEMENT (avi_decoder), + gst_element_get_pad (type, "src"), gpadname); + + avi_decoder->count++; + goto done; + } +#ifndef GST_DISABLE_AUTOPLUG + else { + GstAutoplug *autoplug; + autoplug = gst_autoplugfactory_make("static"); + + new_element = gst_autoplug_to_caps (autoplug, caps, targetcaps, NULL); + + padname = "src_00"; + } +#endif // GST_DISABLE_AUTOPLUG + } + + if (!new_element && (media_type == AVI_TYPE_VIDEO)) { + gst_pad_disconnect (pad, gst_element_get_pad (type, "sink")); + + new_element = gst_elementfactory_make ("windec", "decoder"); + + padname = "src"; + } + else if (!new_element && (media_type == AVI_TYPE_AUDIO)) { + //FIXME + padname = "src"; + } + + if (new_element) { + gst_pad_connect (pad, gst_element_get_pad (new_element, "sink")); + gst_element_set_name (new_element, g_strdup_printf ("element%d", avi_decoder->count)); + gst_bin_add (GST_BIN (avi_decoder), new_element); + + gst_element_add_ghost_pad (GST_ELEMENT (avi_decoder), + gst_element_get_pad (new_element, padname), gpadname); + + avi_decoder->count++; + } + else { + g_warning ("avidecoder: could not autoplug\n"); + } + +done: + gst_element_set_state (GST_ELEMENT (avi_decoder), GST_STATE_PLAYING); +} + +static void +gst_avi_decoder_init (GstAviDecoder *avi_decoder) +{ + avi_decoder->demuxer = gst_elementfactory_make ("avidemux", "demux"); + + if (avi_decoder->demuxer) { + gst_bin_add (GST_BIN (avi_decoder), avi_decoder->demuxer); + + gst_element_add_ghost_pad (GST_ELEMENT (avi_decoder), + gst_element_get_pad (avi_decoder->demuxer, "sink"), "sink"); + + g_signal_connect (G_OBJECT (avi_decoder->demuxer),"new_pad", G_CALLBACK (gst_avi_decoder_new_pad), + avi_decoder); + } + else { + g_warning ("wow!, no avi demuxer found. help me\n"); + } + + avi_decoder->count = 0; +} + +static GstCaps* +avi_typefind (GstBuffer *buf, + gpointer private) +{ + gchar *data = GST_BUFFER_DATA (buf); + GstCaps *new; + + GST_DEBUG (0,"avi_decoder: typefind\n"); + if (strncmp (&data[0], "RIFF", 4)) return NULL; + if (strncmp (&data[8], "AVI ", 4)) return NULL; + + new = gst_caps_new ("avi_typefind","video/avi", NULL); + + return new; +} + +static void +gst_avi_decoder_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstAviDecoder *src; + + g_return_if_fail (GST_IS_AVI_DECODER (object)); + + src = GST_AVI_DECODER (object); + + switch(prop_id) { + case ARG_BITRATE: + break; + case ARG_MEDIA_TIME: + g_value_set_long (value, gst_util_get_long_arg (G_OBJECT (src->demuxer), "media_time")); + break; + case ARG_CURRENT_TIME: + g_value_set_long (value, gst_util_get_long_arg (G_OBJECT (src->demuxer), "current_time")); + break; + default: + break; + } +} + + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + GstTypeFactory *type; + + /* create an elementfactory for the avi_decoder element */ + factory = gst_elementfactory_new ("avidecoder", GST_TYPE_AVI_DECODER, + &gst_avi_decoder_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, + "avidecoder", + plugin_init +}; + diff --git a/gst/avi/gstavidecoder.h b/gst/avi/gstavidecoder.h new file mode 100644 index 00000000..bd18c5c4 --- /dev/null +++ b/gst/avi/gstavidecoder.h @@ -0,0 +1,67 @@ +/* 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. + */ + + +#ifndef __GST_AVI_DECODER_H__ +#define __GST_AVI_DECODER_H__ + + +#include <config.h> +#include <gst/gst.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_AVI_DECODER \ + (gst_avi_decoder_get_type()) +#define GST_AVI_DECODER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVI_DECODER,GstAviDecoder)) +#define GST_AVI_DECODER_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVI_DECODER,GstAviDecoder)) +#define GST_IS_AVI_DECODER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVI_DECODER)) +#define GST_IS_AVI_DECODER_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVI_DECODER)) + + +typedef struct _GstAviDecoder GstAviDecoder; +typedef struct _GstAviDecoderClass GstAviDecoderClass; + +struct _GstAviDecoder { + GstBin element; + + GstElement *demuxer; + + gint count; +}; + +struct _GstAviDecoderClass { + GstBinClass parent_class; +}; + +GType gst_avi_decoder_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_AVI_DECODER_H__ */ 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 +}; + diff --git a/gst/avi/gstavidemux.h b/gst/avi/gstavidemux.h new file mode 100644 index 00000000..d06172be --- /dev/null +++ b/gst/avi/gstavidemux.h @@ -0,0 +1,109 @@ +/* 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. + */ + + +#ifndef __GST_AVI_DEMUX_H__ +#define __GST_AVI_DEMUX_H__ + + +#include <config.h> +#include <gst/gst.h> +#include <libs/riff/gstriff.h> +#include <libs/bytestream/gstbytestream.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GST_TYPE_AVI_DEMUX \ + (gst_avi_demux_get_type()) +#define GST_AVI_DEMUX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVI_DEMUX,GstAviDemux)) +#define GST_AVI_DEMUX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVI_DEMUX,GstAviDemux)) +#define GST_IS_AVI_DEMUX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVI_DEMUX)) +#define GST_IS_AVI_DEMUX_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVI_DEMUX)) + + +#define GST_AVI_DEMUX_UNKNOWN 0 /* initialized state */ +#define GST_AVI_DEMUX_REGULAR 1 /* regular parsing */ +#define GST_AVI_DEMUX_HDRL 2 +#define GST_AVI_DEMUX_STRL 3 +#define GST_AVI_DEMUX_MOVI 4 +#define GST_AVI_DEMUX_AVIH 5 +#define GST_AVI_DEMUX_STRH_VIDS 6 +#define GST_AVI_DEMUX_STRH_AUDS 7 +#define GST_AVI_DEMUX_STRH_IAVS 8 + +#define GST_AVI_DEMUX_MAX_AUDIO_PADS 8 +#define GST_AVI_DEMUX_MAX_VIDEO_PADS 8 + +typedef struct _GstAviDemux GstAviDemux; +typedef struct _GstAviDemuxClass GstAviDemuxClass; + +struct _GstAviDemux { + GstElement element; + + /* pads */ + GstPad *sinkpad,*srcpad; + + /* AVI decoding state */ + gint state; + guint32 fcc_type; + + GstByteStream *bs; + + gst_riff_index_entry *index_entries; + gulong index_size; + gulong index_offset; + gulong resync_offset; + + guint64 next_time; + guint64 time_interval; + gulong tot_frames; + gulong current_frame; + + guint32 flags; + + guint num_audio_pads; + guint num_video_pads; + guint num_iavs_pads; + GstPad *audio_pad[GST_AVI_DEMUX_MAX_AUDIO_PADS]; + gboolean audio_need_flush[GST_AVI_DEMUX_MAX_AUDIO_PADS]; + + GstPad *video_pad[GST_AVI_DEMUX_MAX_VIDEO_PADS]; + gboolean video_need_flush[GST_AVI_DEMUX_MAX_VIDEO_PADS]; + + gpointer extra_data; +}; + +struct _GstAviDemuxClass { + GstElementClass parent_class; +}; + +GType gst_avi_demux_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_AVI_DEMUX_H__ */ diff --git a/gst/avi/gstavimux.c b/gst/avi/gstavimux.c new file mode 100644 index 00000000..c7e81019 --- /dev/null +++ b/gst/avi/gstavimux.c @@ -0,0 +1,376 @@ +/* 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. + */ + + + +#include <stdlib.h> +#include <string.h> + +#include "gstavimux.h" + + + +/* elementfactory information */ +static GstElementDetails +gst_avimux_details = +{ + ".avi mux", + "Mux/Video", + "Encodes audio and video into an avi stream", + VERSION, + "Wim Taymans <wim.taymans@chello.be>", + "(C) 2000", +}; + +/* AviMux signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + /* FILL ME */ +}; + +GST_PADTEMPLATE_FACTORY (src_factory, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "sink_video", + "video/avi", + NULL + ) +) + +GST_PADTEMPLATE_FACTORY (video_sink_factory, + "video_%02d", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_CAPS_NEW ( + "sink_video", + "video/avi", + "format", GST_PROPS_STRING ("strf_vids") + ) +) + +GST_PADTEMPLATE_FACTORY (audio_sink_factory, + "audio_%02d", + GST_PAD_SINK, + GST_PAD_REQUEST, + GST_CAPS_NEW ( + "sink_audio", + "video/avi", + "format", GST_PROPS_STRING ("strf_auds") + ) +) + + +static void gst_avimux_class_init (GstAviMuxClass *klass); +static void gst_avimux_init (GstAviMux *avimux); + +static void gst_avimux_chain (GstPad *pad, GstBuffer *buf); +static GstPad* gst_avimux_request_new_pad (GstElement *element, GstPadTemplate *templ, const gchar *name); + +static void gst_avimux_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void gst_avimux_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + + +static GstElementClass *parent_class = NULL; +//static guint gst_avimux_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_avimux_get_type (void) +{ + static GType avimux_type = 0; + + if (!avimux_type) { + static const GTypeInfo avimux_info = { + sizeof(GstAviMuxClass), + NULL, + NULL, + (GClassInitFunc)gst_avimux_class_init, + NULL, + NULL, + sizeof(GstAviMux), + 0, + (GInstanceInitFunc)gst_avimux_init, + }; + avimux_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviMux", &avimux_info, 0); + } + return avimux_type; +} + +static void +gst_avimux_class_init (GstAviMuxClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + gobject_class->set_property = gst_avimux_set_property; + gobject_class->get_property = gst_avimux_get_property; + + gstelement_class->request_new_pad = gst_avimux_request_new_pad; +} + +static void +gst_avimux_init (GstAviMux *avimux) +{ + avimux->srcpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (src_factory), "src"); + gst_element_add_pad (GST_ELEMENT (avimux), avimux->srcpad); + + avimux->state = GST_AVIMUX_INITIAL; + avimux->riff = NULL; + avimux->num_audio_pads = 0; + avimux->num_video_pads = 0; + avimux->next_time = 0; + + avimux->riff = gst_riff_encoder_new (GST_RIFF_RIFF_AVI); + avimux->aviheader = g_malloc0 (sizeof (gst_riff_avih)); +} + +static void +gst_avimux_newcaps (GstPad *pad, GstCaps *caps) +{ + GstAviMux *avimux; + const gchar* format = gst_caps_get_string (caps, "format"); + gint padnum = GPOINTER_TO_INT (gst_pad_get_element_private (pad)); + + avimux = GST_AVIMUX (gst_pad_get_parent (pad)); + + GST_DEBUG (0, "avimux: newcaps triggered on %s (%d), %s\n", gst_pad_get_name (pad), + padnum, format); + + if (!strncmp (format, "strf_vids", 9)) { + gst_riff_strf_vids *strf_vids = g_malloc(sizeof(gst_riff_strf_vids)); + + strf_vids->size = sizeof(gst_riff_strf_vids); + strf_vids->width = gst_caps_get_int (caps, "width"); + strf_vids->height = gst_caps_get_int (caps, "height");; + strf_vids->planes = gst_caps_get_int (caps, "planes");; + strf_vids->bit_cnt = gst_caps_get_int (caps, "bit_cnt");; + strf_vids->compression = gst_caps_get_fourcc_int (caps, "compression");; + strf_vids->image_size = gst_caps_get_int (caps, "image_size");; + strf_vids->xpels_meter = gst_caps_get_int (caps, "xpels_meter");; + strf_vids->ypels_meter = gst_caps_get_int (caps, "ypels_meter");; + strf_vids->num_colors = gst_caps_get_int (caps, "num_colors");; + strf_vids->imp_colors = gst_caps_get_int (caps, "imp_colors");; + + avimux->video_header[padnum] = strf_vids; + } + else if (!strncmp (format, "strf_auds", 9)) { + + } +} + +static GstPad* +gst_avimux_request_new_pad (GstElement *element, + GstPadTemplate *templ, + const gchar *req_name) +{ + GstAviMux *avimux; + gchar *name = NULL; + GstPad *newpad; + + g_return_val_if_fail (templ != NULL, NULL); + + if (templ->direction != GST_PAD_SINK) { + g_warning ("avimux: request pad that is not a SINK pad\n"); + return NULL; + } + + g_return_val_if_fail (GST_IS_AVIMUX (element), NULL); + + avimux = GST_AVIMUX (element); + + if (templ == GST_PADTEMPLATE_GET (audio_sink_factory)) { + name = g_strdup_printf ("audio_%02d", avimux->num_audio_pads); + newpad = gst_pad_new_from_template (templ, name); + gst_pad_set_element_private (newpad, GINT_TO_POINTER (avimux->num_audio_pads)); + + avimux->audio_pad[avimux->num_audio_pads] = newpad; + avimux->num_audio_pads++; + } + else if (templ == GST_PADTEMPLATE_GET (video_sink_factory)) { + name = g_strdup_printf ("video_%02d", avimux->num_video_pads); + newpad = gst_pad_new_from_template (templ, name); + gst_pad_set_element_private (newpad, GINT_TO_POINTER (avimux->num_video_pads)); + + avimux->video_pad[avimux->num_video_pads] = newpad; + avimux->num_video_pads++; + } + else { + g_warning ("avimux: this is not our template!\n"); + return NULL; + } + + gst_pad_set_chain_function (newpad, gst_avimux_chain); + gst_pad_set_newcaps_function (newpad, gst_avimux_newcaps); + gst_element_add_pad (element, newpad); + + return newpad; +} + +static void +gst_avimux_make_header (GstAviMux *avimux) +{ + gint i; + + gst_riff_strh strh; + + avimux->aviheader->us_frame = 40000; + avimux->aviheader->streams = avimux->num_video_pads + avimux->num_audio_pads; + avimux->aviheader->width = -1; + avimux->aviheader->height = -1; + gst_riff_encoder_avih(avimux->riff, avimux->aviheader, sizeof(gst_riff_avih)); + + memset(&strh, 0, sizeof(gst_riff_strh)); + strh.scale = 40000; + + gst_riff_encoder_strh(avimux->riff, GST_RIFF_FCC_vids, &strh, sizeof(gst_riff_strh)); + + for (i=0; i<avimux->num_video_pads; i++) { + gst_riff_encoder_strf(avimux->riff, avimux->video_header[i], sizeof(gst_riff_strf_vids)); + } +} + +static void +gst_avimux_chain (GstPad *pad, GstBuffer *buf) +{ + GstAviMux *avimux; + guchar *data; + gulong size; + const gchar *padname; + gint channel; + GstBuffer *newbuf; + + g_return_if_fail (pad != NULL); + g_return_if_fail (GST_IS_PAD (pad)); + g_return_if_fail (buf != NULL); + g_return_if_fail (GST_BUFFER_DATA (buf) != NULL); + + avimux = GST_AVIMUX (gst_pad_get_parent (pad)); + + data = (guchar *)GST_BUFFER_DATA(buf); + size = GST_BUFFER_SIZE(buf); + + switch(avimux->state) { + case GST_AVIMUX_INITIAL: + GST_DEBUG (0,"gst_avimux_chain: writing header\n"); + gst_avimux_make_header(avimux); + newbuf = gst_riff_encoder_get_and_reset_buffer(avimux->riff); + gst_pad_push(avimux->srcpad, newbuf); + avimux->state = GST_AVIMUX_MOVI; + case GST_AVIMUX_MOVI: + padname = gst_pad_get_name (pad); + channel = GPOINTER_TO_INT (gst_pad_get_element_private (pad)); + + if (strncmp(padname, "audio_", 6) == 0) { + GST_DEBUG (0,"gst_avimux_chain: got audio buffer in from channel %02d %lu\n", channel, size); + gst_riff_encoder_chunk(avimux->riff, GST_RIFF_01wb, NULL, size); + newbuf = gst_riff_encoder_get_and_reset_buffer(avimux->riff); + gst_pad_push(avimux->srcpad, newbuf); + } + else if (strncmp(padname, "video_", 6) == 0) { + GST_DEBUG (0,"gst_avimux_chain: got video buffer in from channel %02d %lu\n", channel, size); + gst_riff_encoder_chunk(avimux->riff, GST_RIFF_00db, NULL, size); + newbuf = gst_riff_encoder_get_and_reset_buffer(avimux->riff); + GST_DEBUG (0,"gst_avimux_chain: encoded %u\n", GST_BUFFER_SIZE(newbuf)); + gst_pad_push(avimux->srcpad, newbuf); + } + GST_BUFFER_SIZE(buf) = (GST_BUFFER_SIZE(buf)+1)&~1; + gst_pad_push(avimux->srcpad, buf); + break; + default: + break; + } + + //gst_buffer_unref(buf); +} + +static void +gst_avimux_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + GstAviMux *src; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_AVIMUX(object)); + src = GST_AVIMUX(object); + + switch(prop_id) { + default: + break; + } +} + +static void +gst_avimux_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstAviMux *src; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail(GST_IS_AVIMUX(object)); + src = GST_AVIMUX(object); + + switch(prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + /* this filter needs the riff parser */ + if (!gst_library_load ("gstriff")) { + gst_info ("avimux: could not load support library: 'gstriff'\n"); + return FALSE; + } + + /* create an elementfactory for the avimux element */ + factory = gst_elementfactory_new ("avimux", GST_TYPE_AVIMUX, + &gst_avimux_details); + g_return_val_if_fail (factory != NULL, FALSE); + + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_factory)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (audio_sink_factory)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (video_sink_factory)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "avimux", + plugin_init +}; + diff --git a/gst/avi/gstavimux.h b/gst/avi/gstavimux.h new file mode 100644 index 00000000..9de56941 --- /dev/null +++ b/gst/avi/gstavimux.h @@ -0,0 +1,93 @@ +/* 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. + */ + + +#ifndef __GST_AVIMUX_H__ +#define __GST_AVIMUX_H__ + + +#include <config.h> +#include <gst/gst.h> +#include <libs/riff/gstriff.h> + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_AVIMUX \ + (gst_avimux_get_type()) +#define GST_AVIMUX(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVIMUX,GstAviMux)) +#define GST_AVIMUX_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVIMUX,GstAviMux)) +#define GST_IS_AVIMUX(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVIMUX)) +#define GST_IS_AVIMUX_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVIMUX)) + + +#define GST_AVIMUX_INITIAL 0 /* initialized state */ +#define GST_AVIMUX_MOVI 1 /* encoding movi */ + +#define GST_AVIMUX_MAX_AUDIO_PADS 8 +#define GST_AVIMUX_MAX_VIDEO_PADS 8 + +typedef struct _GstAviMux GstAviMux; +typedef struct _GstAviMuxClass GstAviMuxClass; + +struct _GstAviMux { + GstElement element; + + /* pads */ + GstPad *srcpad; + + /* AVI encoding state */ + gint state; + + /* RIFF encoding state */ + GstRiff *riff; + + guint64 next_time; + guint64 time_interval; + + gst_riff_avih *aviheader; /* the avi header */ + guint num_audio_pads; + guint num_video_pads; + + GstPad *audio_pad[GST_AVIMUX_MAX_AUDIO_PADS]; + gst_riff_strf_auds *audio_header[GST_AVIMUX_MAX_AUDIO_PADS]; + + GstPad *video_pad[GST_AVIMUX_MAX_VIDEO_PADS]; + gst_riff_strf_vids *video_header[GST_AVIMUX_MAX_VIDEO_PADS]; +}; + +struct _GstAviMuxClass { + GstElementClass parent_class; +}; + +GType gst_avimux_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_AVIMUX_H__ */ diff --git a/gst/avi/gstavitypes.c b/gst/avi/gstavitypes.c new file mode 100644 index 00000000..b43f2a0c --- /dev/null +++ b/gst/avi/gstavitypes.c @@ -0,0 +1,323 @@ +/* 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 "gstavitypes.h" + + + +/* elementfactory information */ +static GstElementDetails gst_avi_types_details = { + "avi type converter", + "Decoder/Video", + "Converts avi types into gstreamer types", + VERSION, + "Wim Taymans <wim.taymans@tvd.be>", + "(C) 1999", +}; + +/* AviTypes signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, + ARG_TYPE_FOUND, + /* FILL ME */ +}; + +GST_PADTEMPLATE_FACTORY (sink_templ, + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "avitypes_sink", + "video/avi", + "format", GST_PROPS_LIST ( + GST_PROPS_STRING ("strf_vids"), + GST_PROPS_STRING ("strf_auds"), + GST_PROPS_STRING ("strf_iavs") + ) + ) +) + +GST_PADTEMPLATE_FACTORY (src_templ, + "video_src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "avitypes_src", + "video/raw", + "format", GST_PROPS_LIST ( + GST_PROPS_FOURCC (GST_MAKE_FOURCC ('Y','U','Y','2')), + GST_PROPS_FOURCC (GST_MAKE_FOURCC ('R','G','B',' ')) + ), + "width", GST_PROPS_INT_RANGE (16, 4096), + "height", GST_PROPS_INT_RANGE (16, 4096) + ), + GST_CAPS_NEW ( + "avitypes_src", + "video/avi", + "format", GST_PROPS_STRING ("strf_vids") + ), + GST_CAPS_NEW ( + "src_audio", + "audio/raw", + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_LIST ( + GST_PROPS_BOOLEAN (TRUE), + GST_PROPS_BOOLEAN (FALSE) + ), + "width", GST_PROPS_LIST ( + GST_PROPS_INT (8), + GST_PROPS_INT (16) + ), + "depth", GST_PROPS_LIST ( + GST_PROPS_INT (8), + GST_PROPS_INT (16) + ), + "rate", GST_PROPS_INT_RANGE (11025, 44100), + "channels", GST_PROPS_INT_RANGE (1, 2) + ), + GST_CAPS_NEW ( + "src_audio", + "audio/mp3", + NULL + ), + GST_CAPS_NEW ( + "src_video", + "video/jpeg", + NULL + ), + GST_CAPS_NEW ( + "src_dv", + "video/dv", + NULL + ) +) + +static void gst_avi_types_class_init (GstAviTypesClass *klass); +static void gst_avi_types_init (GstAviTypes *avi_types); + +static void gst_avi_types_chain (GstPad *pad, GstBuffer *buffer); + +static void gst_avi_types_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); + + +static GstElementClass *parent_class = NULL; +//static guint gst_avi_types_signals[LAST_SIGNAL] = { 0 }; + +GType +gst_avi_types_get_type(void) +{ + static GType avi_types_type = 0; + + if (!avi_types_type) { + static const GTypeInfo avi_types_info = { + sizeof(GstAviTypesClass), + NULL, + NULL, + (GClassInitFunc)gst_avi_types_class_init, + NULL, + NULL, + sizeof(GstAviTypes), + 0, + (GInstanceInitFunc)gst_avi_types_init, + }; + avi_types_type = g_type_register_static(GST_TYPE_ELEMENT, "GstAviTypes", &avi_types_info, 0); + } + return avi_types_type; +} + +static void +gst_avi_types_class_init (GstAviTypesClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TYPE_FOUND, + g_param_spec_boolean ("type_found","type_found","type_found", + FALSE, G_PARAM_READABLE)); + + gobject_class->get_property = gst_avi_types_get_property; +} + +static void +gst_avi_types_newcaps (GstPad *pad, GstCaps *caps) +{ + GstAviTypes *avi_types; + const gchar *format; + GstCaps *newcaps = NULL; + + avi_types = GST_AVI_TYPES (gst_pad_get_parent (pad)); + + format = gst_caps_get_string (caps, "format"); + + if (!strcmp (format, "strf_vids")) { + gulong video_format = gst_caps_get_fourcc_int (caps, "compression"); + + switch (video_format) { + case GST_MAKE_FOURCC ('M','J','P','G'): + newcaps = gst_caps_new ("avi_type_mjpg", + "video/jpeg", NULL); + break; + case GST_MAKE_FOURCC ('d','v','s','d'): + newcaps = gst_caps_new ("avi_type_dv", + "video/dv", + gst_props_new ( + "format", GST_PROPS_STRING ("NTSC"), + NULL)); + default: + break; + } + } + else if (!strcmp (format, "strf_auds")) { + gint16 audio_format = gst_caps_get_int (caps, "fmt"); + gint blockalign = gst_caps_get_int (caps, "blockalign"); + gint size = gst_caps_get_int (caps, "size"); + gint channels = gst_caps_get_int (caps, "channels"); + gint rate = gst_caps_get_int (caps, "rate"); + gboolean sign = (size == 8 ? FALSE : TRUE); + + GST_DEBUG (GST_CAT_PLUGIN_INFO, "avitypes: new caps with audio format:%04x\n", audio_format); + + switch (audio_format) { + case 0x0001: + newcaps = gst_caps_new ("avi_type_pcm", + "audio/raw", + gst_props_new ( + "format", GST_PROPS_STRING ("int"), + "law", GST_PROPS_INT (0), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "signed", GST_PROPS_BOOLEAN (sign), + "width", GST_PROPS_INT ((blockalign*8)/channels), + "depth", GST_PROPS_INT (size), + "rate", GST_PROPS_INT (rate), + "channels", GST_PROPS_INT (channels), + NULL + )); + break; + case 0x0050: + case 0x0055: + newcaps = gst_caps_new ("avi_type_mp3", + "audio/mp3", NULL); + break; + default: + break; + } + } + else if (!strcmp (format, "strf_iavs")) { + newcaps = gst_caps_new ("avi_type_dv", + "video/dv", + gst_props_new ( + "format", GST_PROPS_STRING ("NTSC"), + NULL)); + } + + if (newcaps) { + gst_pad_set_caps (avi_types->srcpad, newcaps); + avi_types->type_found = TRUE; + } +} + +static void +gst_avi_types_init (GstAviTypes *avi_types) +{ + avi_types->sinkpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (sink_templ), "sink"); + gst_element_add_pad (GST_ELEMENT (avi_types), avi_types->sinkpad); + gst_pad_set_newcaps_function (avi_types->sinkpad, gst_avi_types_newcaps); + gst_pad_set_chain_function (avi_types->sinkpad, gst_avi_types_chain); + + avi_types->srcpad = gst_pad_new_from_template ( + GST_PADTEMPLATE_GET (src_templ), "src"); + gst_element_add_pad (GST_ELEMENT (avi_types), avi_types->srcpad); + + avi_types->type_found = FALSE; +} + +static void +gst_avi_types_chain (GstPad *pad, GstBuffer *buffer) +{ + GstAviTypes *avi_types; + + avi_types = GST_AVI_TYPES (gst_pad_get_parent (pad)); + + if (GST_PAD_CONNECTED (avi_types->srcpad)) + gst_pad_push (avi_types->srcpad, buffer); + else + gst_buffer_unref (buffer); +} + +static void +gst_avi_types_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + GstAviTypes *src; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_AVI_TYPES (object)); + + src = GST_AVI_TYPES (object); + + switch (prop_id) { + case ARG_TYPE_FOUND: + g_value_set_boolean (value, src->type_found); + break; + default: + break; + } +} + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + /* create an elementfactory for the avi_types element */ + factory = gst_elementfactory_new ("avitypes",GST_TYPE_AVI_TYPES, + &gst_avi_types_details); + g_return_val_if_fail (factory != NULL, FALSE); + + //gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (src_templ)); + gst_elementfactory_add_padtemplate (factory, GST_PADTEMPLATE_GET (sink_templ)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "avitypes", + plugin_init +}; + diff --git a/gst/avi/gstavitypes.h b/gst/avi/gstavitypes.h new file mode 100644 index 00000000..43136e64 --- /dev/null +++ b/gst/avi/gstavitypes.h @@ -0,0 +1,65 @@ +/* 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. + */ + + +#ifndef __GST_AVI_TYPES_H__ +#define __GST_AVI_TYPES_H__ + + +#include <config.h> +#include <gst/gst.h> + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define GST_TYPE_AVI_TYPES \ + (gst_avi_types_get_type()) +#define GST_AVI_TYPES(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVI_TYPES,GstAviTypes)) +#define GST_AVI_TYPES_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVI_TYPES,GstAviTypes)) +#define GST_IS_AVI_TYPES(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVI_TYPES)) +#define GST_IS_AVI_TYPES_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVI_TYPES)) + +typedef struct _GstAviTypes GstAviTypes; +typedef struct _GstAviTypesClass GstAviTypesClass; + +struct _GstAviTypes { + GstElement element; + + GstPad *srcpad, *sinkpad; + + gboolean type_found; +}; + +struct _GstAviTypesClass { + GstElementClass parent_class; +}; + +GType gst_avi_types_get_type (void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_AVI_TYPES_H__ */ |