From f6bfbdd2224fa6641779e28918952815b61bbf0c Mon Sep 17 00:00:00 2001 From: Iain Holmes Date: Mon, 21 Oct 2002 17:06:53 +0000 Subject: [PATCH] Added a WAV file encoder Original commit message from CVS: Added a WAV file encoder --- configure.ac | 3 +- gst/wavenc/Makefile.am | 10 ++ gst/wavenc/gstwavenc.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++ gst/wavenc/gstwavenc.h | 76 ++++++++++++ 4 files changed, 395 insertions(+), 1 deletion(-) create mode 100644 gst/wavenc/Makefile.am create mode 100644 gst/wavenc/gstwavenc.c create mode 100644 gst/wavenc/gstwavenc.h diff --git a/configure.ac b/configure.ac index b2eb048..8e920c8 100644 --- a/configure.ac +++ b/configure.ac @@ -218,7 +218,7 @@ GST_PLUGINS_ALL="\ monoscope passthrough playondemand qtdemux rtjpeg silence sine\ smooth spectrum speed stereo stereomono synaesthesia\ udp videocrop videoscale videotestsrc volenv volume\ - vumeter wavparse y4m" + vumeter wavenc wavparse y4m" dnl see if we can build C++ plug-ins if test "x$HAVE_CXX" = "xyes"; then @@ -977,6 +977,7 @@ gst/videocrop/Makefile gst/volenv/Makefile gst/volume/Makefile gst/vumeter/Makefile +gst/wavenc/Makefile gst/wavparse/Makefile gst/y4m/Makefile sys/Makefile diff --git a/gst/wavenc/Makefile.am b/gst/wavenc/Makefile.am new file mode 100644 index 0000000..bf61337 --- /dev/null +++ b/gst/wavenc/Makefile.am @@ -0,0 +1,10 @@ +plugindir = $(libdir)/gst + +plugin_LTLIBRARIES = libgstwavenc.la + +libgstwavenc_la_SOURCES = gstwavenc.c +libgstwavenc_la_CFLAGS = $(GST_CFLAGS) +libgstwavenc_la_LIBADD = +libgstwavenc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +noinst_HEADERS = gstwavenc.h diff --git a/gst/wavenc/gstwavenc.c b/gst/wavenc/gstwavenc.c new file mode 100644 index 0000000..dc0a86d --- /dev/null +++ b/gst/wavenc/gstwavenc.c @@ -0,0 +1,307 @@ +/* GStreamer + * Copyright (C) <2002> Iain Holmes + */ + +#include +#include + +static void gst_wavenc_class_init (GstWavEncClass *klass); +static void gst_wavenc_init (GstWavEnc *wavenc); +static void gst_wavenc_chain (GstPad *pad, GstBuffer *buf); + +#define WAVE_FORMAT_PCM 0x0001 + +#define WRITE_U32(buf, x) *(buf) = (unsigned char) (x&0xff);\ +*((buf)+1) = (unsigned char)((x>>8)&0xff);\ +*((buf)+2) = (unsigned char)((x>>16)&0xff);\ +*((buf)+3) = (unsigned char)((x>>24)&0xff); + +#define WRITE_U16(buf, x) *(buf) = (unsigned char) (x&0xff);\ +*((buf)+1) = (unsigned char)((x>>8)&0xff); + +struct riff_struct { + unsigned char id[4]; /* RIFF */ + unsigned int len; + unsigned char wav_id[4]; /* WAVE */ +}; + +struct chunk_struct { + unsigned char id[4]; + unsigned int len; +}; + +struct common_struct { + unsigned short wFormatTag; + unsigned short wChannels; + unsigned int dwSamplesPerSec; + unsigned int dwAvgBytesPerSec; + unsigned short wBlockAlign; + unsigned short wBitsPerSample; /* Only for PCM */ +}; + +struct wave_header { + struct riff_struct riff; + struct chunk_struct format; + struct common_struct common; + struct chunk_struct data; +}; + +static GstElementDetails gst_wavenc_details = { + "WAV encoder", + "Codec/Encoder", + "GPL", + "Encode raw audio into WAV", + VERSION, + "Iain Holmes ", + "(C) 2002", +}; + +static GstPadTemplate *srctemplate, *sinktemplate; + +static GstPadTemplate * +sink_factory (void) +{ + return gst_pad_template_new ("wavenc_sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + gst_caps_new ("wavenc_raw", + "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 (16), + "depth", GST_PROPS_INT (16), + "rate", GST_PROPS_INT_RANGE (8000, 48000), + "channels", GST_PROPS_INT_RANGE (1, 2), + NULL)), + NULL); +} + +static GstPadTemplate * +src_factory (void) +{ + return gst_pad_template_new ("wavenc_src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + gst_caps_new ("wavenc_wav", + "audio/x-wav", + NULL), + NULL); +} + +static GstElementClass *parent_class = NULL; + +GType +gst_wavenc_get_type (void) +{ + static GType type = 0; + + if (type == 0) { + static const GTypeInfo info = { + sizeof (GstWavEncClass), NULL, NULL, + (GClassInitFunc) gst_wavenc_class_init, NULL, NULL, + sizeof (GstWavEnc), 0, (GInstanceInitFunc) gst_wavenc_init + }; + + type = g_type_register_static (GST_TYPE_ELEMENT, "GstWavEnc", &info, 0); + } + + return type; +} + +static GstElementStateReturn +gst_wavenc_change_state (GstElement *element) +{ + GstWavEnc *wavenc = GST_WAVENC (element); + + switch (GST_STATE_TRANSITION (element)) { + case GST_STATE_NULL_TO_READY: + case GST_STATE_READY_TO_PAUSED: + wavenc->setup = FALSE; + break; + + default: + break; + } + + if (parent_class->change_state) { + return parent_class->change_state (element); + } + + return GST_STATE_SUCCESS; +} + +static void +gst_wavenc_class_init (GstWavEncClass *klass) +{ + GstElementClass *element_class; + + element_class = (GstElementClass *) klass; + element_class->change_state = gst_wavenc_change_state; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); +} + +static gboolean +gst_wavenc_setup (GstWavEnc *wavenc) +{ + struct wave_header wave; + int size = 0x7fffffff; /* Use a bogus size initially */ + + wave.common.wChannels = wavenc->channels; + wave.common.wBitsPerSample = wavenc->bits; + wave.common.dwSamplesPerSec = wavenc->rate; + + memset (wavenc->header, 0, WAV_HEADER_LEN); + + /* Fill out our wav-header with some information */ + strncpy (wave.riff.id, "RIFF", 4); + wave.riff.len = size - 8; + strncpy (wave.riff.wav_id, "WAVE", 4); + + strncpy (wave.format.id, "fmt ", 4); + wave.format.len = 16; + + wave.common.wFormatTag = WAVE_FORMAT_PCM; + wave.common.dwAvgBytesPerSec = wave.common.wChannels * wave.common.dwSamplesPerSec * (wave.common.wBitsPerSample >> 3); + wave.common.wBlockAlign = wave.common.wChannels * (wave.common.wBitsPerSample >> 3); + + strncpy (wave.data.id, "data", 4); + wave.data.len = size - 44; + + strncpy (wavenc->header, wave.riff.id, 4); + WRITE_U32 (wavenc->header + 4, wave.riff.len); + strncpy (wavenc->header + 8, wave.riff.wav_id, 4); + strncpy (wavenc->header + 12, wave.format.id, 4); + WRITE_U32 (wavenc->header + 16, wave.format.len); + WRITE_U16 (wavenc->header + 20, wave.common.wFormatTag); + WRITE_U16 (wavenc->header + 22, wave.common.wChannels); + WRITE_U32 (wavenc->header + 24, wave.common.dwSamplesPerSec); + WRITE_U32 (wavenc->header + 28, wave.common.dwAvgBytesPerSec); + WRITE_U16 (wavenc->header + 32, wave.common.wBlockAlign); + WRITE_U16 (wavenc->header + 34, wave.common.wBitsPerSample); + strncpy (wavenc->header + 36, wave.data.id, 4); + WRITE_U32 (wavenc->header + 40, wave.data.len); + + wavenc->setup = TRUE; + return TRUE; +} + +static GstPadConnectReturn +gst_wavenc_sinkconnect (GstPad *pad, + GstCaps *caps) +{ + GstWavEnc *wavenc; + + wavenc = GST_WAVENC (gst_pad_get_parent (pad)); + + if (!GST_CAPS_IS_FIXED (caps)) { + return GST_PAD_CONNECT_DELAYED; + } + + gst_caps_get_int (caps, "channels", &wavenc->channels); + gst_caps_get_int (caps, "rate", &wavenc->rate); + gst_caps_get_int (caps, "depth", &wavenc->bits); + + gst_wavenc_setup (wavenc); + + if (wavenc->setup) { + return GST_PAD_CONNECT_OK; + } + + return GST_PAD_CONNECT_REFUSED; +} + +static void +gst_wavenc_init (GstWavEnc *wavenc) +{ + wavenc->sinkpad = gst_pad_new_from_template (sinktemplate, "sink"); + gst_element_add_pad (GST_ELEMENT (wavenc), wavenc->sinkpad); + gst_pad_set_chain_function (wavenc->sinkpad, gst_wavenc_chain); + gst_pad_set_connect_function (wavenc->sinkpad, gst_wavenc_sinkconnect); + + wavenc->srcpad = gst_pad_new_from_template (srctemplate, "src"); + gst_element_add_pad (GST_ELEMENT (wavenc), wavenc->srcpad); + + wavenc->setup = FALSE; + wavenc->flush_header = TRUE; +} + +static void +gst_wavenc_chain (GstPad *pad, + GstBuffer *buf) +{ + GstWavEnc *wavenc; + + wavenc = GST_WAVENC (gst_pad_get_parent (pad)); + + if (GST_IS_EVENT (buf)) { + GstEvent *event = GST_EVENT (buf); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + /* Should do something... */ + gst_event_unref (event); + + gst_pad_push (wavenc->srcpad, GST_BUFFER (gst_event_new (GST_EVENT_EOS))); + gst_element_set_eos (GST_ELEMENT (wavenc)); + break; + + default: + gst_pad_event_default (pad, event); + return; + } + } else { + if (!wavenc->setup) { + gst_buffer_unref (buf); + gst_element_error (GST_ELEMENT (wavenc), "encoder not initialised (input is not audio?)"); + return; + } + + if (wavenc->flush_header) { + GstBuffer *outbuf; + + outbuf = gst_buffer_new_and_alloc (WAV_HEADER_LEN); + memcpy (GST_BUFFER_DATA (outbuf), wavenc->header, WAV_HEADER_LEN); + + if (GST_PAD_IS_USABLE (wavenc->srcpad)) { + gst_pad_push (wavenc->srcpad, outbuf); + } else { + gst_buffer_unref (outbuf); + } + + wavenc->flush_header = FALSE; + } + + gst_pad_push (wavenc->srcpad, buf); + } +} + +static gboolean +plugin_init (GModule *module, + GstPlugin *plugin) +{ + GstElementFactory *factory; + + factory = gst_element_factory_new ("wavenc", GST_TYPE_WAVENC, + &gst_wavenc_details); + + srctemplate = src_factory (); + gst_element_factory_add_pad_template (factory, srctemplate); + + sinktemplate = sink_factory (); + gst_element_factory_add_pad_template (factory, sinktemplate); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "wavenc", + plugin_init +}; + diff --git a/gst/wavenc/gstwavenc.h b/gst/wavenc/gstwavenc.h new file mode 100644 index 0000000..ebd3eae --- /dev/null +++ b/gst/wavenc/gstwavenc.h @@ -0,0 +1,76 @@ +/* GStreamer + * Copyright (C) 2002, Iain Holmes + * + * 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_WAVENC_H__ +#define __GST_WAVENC_H__ + + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + + +#define GST_TYPE_WAVENC \ + (gst_wavenc_get_type()) +#define GST_WAVENC(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAVENC,GstWavEnc)) +#define GST_WAVENC_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAVENC,GstWavEnc)) +#define GST_IS_WAVENC(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAVENC)) +#define GST_IS_WAVENC_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAVENC)) + +typedef struct _GstWavEnc GstWavEnc; +typedef struct _GstWavEncClass GstWavEncClass; + +#define WAV_HEADER_LEN 44 + +struct _GstWavEnc { + GstElement element; + + /* pads */ + GstPad *sinkpad,*srcpad; + + /* useful audio data */ + guint bits; + guint rate; + guint channels; + guint width; + + gboolean setup, flush_header; + guchar header[WAV_HEADER_LEN]; +}; + +struct _GstWavEncClass { + GstElementClass parent_class; +}; + +GType gst_wavenc_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + + +#endif /* __GST_ENC_H__ */ -- 2.7.4