Merge branch 'master' into 0.11

Conflicts:
	ext/opus/gstopusdec.c
	ext/opus/gstopusenc.c
	ext/opus/gstopusparse.c
	gst/audiovisualizers/gstwavescope.c
	gst/filter/Makefile.am
	gst/filter/gstfilter.c
	gst/filter/gstiir.c
	gst/playondemand/gstplayondemand.c
This commit is contained in:
Wim Taymans 2011-11-23 11:08:39 +01:00
commit 0a9387c43c
79 changed files with 3063 additions and 4367 deletions

View file

@ -296,7 +296,7 @@ dnl Make sure you have a space before and after all plugins
GST_PLUGINS_NONPORTED=" adpcmdec adpcmenc aiff asfmux \
autoconvert camerabin cdxaparse coloreffects \
dccp debugutils dtmf faceoverlay festival \
fieldanalysis freeze frei0r gaudieffects geometrictransform h264parse \
fieldanalysis freeverb freeze frei0r gaudieffects geometrictransform h264parse \
hdvparse hls id3tag inter interlace ivfparse jpegformat jp2kdecimator \
kate liveadder legacyresample librfb mpegdemux mpegtsmux \
mpegpsmux mpegvideoparse mve mxf mythtv nsf nuvdemux \
@ -306,7 +306,7 @@ GST_PLUGINS_NONPORTED=" adpcmdec adpcmenc aiff asfmux \
decklink fbdev linsys shm vcd \
voaacenc apexsink bz2 camerabin2 cdaudio celt cog curl dc1394 dirac directfb dts resindvd \
gsettings gsm jp2k ladspa modplug mpeg2enc mplex mimic \
musepack musicbrainz nas neon ofa openal rsvg schro sdl sndfile soundtouch spandsp timidity \
musepack musicbrainz nas neon ofa openal rsvg schro sdl smooth sndfile soundtouch spandsp timidity \
wildmidi xvid "
AC_SUBST(GST_PLUGINS_NONPORTED)
@ -332,6 +332,7 @@ AG_GST_CHECK_PLUGIN(faceoverlay)
AG_GST_CHECK_PLUGIN(festival)
AG_GST_CHECK_PLUGIN(fieldanalysis)
AG_GST_CHECK_PLUGIN(freeze)
AG_GST_CHECK_PLUGIN(freeverb)
AG_GST_CHECK_PLUGIN(frei0r)
AG_GST_CHECK_PLUGIN(gaudieffects)
AG_GST_CHECK_PLUGIN(geometrictransform)
@ -370,6 +371,7 @@ AG_GST_CHECK_PLUGIN(sdi)
AG_GST_CHECK_PLUGIN(sdp)
AG_GST_CHECK_PLUGIN(segmentclip)
AG_GST_CHECK_PLUGIN(siren)
AG_GST_CHECK_PLUGIN(smooth)
AG_GST_CHECK_PLUGIN(speed)
AG_GST_CHECK_PLUGIN(subenc)
AG_GST_CHECK_PLUGIN(stereo)
@ -1925,6 +1927,7 @@ gst/faceoverlay/Makefile
gst/festival/Makefile
gst/fieldanalysis/Makefile
gst/freeze/Makefile
gst/freeverb/Makefile
gst/frei0r/Makefile
gst/gaudieffects/Makefile
gst/geometrictransform/Makefile
@ -1964,6 +1967,7 @@ gst/sdi/Makefile
gst/sdp/Makefile
gst/segmentclip/Makefile
gst/siren/Makefile
gst/smooth/Makefile
gst/speed/Makefile
gst/subenc/Makefile
gst/stereo/Makefile

View file

@ -52,8 +52,6 @@ struct _GstCeltDec {
gint frame_size;
guint64 packetno;
gboolean discont;
GstBuffer *streamheader;
GstBuffer *vorbiscomment;
GList *extra_headers;

View file

@ -501,7 +501,8 @@ gst_celt_enc_encode (GstCeltEnc * enc, GstBuffer * buf)
#endif
if (outsize < 0) {
GST_ERROR_OBJECT (enc, "Encoding failed: %d", outsize);
GST_ELEMENT_ERROR (enc, STREAM, ENCODE, (NULL),
("encoding failed: %d", outsize));
ret = GST_FLOW_ERROR;
goto done;
}

View file

@ -117,14 +117,6 @@ gst_cv_dilate_erode_get_type (void)
return opencv_dilate_erode_type;
}
/* Clean up */
static void
gst_cv_dilate_erode_finalize (GObject * obj)
{
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
/* GObject vmethod implementations */
static void
@ -158,7 +150,6 @@ gst_cv_dilate_erode_class_init (GstCvDilateErodeClass * klass)
parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_cv_dilate_erode_finalize);
gobject_class->set_property = gst_cv_dilate_erode_set_property;
gobject_class->get_property = gst_cv_dilate_erode_get_property;

View file

@ -70,13 +70,6 @@ static GstFlowReturn gst_cv_equalize_hist_transform (GstOpencvVideoFilter *
filter, GstBuffer * buf, IplImage * img, GstBuffer * outbuf,
IplImage * outimg);
/* Clean up */
static void
gst_cv_equalize_hist_finalize (GObject * obj)
{
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
/* GObject vmethod implementations */
static void
@ -99,14 +92,11 @@ gst_cv_equalize_hist_base_init (gpointer gclass)
static void
gst_cv_equalize_hist_class_init (GstCvEqualizeHistClass * klass)
{
GObjectClass *gobject_class;
GstOpencvVideoFilterClass *gstopencvbasefilter_class;
gobject_class = (GObjectClass *) klass;
gstopencvbasefilter_class = (GstOpencvVideoFilterClass *) klass;
parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_cv_equalize_hist_finalize);
gstopencvbasefilter_class->cv_trans_func = gst_cv_equalize_hist_transform;
}

View file

@ -119,14 +119,6 @@ static GstFlowReturn gst_cv_smooth_transform_ip (GstOpencvVideoFilter *
static GstFlowReturn gst_cv_smooth_transform (GstOpencvVideoFilter * filter,
GstBuffer * buf, IplImage * img, GstBuffer * outbuf, IplImage * outimg);
/* Clean up */
static void
gst_cv_smooth_finalize (GObject * obj)
{
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
/* GObject vmethod implementations */
static void
@ -166,7 +158,6 @@ gst_cv_smooth_class_init (GstCvSmoothClass * klass)
parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_cv_smooth_finalize);
gobject_class->set_property = gst_cv_smooth_set_property;
gobject_class->get_property = gst_cv_smooth_get_property;

View file

@ -103,13 +103,6 @@ static GstCaps *gst_cv_sobel_transform_caps (GstBaseTransform * trans,
static GstFlowReturn gst_cv_sobel_transform (GstOpencvVideoFilter * filter,
GstBuffer * buf, IplImage * img, GstBuffer * outbuf, IplImage * outimg);
/* Clean up */
static void
gst_cv_sobel_finalize (GObject * obj)
{
G_OBJECT_CLASS (parent_class)->finalize (obj);
}
/* GObject vmethod implementations */
static void
@ -143,7 +136,6 @@ gst_cv_sobel_class_init (GstCvSobelClass * klass)
parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_cv_sobel_finalize);
gobject_class->set_property = gst_cv_sobel_set_property;
gobject_class->get_property = gst_cv_sobel_get_property;

View file

@ -65,8 +65,8 @@
#include "gstopencvutils.h"
#include "gstedgedetect.h"
GST_DEBUG_CATEGORY_STATIC (gst_edgedetect_debug);
#define GST_CAT_DEFAULT gst_edgedetect_debug
GST_DEBUG_CATEGORY_STATIC (gst_edge_detect_debug);
#define GST_CAT_DEFAULT gst_edge_detect_debug
/* Filter signals and args */
enum
@ -100,21 +100,21 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB)
);
GST_BOILERPLATE (Gstedgedetect, gst_edgedetect, GstElement, GST_TYPE_ELEMENT);
GST_BOILERPLATE (GstEdgeDetect, gst_edge_detect, GstElement, GST_TYPE_ELEMENT);
static void gst_edgedetect_set_property (GObject * object, guint prop_id,
static void gst_edge_detect_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_edgedetect_get_property (GObject * object, guint prop_id,
static void gst_edge_detect_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_edgedetect_set_caps (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_edgedetect_chain (GstPad * pad, GstBuffer * buf);
static gboolean gst_edge_detect_set_caps (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_edge_detect_chain (GstPad * pad, GstBuffer * buf);
/* Clean up */
static void
gst_edgedetect_finalize (GObject * obj)
gst_edge_detect_finalize (GObject * obj)
{
Gstedgedetect *filter = GST_EDGEDETECT (obj);
GstEdgeDetect *filter = GST_EDGE_DETECT (obj);
if (filter->cvImage != NULL) {
cvReleaseImage (&filter->cvImage);
@ -128,7 +128,7 @@ gst_edgedetect_finalize (GObject * obj)
/* GObject vmethod implementations */
static void
gst_edgedetect_base_init (gpointer gclass)
gst_edge_detect_base_init (gpointer gclass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
@ -146,15 +146,15 @@ gst_edgedetect_base_init (gpointer gclass)
/* initialize the edgedetect's class */
static void
gst_edgedetect_class_init (GstedgedetectClass * klass)
gst_edge_detect_class_init (GstEdgeDetectClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_edgedetect_finalize);
gobject_class->set_property = gst_edgedetect_set_property;
gobject_class->get_property = gst_edgedetect_get_property;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_edge_detect_finalize);
gobject_class->set_property = gst_edge_detect_set_property;
gobject_class->get_property = gst_edge_detect_get_property;
g_object_class_install_property (gobject_class, PROP_MASK,
g_param_spec_boolean ("mask", "Mask",
@ -180,15 +180,15 @@ gst_edgedetect_class_init (GstedgedetectClass * klass)
* initialize instance structure
*/
static void
gst_edgedetect_init (Gstedgedetect * filter, GstedgedetectClass * gclass)
gst_edge_detect_init (GstEdgeDetect * filter, GstEdgeDetectClass * gclass)
{
filter->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
gst_pad_set_setcaps_function (filter->sinkpad,
GST_DEBUG_FUNCPTR (gst_edgedetect_set_caps));
GST_DEBUG_FUNCPTR (gst_edge_detect_set_caps));
gst_pad_set_getcaps_function (filter->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
gst_pad_set_chain_function (filter->sinkpad,
GST_DEBUG_FUNCPTR (gst_edgedetect_chain));
GST_DEBUG_FUNCPTR (gst_edge_detect_chain));
filter->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
gst_pad_set_getcaps_function (filter->srcpad,
@ -203,10 +203,10 @@ gst_edgedetect_init (Gstedgedetect * filter, GstedgedetectClass * gclass)
}
static void
gst_edgedetect_set_property (GObject * object, guint prop_id,
gst_edge_detect_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
Gstedgedetect *filter = GST_EDGEDETECT (object);
GstEdgeDetect *filter = GST_EDGE_DETECT (object);
switch (prop_id) {
case PROP_MASK:
@ -228,10 +228,10 @@ gst_edgedetect_set_property (GObject * object, guint prop_id,
}
static void
gst_edgedetect_get_property (GObject * object, guint prop_id,
gst_edge_detect_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
Gstedgedetect *filter = GST_EDGEDETECT (object);
GstEdgeDetect *filter = GST_EDGE_DETECT (object);
switch (prop_id) {
case PROP_MASK:
@ -256,14 +256,14 @@ gst_edgedetect_get_property (GObject * object, guint prop_id,
/* this function handles the link with other elements */
static gboolean
gst_edgedetect_set_caps (GstPad * pad, GstCaps * caps)
gst_edge_detect_set_caps (GstPad * pad, GstCaps * caps)
{
Gstedgedetect *filter;
GstEdgeDetect *filter;
GstPad *otherpad;
gint width, height;
GstStructure *structure;
filter = GST_EDGEDETECT (gst_pad_get_parent (pad));
filter = GST_EDGE_DETECT (gst_pad_get_parent (pad));
structure = gst_caps_get_structure (caps, 0);
gst_structure_get_int (structure, "width", &width);
gst_structure_get_int (structure, "height", &height);
@ -283,12 +283,12 @@ gst_edgedetect_set_caps (GstPad * pad, GstCaps * caps)
* this function does the actual processing
*/
static GstFlowReturn
gst_edgedetect_chain (GstPad * pad, GstBuffer * buf)
gst_edge_detect_chain (GstPad * pad, GstBuffer * buf)
{
Gstedgedetect *filter;
GstEdgeDetect *filter;
GstBuffer *outbuf;
filter = GST_EDGEDETECT (GST_OBJECT_PARENT (pad));
filter = GST_EDGE_DETECT (GST_OBJECT_PARENT (pad));
filter->cvImage->imageData = (char *) GST_BUFFER_DATA (buf);
@ -319,14 +319,14 @@ gst_edgedetect_chain (GstPad * pad, GstBuffer * buf)
* register the element factories and other features
*/
gboolean
gst_edgedetect_plugin_init (GstPlugin * plugin)
gst_edge_detect_plugin_init (GstPlugin * plugin)
{
/* debug category for fltering log messages
*
*/
GST_DEBUG_CATEGORY_INIT (gst_edgedetect_debug, "edgedetect",
GST_DEBUG_CATEGORY_INIT (gst_edge_detect_debug, "edgedetect",
0, "Performs canny edge detection on videos and images");
return gst_element_register (plugin, "edgedetect", GST_RANK_NONE,
GST_TYPE_EDGEDETECT);
GST_TYPE_EDGE_DETECT);
}

View file

@ -43,28 +43,28 @@
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_EDGEDETECT_H__
#define __GST_EDGEDETECT_H__
#ifndef __GST_EDGE_DETECT_H__
#define __GST_EDGE_DETECT_H__
#include <gst/gst.h>
#include <cv.h>
G_BEGIN_DECLS
/* #defines don't like whitespacey bits */
#define GST_TYPE_EDGEDETECT \
(gst_edgedetect_get_type())
#define GST_EDGEDETECT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_EDGEDETECT,Gstedgedetect))
#define GST_EDGEDETECT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EDGEDETECT,GstedgedetectClass))
#define GST_IS_EDGEDETECT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_EDGEDETECT))
#define GST_IS_EDGEDETECT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EDGEDETECT))
typedef struct _Gstedgedetect Gstedgedetect;
typedef struct _GstedgedetectClass GstedgedetectClass;
#define GST_TYPE_EDGE_DETECT \
(gst_edge_detect_get_type())
#define GST_EDGE_DETECT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_EDGE_DETECT,GstEdgeDetect))
#define GST_EDGE_DETECT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EDGE_DETECT,GstEdgeDetectClass))
#define GST_IS_EDGE_DETECT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_EDGE_DETECT))
#define GST_IS_EDGE_DETECT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EDGE_DETECT))
typedef struct _GstEdgeDetect GstEdgeDetect;
typedef struct _GstEdgeDetectClass GstEdgeDetectClass;
struct _Gstedgedetect
struct _GstEdgeDetect
{
GstElement element;
@ -77,14 +77,14 @@ struct _Gstedgedetect
IplImage *cvEdge, *cvGray, *cvImage, *cvCEdge;
};
struct _GstedgedetectClass
struct _GstEdgeDetectClass
{
GstElementClass parent_class;
};
GType gst_edgedetect_get_type (void);
GType gst_edge_detect_get_type (void);
gboolean gst_edgedetect_plugin_init (GstPlugin * plugin);
gboolean gst_edge_detect_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* __GST_EDGEDETECT_H__ */
#endif /* __GST_EDGE_DETECT_H__ */

View file

@ -46,7 +46,7 @@
/**
* SECTION:element-faceblur
*
* FIXME:Describe faceblur here.
* Blurs faces in images and videos.
*
* <refsect2>
* <title>Example launch line</title>
@ -65,8 +65,8 @@
#include "gstopencvutils.h"
#include "gstfaceblur.h"
GST_DEBUG_CATEGORY_STATIC (gst_faceblur_debug);
#define GST_CAT_DEFAULT gst_faceblur_debug
GST_DEBUG_CATEGORY_STATIC (gst_face_blur_debug);
#define GST_CAT_DEFAULT gst_face_blur_debug
#define DEFAULT_PROFILE "/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml"
@ -97,23 +97,23 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB)
);
GST_BOILERPLATE (Gstfaceblur, gst_faceblur, GstElement, GST_TYPE_ELEMENT);
GST_BOILERPLATE (GstFaceBlur, gst_face_blur, GstElement, GST_TYPE_ELEMENT);
static void gst_faceblur_set_property (GObject * object, guint prop_id,
static void gst_face_blur_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_faceblur_get_property (GObject * object, guint prop_id,
static void gst_face_blur_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_faceblur_set_caps (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_faceblur_chain (GstPad * pad, GstBuffer * buf);
static gboolean gst_face_blur_set_caps (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_face_blur_chain (GstPad * pad, GstBuffer * buf);
static void gst_faceblur_load_profile (Gstfaceblur * filter);
static void gst_face_blur_load_profile (GstFaceBlur * filter);
/* Clean up */
static void
gst_faceblur_finalize (GObject * obj)
gst_face_blur_finalize (GObject * obj)
{
Gstfaceblur *filter = GST_FACEBLUR (obj);
GstFaceBlur *filter = GST_FACE_BLUR (obj);
if (filter->cvImage) {
cvReleaseImage (&filter->cvImage);
@ -128,7 +128,7 @@ gst_faceblur_finalize (GObject * obj)
/* GObject vmethod implementations */
static void
gst_faceblur_base_init (gpointer gclass)
gst_face_blur_base_init (gpointer gclass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
@ -146,16 +146,16 @@ gst_faceblur_base_init (gpointer gclass)
/* initialize the faceblur's class */
static void
gst_faceblur_class_init (GstfaceblurClass * klass)
gst_face_blur_class_init (GstFaceBlurClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_faceblur_finalize);
gobject_class->set_property = gst_faceblur_set_property;
gobject_class->get_property = gst_faceblur_get_property;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_face_blur_finalize);
gobject_class->set_property = gst_face_blur_set_property;
gobject_class->get_property = gst_face_blur_get_property;
g_object_class_install_property (gobject_class, PROP_PROFILE,
g_param_spec_string ("profile", "Profile",
@ -169,15 +169,15 @@ gst_faceblur_class_init (GstfaceblurClass * klass)
* initialize instance structure
*/
static void
gst_faceblur_init (Gstfaceblur * filter, GstfaceblurClass * gclass)
gst_face_blur_init (GstFaceBlur * filter, GstFaceBlurClass * gclass)
{
filter->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
gst_pad_set_setcaps_function (filter->sinkpad,
GST_DEBUG_FUNCPTR (gst_faceblur_set_caps));
GST_DEBUG_FUNCPTR (gst_face_blur_set_caps));
gst_pad_set_getcaps_function (filter->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
gst_pad_set_chain_function (filter->sinkpad,
GST_DEBUG_FUNCPTR (gst_faceblur_chain));
GST_DEBUG_FUNCPTR (gst_face_blur_chain));
filter->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
gst_pad_set_getcaps_function (filter->srcpad,
@ -186,20 +186,20 @@ gst_faceblur_init (Gstfaceblur * filter, GstfaceblurClass * gclass)
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
filter->profile = g_strdup (DEFAULT_PROFILE);
gst_faceblur_load_profile (filter);
gst_face_blur_load_profile (filter);
}
static void
gst_faceblur_set_property (GObject * object, guint prop_id,
gst_face_blur_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
Gstfaceblur *filter = GST_FACEBLUR (object);
GstFaceBlur *filter = GST_FACE_BLUR (object);
switch (prop_id) {
case PROP_PROFILE:
g_free (filter->profile);
filter->profile = g_value_dup_string (value);
gst_faceblur_load_profile (filter);
gst_face_blur_load_profile (filter);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@ -208,10 +208,10 @@ gst_faceblur_set_property (GObject * object, guint prop_id,
}
static void
gst_faceblur_get_property (GObject * object, guint prop_id,
gst_face_blur_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
Gstfaceblur *filter = GST_FACEBLUR (object);
GstFaceBlur *filter = GST_FACE_BLUR (object);
switch (prop_id) {
case PROP_PROFILE:
@ -227,14 +227,14 @@ gst_faceblur_get_property (GObject * object, guint prop_id,
/* this function handles the link with other elements */
static gboolean
gst_faceblur_set_caps (GstPad * pad, GstCaps * caps)
gst_face_blur_set_caps (GstPad * pad, GstCaps * caps)
{
Gstfaceblur *filter;
GstFaceBlur *filter;
GstPad *otherpad;
gint width, height;
GstStructure *structure;
filter = GST_FACEBLUR (gst_pad_get_parent (pad));
filter = GST_FACE_BLUR (gst_pad_get_parent (pad));
structure = gst_caps_get_structure (caps, 0);
gst_structure_get_int (structure, "width", &width);
gst_structure_get_int (structure, "height", &height);
@ -253,13 +253,13 @@ gst_faceblur_set_caps (GstPad * pad, GstCaps * caps)
* this function does the actual processing
*/
static GstFlowReturn
gst_faceblur_chain (GstPad * pad, GstBuffer * buf)
gst_face_blur_chain (GstPad * pad, GstBuffer * buf)
{
Gstfaceblur *filter;
GstFaceBlur *filter;
CvSeq *faces;
int i;
filter = GST_FACEBLUR (GST_OBJECT_PARENT (pad));
filter = GST_FACE_BLUR (GST_OBJECT_PARENT (pad));
filter->cvImage->imageData = (char *) GST_BUFFER_DATA (buf);
@ -294,7 +294,7 @@ gst_faceblur_chain (GstPad * pad, GstBuffer * buf)
static void
gst_faceblur_load_profile (Gstfaceblur * filter)
gst_face_blur_load_profile (GstFaceBlur * filter)
{
filter->cvCascade =
(CvHaarClassifierCascade *) cvLoad (filter->profile, 0, 0, 0);
@ -309,12 +309,12 @@ gst_faceblur_load_profile (Gstfaceblur * filter)
* register the element factories and other features
*/
gboolean
gst_faceblur_plugin_init (GstPlugin * plugin)
gst_face_blur_plugin_init (GstPlugin * plugin)
{
/* debug category for filtering log messages */
GST_DEBUG_CATEGORY_INIT (gst_faceblur_debug, "faceblur",
GST_DEBUG_CATEGORY_INIT (gst_face_blur_debug, "faceblur",
0, "Blurs faces in images and videos");
return gst_element_register (plugin, "faceblur", GST_RANK_NONE,
GST_TYPE_FACEBLUR);
GST_TYPE_FACE_BLUR);
}

View file

@ -43,8 +43,8 @@
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_FACEBLUR_H__
#define __GST_FACEBLUR_H__
#ifndef __GST_FACE_BLUR_H__
#define __GST_FACE_BLUR_H__
#include <gst/gst.h>
#include <cv.h>
@ -55,20 +55,20 @@
G_BEGIN_DECLS
/* #defines don't like whitespacey bits */
#define GST_TYPE_FACEBLUR \
(gst_faceblur_get_type())
#define GST_FACEBLUR(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FACEBLUR,Gstfaceblur))
#define GST_FACEBLUR_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FACEBLUR,GstfaceblurClass))
#define GST_IS_FACEBLUR(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FACEBLUR))
#define GST_IS_FACEBLUR_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FACEBLUR))
typedef struct _Gstfaceblur Gstfaceblur;
typedef struct _GstfaceblurClass GstfaceblurClass;
#define GST_TYPE_FACE_BLUR \
(gst_face_blur_get_type())
#define GST_FACE_BLUR(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FACE_BLUR,GstFaceBlur))
#define GST_FACE_BLUR_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FACE_BLUR,GstFaceBlurClass))
#define GST_IS_FACE_BLUR(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FACE_BLUR))
#define GST_IS_FACE_BLUR_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FACE_BLUR))
typedef struct _GstFaceBlur GstFaceBlur;
typedef struct _GstFaceBlurClass GstFaceBlurClass;
struct _Gstfaceblur
struct _GstFaceBlur
{
GstElement element;
@ -83,14 +83,14 @@ struct _Gstfaceblur
CvMemStorage *cvStorage;
};
struct _GstfaceblurClass
struct _GstFaceBlurClass
{
GstElementClass parent_class;
};
GType gst_faceblur_get_type (void);
GType gst_face_blur_get_type (void);
gboolean gst_faceblur_plugin_init (GstPlugin * plugin);
gboolean gst_face_blur_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* __GST_FACEBLUR_H__ */
#endif /* __GST_FACE_BLUR_H__ */

View file

@ -49,9 +49,9 @@
*
* Performs face detection on videos and images.
*
* The image is scaled down multiple times using the GstFacedetect::scale-factor
* until the size is &lt;= GstFacedetect::min-size-width or
* GstFacedetect::min-size-height.
* The image is scaled down multiple times using the GstFaceDetect::scale-factor
* until the size is &lt;= GstFaceDetect::min-size-width or
* GstFaceDetect::min-size-height.
*
* <refsect2>
* <title>Example launch line</title>
@ -76,10 +76,11 @@
#include <gst/gst.h>
#include "gstopencvutils.h"
#include "gstfacedetect.h"
GST_DEBUG_CATEGORY_STATIC (gst_facedetect_debug);
#define GST_CAT_DEFAULT gst_facedetect_debug
GST_DEBUG_CATEGORY_STATIC (gst_face_detect_debug);
#define GST_CAT_DEFAULT gst_face_detect_debug
#define DEFAULT_FACE_PROFILE "/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml"
#define DEFAULT_NOSE_PROFILE "/usr/share/opencv/haarcascades/haarcascade_mcs_nose.xml"
@ -114,7 +115,7 @@ enum
};
/**
/*
* GstOpencvFaceDetectFlags:
*
* Flags parameter to OpenCV's cvHaarDetectObjects function.
@ -152,37 +153,37 @@ gst_opencv_face_detect_flags_get_type (void)
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-rgb")
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB)
);
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-rgb")
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB)
);
GST_BOILERPLATE (GstFacedetect, gst_facedetect, GstOpencvVideoFilter,
GST_BOILERPLATE (GstFaceDetect, gst_face_detect, GstOpencvVideoFilter,
GST_TYPE_OPENCV_VIDEO_FILTER);
static void gst_facedetect_set_property (GObject * object, guint prop_id,
static void gst_face_detect_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_facedetect_get_property (GObject * object, guint prop_id,
static void gst_face_detect_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_facedetect_set_caps (GstOpencvVideoFilter * transform,
static gboolean gst_face_detect_set_caps (GstOpencvVideoFilter * transform,
gint in_width, gint in_height, gint in_depth, gint in_channels,
gint out_width, gint out_height, gint out_depth, gint out_channels);
static GstFlowReturn gst_facedetect_transform_ip (GstOpencvVideoFilter * base,
static GstFlowReturn gst_face_detect_transform_ip (GstOpencvVideoFilter * base,
GstBuffer * buf, IplImage * img);
static CvHaarClassifierCascade *gst_facedetect_load_profile (GstFacedetect *
static CvHaarClassifierCascade *gst_face_detect_load_profile (GstFaceDetect *
filter, gchar * profile);
/* Clean up */
static void
gst_facedetect_finalize (GObject * obj)
gst_face_detect_finalize (GObject * obj)
{
GstFacedetect *filter = GST_FACEDETECT (obj);
GstFaceDetect *filter = GST_FACE_DETECT (obj);
if (filter->cvGray)
cvReleaseImage (&filter->cvGray);
@ -209,7 +210,7 @@ gst_facedetect_finalize (GObject * obj)
/* GObject vmethod implementations */
static void
gst_facedetect_base_init (gpointer gclass)
gst_face_detect_base_init (gpointer gclass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
@ -227,7 +228,7 @@ gst_facedetect_base_init (gpointer gclass)
/* initialize the facedetect's class */
static void
gst_facedetect_class_init (GstFacedetectClass * klass)
gst_face_detect_class_init (GstFaceDetectClass * klass)
{
GObjectClass *gobject_class;
GstOpencvVideoFilterClass *gstopencvbasefilter_class;
@ -235,12 +236,12 @@ gst_facedetect_class_init (GstFacedetectClass * klass)
gobject_class = (GObjectClass *) klass;
gstopencvbasefilter_class = (GstOpencvVideoFilterClass *) klass;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_facedetect_finalize);
gobject_class->set_property = gst_facedetect_set_property;
gobject_class->get_property = gst_facedetect_get_property;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_face_detect_finalize);
gobject_class->set_property = gst_face_detect_set_property;
gobject_class->get_property = gst_face_detect_get_property;
gstopencvbasefilter_class->cv_trans_ip_func = gst_facedetect_transform_ip;
gstopencvbasefilter_class->cv_set_caps = gst_facedetect_set_caps;
gstopencvbasefilter_class->cv_trans_ip_func = gst_face_detect_transform_ip;
gstopencvbasefilter_class->cv_set_caps = gst_face_detect_set_caps;
g_object_class_install_property (gobject_class, PROP_DISPLAY,
g_param_spec_boolean ("display", "Display",
@ -292,7 +293,7 @@ gst_facedetect_class_init (GstFacedetectClass * klass)
* initialize instance structure
*/
static void
gst_facedetect_init (GstFacedetect * filter, GstFacedetectClass * gclass)
gst_face_detect_init (GstFaceDetect * filter, GstFaceDetectClass * gclass)
{
filter->face_profile = g_strdup (DEFAULT_FACE_PROFILE);
filter->nose_profile = g_strdup (DEFAULT_NOSE_PROFILE);
@ -305,23 +306,23 @@ gst_facedetect_init (GstFacedetect * filter, GstFacedetectClass * gclass)
filter->min_size_width = DEFAULT_MIN_SIZE_WIDTH;
filter->min_size_height = DEFAULT_MIN_SIZE_HEIGHT;
filter->cvFaceDetect =
gst_facedetect_load_profile (filter, filter->face_profile);
gst_face_detect_load_profile (filter, filter->face_profile);
filter->cvNoseDetect =
gst_facedetect_load_profile (filter, filter->nose_profile);
gst_face_detect_load_profile (filter, filter->nose_profile);
filter->cvMouthDetect =
gst_facedetect_load_profile (filter, filter->mouth_profile);
gst_face_detect_load_profile (filter, filter->mouth_profile);
filter->cvEyesDetect =
gst_facedetect_load_profile (filter, filter->eyes_profile);
gst_face_detect_load_profile (filter, filter->eyes_profile);
gst_opencv_video_filter_set_in_place (GST_OPENCV_VIDEO_FILTER_CAST (filter),
TRUE);
}
static void
gst_facedetect_set_property (GObject * object, guint prop_id,
gst_face_detect_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstFacedetect *filter = GST_FACEDETECT (object);
GstFaceDetect *filter = GST_FACE_DETECT (object);
switch (prop_id) {
case PROP_FACE_PROFILE:
@ -330,7 +331,7 @@ gst_facedetect_set_property (GObject * object, guint prop_id,
cvReleaseHaarClassifierCascade (&filter->cvFaceDetect);
filter->face_profile = g_value_dup_string (value);
filter->cvFaceDetect =
gst_facedetect_load_profile (filter, filter->face_profile);
gst_face_detect_load_profile (filter, filter->face_profile);
break;
case PROP_NOSE_PROFILE:
g_free (filter->nose_profile);
@ -338,7 +339,7 @@ gst_facedetect_set_property (GObject * object, guint prop_id,
cvReleaseHaarClassifierCascade (&filter->cvNoseDetect);
filter->nose_profile = g_value_dup_string (value);
filter->cvNoseDetect =
gst_facedetect_load_profile (filter, filter->nose_profile);
gst_face_detect_load_profile (filter, filter->nose_profile);
break;
case PROP_MOUTH_PROFILE:
g_free (filter->mouth_profile);
@ -346,7 +347,7 @@ gst_facedetect_set_property (GObject * object, guint prop_id,
cvReleaseHaarClassifierCascade (&filter->cvMouthDetect);
filter->mouth_profile = g_value_dup_string (value);
filter->cvMouthDetect =
gst_facedetect_load_profile (filter, filter->mouth_profile);
gst_face_detect_load_profile (filter, filter->mouth_profile);
break;
case PROP_EYES_PROFILE:
g_free (filter->eyes_profile);
@ -354,7 +355,7 @@ gst_facedetect_set_property (GObject * object, guint prop_id,
cvReleaseHaarClassifierCascade (&filter->cvEyesDetect);
filter->eyes_profile = g_value_dup_string (value);
filter->cvEyesDetect =
gst_facedetect_load_profile (filter, filter->eyes_profile);
gst_face_detect_load_profile (filter, filter->eyes_profile);
break;
case PROP_DISPLAY:
filter->display = g_value_get_boolean (value);
@ -381,10 +382,10 @@ gst_facedetect_set_property (GObject * object, guint prop_id,
}
static void
gst_facedetect_get_property (GObject * object, guint prop_id,
gst_face_detect_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstFacedetect *filter = GST_FACEDETECT (object);
GstFaceDetect *filter = GST_FACE_DETECT (object);
switch (prop_id) {
case PROP_FACE_PROFILE:
@ -427,13 +428,13 @@ gst_facedetect_get_property (GObject * object, guint prop_id,
/* this function handles the link with other elements */
static gboolean
gst_facedetect_set_caps (GstOpencvVideoFilter * transform, gint in_width,
gst_face_detect_set_caps (GstOpencvVideoFilter * transform, gint in_width,
gint in_height, gint in_depth, gint in_channels,
gint out_width, gint out_height, gint out_depth, gint out_channels)
{
GstFacedetect *filter;
GstFaceDetect *filter;
filter = GST_FACEDETECT (transform);
filter = GST_FACE_DETECT (transform);
if (filter->cvGray)
cvReleaseImage (&filter->cvGray);
@ -450,7 +451,7 @@ gst_facedetect_set_caps (GstOpencvVideoFilter * transform, gint in_width,
}
static GstMessage *
gst_facedetect_message_new (GstFacedetect * filter, GstBuffer * buf)
gst_face_detect_message_new (GstFaceDetect * filter, GstBuffer * buf)
{
GstBaseTransform *trans = GST_BASE_TRANSFORM_CAST (filter);
GstStructure *s;
@ -475,10 +476,10 @@ gst_facedetect_message_new (GstFacedetect * filter, GstBuffer * buf)
* Performs the face detection
*/
static GstFlowReturn
gst_facedetect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
gst_face_detect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
IplImage * img)
{
GstFacedetect *filter = GST_FACEDETECT (base);
GstFaceDetect *filter = GST_FACE_DETECT (base);
if (filter->cvFaceDetect) {
GstMessage *msg = NULL;
@ -509,7 +510,7 @@ gst_facedetect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
);
if (faces && faces->total > 0) {
msg = gst_facedetect_message_new (filter, buf);
msg = gst_face_detect_message_new (filter, buf);
g_value_init (&facelist, GST_TYPE_LIST);
}
@ -692,7 +693,7 @@ gst_facedetect_transform_ip (GstOpencvVideoFilter * base, GstBuffer * buf,
static CvHaarClassifierCascade *
gst_facedetect_load_profile (GstFacedetect * filter, gchar * profile)
gst_face_detect_load_profile (GstFaceDetect * filter, gchar * profile)
{
CvHaarClassifierCascade *cascade;
@ -709,13 +710,13 @@ gst_facedetect_load_profile (GstFacedetect * filter, gchar * profile)
* register the element factories and other features
*/
gboolean
gst_facedetect_plugin_init (GstPlugin * plugin)
gst_face_detect_plugin_init (GstPlugin * plugin)
{
/* debug category for fltering log messages */
GST_DEBUG_CATEGORY_INIT (gst_facedetect_debug, "facedetect",
GST_DEBUG_CATEGORY_INIT (gst_face_detect_debug, "facedetect",
0,
"Performs face detection on videos and images, providing detected positions via bus messages");
return gst_element_register (plugin, "facedetect", GST_RANK_NONE,
GST_TYPE_FACEDETECT);
GST_TYPE_FACE_DETECT);
}

View file

@ -44,8 +44,8 @@
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_FACEDETECT_H__
#define __GST_FACEDETECT_H__
#ifndef __GST_FACE_DETECT_H__
#define __GST_FACE_DETECT_H__
#include <gst/gst.h>
#include <cv.h>
@ -57,20 +57,20 @@
G_BEGIN_DECLS
/* #defines don't like whitespacey bits */
#define GST_TYPE_FACEDETECT \
(gst_facedetect_get_type())
#define GST_FACEDETECT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FACEDETECT,GstFacedetect))
#define GST_FACEDETECT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FACEDETECT,GstFacedetectClass))
#define GST_IS_FACEDETECT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FACEDETECT))
#define GST_IS_FACEDETECT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FACEDETECT))
typedef struct _GstFacedetect GstFacedetect;
typedef struct _GstFacedetectClass GstFacedetectClass;
#define GST_TYPE_FACE_DETECT \
(gst_face_detect_get_type())
#define GST_FACE_DETECT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FACE_DETECT,GstFaceDetect))
#define GST_FACE_DETECT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_FACE_DETECT,GstFaceDetectClass))
#define GST_IS_FACE_DETECT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FACE_DETECT))
#define GST_IS_FACE_DETECT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_FACE_DETECT))
typedef struct _GstFaceDetect GstFaceDetect;
typedef struct _GstFaceDetectClass GstFaceDetectClass;
struct _GstFacedetect
struct _GstFaceDetect
{
GstOpencvVideoFilter element;
@ -94,14 +94,14 @@ struct _GstFacedetect
CvMemStorage *cvStorage;
};
struct _GstFacedetectClass
struct _GstFaceDetectClass
{
GstOpencvVideoFilterClass parent_class;
};
GType gst_facedetect_get_type (void);
GType gst_face_detect_get_type (void);
gboolean gst_facedetect_plugin_init (GstPlugin * plugin);
gboolean gst_face_detect_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* __GST_FACEDETECT_H__ */
#endif /* __GST_FACE_DETECT_H__ */

View file

@ -61,13 +61,15 @@
#include <stdio.h>
#include <string.h>
#include <glib.h>
#include "gstmotioncells.h"
#include "motioncells_wrapper.h"
#include <sys/time.h>
#include <time.h>
#include <limits.h>
#include <glib.h>
#include "gstmotioncells.h"
#include "motioncells_wrapper.h"
#include <gst/video/video.h>
GST_DEBUG_CATEGORY_STATIC (gst_motion_cells_debug);
#define GST_CAT_DEFAULT gst_motion_cells_debug
@ -139,10 +141,14 @@ enum
/* the capabilities of the inputs and outputs.
*/
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/x-raw-rgb"));
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB));
static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS ("video/x-raw-rgb"));
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB));
GST_BOILERPLATE (GstMotioncells, gst_motion_cells, GstElement,
GST_TYPE_ELEMENT);
@ -1092,7 +1098,7 @@ gst_motion_cells_chain (GstPad * pad, GstBuffer * buf)
* register the element factories and other features
*/
gboolean
gst_motioncells_plugin_init (GstPlugin * plugin)
gst_motion_cells_plugin_init (GstPlugin * plugin)
{
/* debug category for fltering log messages */
GST_DEBUG_CATEGORY_INIT (gst_motion_cells_debug,

View file

@ -118,7 +118,7 @@ struct _GstMotioncellsClass
GType gst_motion_cells_get_type (void);
gboolean gst_motioncells_plugin_init (GstPlugin * plugin);
gboolean gst_motion_cells_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* __GST_MOTION_CELLS_H__ */

View file

@ -58,22 +58,22 @@ plugin_init (GstPlugin * plugin)
if (!gst_cv_sobel_plugin_init (plugin))
return FALSE;
if (!gst_edgedetect_plugin_init (plugin))
if (!gst_edge_detect_plugin_init (plugin))
return FALSE;
if (!gst_faceblur_plugin_init (plugin))
if (!gst_face_blur_plugin_init (plugin))
return FALSE;
if (!gst_facedetect_plugin_init (plugin))
if (!gst_face_detect_plugin_init (plugin))
return FALSE;
if (!gst_motioncells_plugin_init (plugin))
if (!gst_motion_cells_plugin_init (plugin))
return FALSE;
if (!gst_pyramidsegment_plugin_init (plugin))
if (!gst_pyramid_segment_plugin_init (plugin))
return FALSE;
if (!gst_templatematch_plugin_init (plugin))
if (!gst_template_match_plugin_init (plugin))
return FALSE;
if (!gst_opencv_text_overlay_plugin_init (plugin))

View file

@ -46,7 +46,7 @@
/**
* SECTION:element-pyramidsegment
*
* FIXME:Describe pyramidsegment here.
* Applies pyramid segmentation to a video or image.
*
* <refsect2>
* <title>Example launch line</title>
@ -67,8 +67,8 @@
#define BLOCK_SIZE 1000
GST_DEBUG_CATEGORY_STATIC (gst_pyramidsegment_debug);
#define GST_CAT_DEFAULT gst_pyramidsegment_debug
GST_DEBUG_CATEGORY_STATIC (gst_pyramid_segment_debug);
#define GST_CAT_DEFAULT gst_pyramid_segment_debug
/* Filter signals and args */
enum
@ -102,22 +102,22 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB)
);
GST_BOILERPLATE (Gstpyramidsegment, gst_pyramidsegment, GstElement,
GST_BOILERPLATE (GstPyramidSegment, gst_pyramid_segment, GstElement,
GST_TYPE_ELEMENT);
static void gst_pyramidsegment_set_property (GObject * object, guint prop_id,
static void gst_pyramid_segment_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_pyramidsegment_get_property (GObject * object, guint prop_id,
static void gst_pyramid_segment_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_pyramidsegment_set_caps (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_pyramidsegment_chain (GstPad * pad, GstBuffer * buf);
static gboolean gst_pyramid_segment_set_caps (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_pyramid_segment_chain (GstPad * pad, GstBuffer * buf);
/* Clean up */
static void
gst_pyramidsegment_finalize (GObject * obj)
gst_pyramid_segment_finalize (GObject * obj)
{
Gstpyramidsegment *filter = GST_PYRAMIDSEGMENT (obj);
GstPyramidSegment *filter = GST_PYRAMID_SEGMENT (obj);
if (filter->cvImage != NULL) {
cvReleaseImage (&filter->cvImage);
@ -129,7 +129,7 @@ gst_pyramidsegment_finalize (GObject * obj)
/* GObject vmethod implementations */
static void
gst_pyramidsegment_base_init (gpointer gclass)
gst_pyramid_segment_base_init (gpointer gclass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
@ -147,16 +147,16 @@ gst_pyramidsegment_base_init (gpointer gclass)
/* initialize the pyramidsegment's class */
static void
gst_pyramidsegment_class_init (GstpyramidsegmentClass * klass)
gst_pyramid_segment_class_init (GstPyramidSegmentClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
parent_class = g_type_class_peek_parent (klass);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_pyramidsegment_finalize);
gobject_class->set_property = gst_pyramidsegment_set_property;
gobject_class->get_property = gst_pyramidsegment_get_property;
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_pyramid_segment_finalize);
gobject_class->set_property = gst_pyramid_segment_set_property;
gobject_class->get_property = gst_pyramid_segment_get_property;
g_object_class_install_property (gobject_class, PROP_SILENT,
g_param_spec_boolean ("silent", "Silent", "Produce verbose output ?",
@ -184,16 +184,16 @@ gst_pyramidsegment_class_init (GstpyramidsegmentClass * klass)
* initialize instance structure
*/
static void
gst_pyramidsegment_init (Gstpyramidsegment * filter,
GstpyramidsegmentClass * gclass)
gst_pyramid_segment_init (GstPyramidSegment * filter,
GstPyramidSegmentClass * gclass)
{
filter->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
gst_pad_set_setcaps_function (filter->sinkpad,
GST_DEBUG_FUNCPTR (gst_pyramidsegment_set_caps));
GST_DEBUG_FUNCPTR (gst_pyramid_segment_set_caps));
gst_pad_set_getcaps_function (filter->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
gst_pad_set_chain_function (filter->sinkpad,
GST_DEBUG_FUNCPTR (gst_pyramidsegment_chain));
GST_DEBUG_FUNCPTR (gst_pyramid_segment_chain));
filter->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
gst_pad_set_getcaps_function (filter->srcpad,
@ -211,10 +211,10 @@ gst_pyramidsegment_init (Gstpyramidsegment * filter,
}
static void
gst_pyramidsegment_set_property (GObject * object, guint prop_id,
gst_pyramid_segment_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
Gstpyramidsegment *filter = GST_PYRAMIDSEGMENT (object);
GstPyramidSegment *filter = GST_PYRAMID_SEGMENT (object);
switch (prop_id) {
case PROP_SILENT:
@ -236,10 +236,10 @@ gst_pyramidsegment_set_property (GObject * object, guint prop_id,
}
static void
gst_pyramidsegment_get_property (GObject * object, guint prop_id,
gst_pyramid_segment_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
Gstpyramidsegment *filter = GST_PYRAMIDSEGMENT (object);
GstPyramidSegment *filter = GST_PYRAMID_SEGMENT (object);
switch (prop_id) {
case PROP_SILENT:
@ -264,14 +264,14 @@ gst_pyramidsegment_get_property (GObject * object, guint prop_id,
/* this function handles the link with other elements */
static gboolean
gst_pyramidsegment_set_caps (GstPad * pad, GstCaps * caps)
gst_pyramid_segment_set_caps (GstPad * pad, GstCaps * caps)
{
Gstpyramidsegment *filter;
GstPyramidSegment *filter;
GstPad *otherpad;
GstStructure *structure;
gint width, height;
filter = GST_PYRAMIDSEGMENT (gst_pad_get_parent (pad));
filter = GST_PYRAMID_SEGMENT (gst_pad_get_parent (pad));
structure = gst_caps_get_structure (caps, 0);
gst_structure_get_int (structure, "width", &width);
@ -289,12 +289,12 @@ gst_pyramidsegment_set_caps (GstPad * pad, GstCaps * caps)
* this function does the actual processing
*/
static GstFlowReturn
gst_pyramidsegment_chain (GstPad * pad, GstBuffer * buf)
gst_pyramid_segment_chain (GstPad * pad, GstBuffer * buf)
{
Gstpyramidsegment *filter;
GstPyramidSegment *filter;
GstBuffer *outbuf;
filter = GST_PYRAMIDSEGMENT (GST_OBJECT_PARENT (pad));
filter = GST_PYRAMID_SEGMENT (GST_OBJECT_PARENT (pad));
filter->cvImage->imageData = (char *) GST_BUFFER_DATA (buf);
filter->cvSegmentedImage = cvCloneImage (filter->cvImage);
@ -323,12 +323,12 @@ gst_pyramidsegment_chain (GstPad * pad, GstBuffer * buf)
* register the element factories and other features
*/
gboolean
gst_pyramidsegment_plugin_init (GstPlugin * plugin)
gst_pyramid_segment_plugin_init (GstPlugin * plugin)
{
/* debug category for fltering log messages */
GST_DEBUG_CATEGORY_INIT (gst_pyramidsegment_debug, "pyramidsegment",
GST_DEBUG_CATEGORY_INIT (gst_pyramid_segment_debug, "pyramidsegment",
0, "Applies pyramid segmentation to a video or image");
return gst_element_register (plugin, "pyramidsegment", GST_RANK_NONE,
GST_TYPE_PYRAMIDSEGMENT);
GST_TYPE_PYRAMID_SEGMENT);
}

View file

@ -43,28 +43,28 @@
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_PYRAMIDSEGMENT_H__
#define __GST_PYRAMIDSEGMENT_H__
#ifndef __GST_PYRAMID_SEGMENT_H__
#define __GST_PYRAMID_SEGMENT_H__
#include <gst/gst.h>
#include <cv.h>
G_BEGIN_DECLS
/* #defines don't like whitespacey bits */
#define GST_TYPE_PYRAMIDSEGMENT \
(gst_pyramidsegment_get_type())
#define GST_PYRAMIDSEGMENT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PYRAMIDSEGMENT,Gstpyramidsegment))
#define GST_PYRAMIDSEGMENT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PYRAMIDSEGMENT,GstpyramidsegmentClass))
#define GST_IS_PYRAMIDSEGMENT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PYRAMIDSEGMENT))
#define GST_IS_PYRAMIDSEGMENT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PYRAMIDSEGMENT))
typedef struct _Gstpyramidsegment Gstpyramidsegment;
typedef struct _GstpyramidsegmentClass GstpyramidsegmentClass;
#define GST_TYPE_PYRAMID_SEGMENT \
(gst_pyramid_segment_get_type())
#define GST_PYRAMID_SEGMENT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PYRAMID_SEGMENT,GstPyramidSegment))
#define GST_PYRAMID_SEGMENT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PYRAMID_SEGMENT,GstPyramidSegmentClass))
#define GST_IS_PYRAMID_SEGMENT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PYRAMID_SEGMENT))
#define GST_IS_PYRAMID_SEGMENT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PYRAMID_SEGMENT))
typedef struct _GstPyramidSegment GstPyramidSegment;
typedef struct _GstPyramidSegmentClass GstPyramidSegmentClass;
struct _Gstpyramidsegment
struct _GstPyramidSegment
{
GstElement element;
@ -83,14 +83,14 @@ struct _Gstpyramidsegment
int level;
};
struct _GstpyramidsegmentClass
struct _GstPyramidSegmentClass
{
GstElementClass parent_class;
};
GType gst_pyramidsegment_get_type (void);
GType gst_pyramid_segment_get_type (void);
gboolean gst_pyramidsegment_plugin_init (GstPlugin * plugin);
gboolean gst_pyramid_segment_plugin_init (GstPlugin * plugin);
G_END_DECLS
#endif /* __GST_PYRAMIDSEGMENT_H__ */
#endif /* __GST_PYRAMID_SEGMENT_H__ */

View file

@ -47,7 +47,7 @@
/**
* SECTION:element-templatematch
*
* FIXME:Describe templatematch here.
* Performs template matching on videos and images, providing detected positions via bus messages.
*
* <refsect2>
* <title>Example launch line</title>
@ -66,8 +66,8 @@
#include "gstopencvutils.h"
#include "gsttemplatematch.h"
GST_DEBUG_CATEGORY_STATIC (gst_templatematch_debug);
#define GST_CAT_DEFAULT gst_templatematch_debug
GST_DEBUG_CATEGORY_STATIC (gst_template_match_debug);
#define GST_CAT_DEFAULT gst_template_match_debug
#define DEFAULT_METHOD (3)
@ -100,33 +100,33 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB)
);
GST_BOILERPLATE (GstTemplateMatch, gst_templatematch, GstElement,
GST_BOILERPLATE (GstTemplateMatch, gst_template_match, GstElement,
GST_TYPE_ELEMENT);
static void gst_templatematch_finalize (GObject * object);
static void gst_templatematch_set_property (GObject * object, guint prop_id,
static void gst_template_match_finalize (GObject * object);
static void gst_template_match_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_templatematch_get_property (GObject * object, guint prop_id,
static void gst_template_match_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static gboolean gst_templatematch_set_caps (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_templatematch_chain (GstPad * pad, GstBuffer * buf);
static gboolean gst_template_match_set_caps (GstPad * pad, GstCaps * caps);
static GstFlowReturn gst_template_match_chain (GstPad * pad, GstBuffer * buf);
static void gst_templatematch_load_template (GstTemplateMatch * filter);
static void gst_templatematch_match (IplImage * input, IplImage * template,
static void gst_template_match_load_template (GstTemplateMatch * filter);
static void gst_template_match_match (IplImage * input, IplImage * template,
IplImage * dist_image, double *best_res, CvPoint * best_pos, int method);
/* GObject vmethod implementations */
static void
gst_templatematch_base_init (gpointer gclass)
gst_template_match_base_init (gpointer gclass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (gclass);
gst_element_class_set_details_simple (element_class,
"templatematch",
"Filter/Effect/Video",
"Performs template matching on videos and images, providing detected positions via bus messages",
"Performs template matching on videos and images, providing detected positions via bus messages.",
"Noam Lewis <jones.noamle@gmail.com>");
gst_element_class_add_pad_template (element_class,
@ -137,15 +137,15 @@ gst_templatematch_base_init (gpointer gclass)
/* initialize the templatematch's class */
static void
gst_templatematch_class_init (GstTemplateMatchClass * klass)
gst_template_match_class_init (GstTemplateMatchClass * klass)
{
GObjectClass *gobject_class;
gobject_class = (GObjectClass *) klass;
gobject_class->finalize = gst_templatematch_finalize;
gobject_class->set_property = gst_templatematch_set_property;
gobject_class->get_property = gst_templatematch_get_property;
gobject_class->finalize = gst_template_match_finalize;
gobject_class->set_property = gst_template_match_set_property;
gobject_class->get_property = gst_template_match_get_property;
g_object_class_install_property (gobject_class, PROP_METHOD,
g_param_spec_int ("method", "Method",
@ -166,16 +166,16 @@ gst_templatematch_class_init (GstTemplateMatchClass * klass)
* initialize instance structure
*/
static void
gst_templatematch_init (GstTemplateMatch * filter,
gst_template_match_init (GstTemplateMatch * filter,
GstTemplateMatchClass * gclass)
{
filter->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink");
gst_pad_set_setcaps_function (filter->sinkpad,
GST_DEBUG_FUNCPTR (gst_templatematch_set_caps));
GST_DEBUG_FUNCPTR (gst_template_match_set_caps));
gst_pad_set_getcaps_function (filter->sinkpad,
GST_DEBUG_FUNCPTR (gst_pad_proxy_getcaps));
gst_pad_set_chain_function (filter->sinkpad,
GST_DEBUG_FUNCPTR (gst_templatematch_chain));
GST_DEBUG_FUNCPTR (gst_template_match_chain));
filter->srcpad = gst_pad_new_from_static_template (&src_factory, "src");
gst_pad_set_getcaps_function (filter->srcpad,
@ -189,14 +189,14 @@ gst_templatematch_init (GstTemplateMatch * filter,
filter->cvDistImage = NULL;
filter->cvImage = NULL;
filter->method = DEFAULT_METHOD;
gst_templatematch_load_template (filter);
gst_template_match_load_template (filter);
}
static void
gst_templatematch_set_property (GObject * object, guint prop_id,
gst_template_match_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstTemplateMatch *filter = GST_TEMPLATEMATCH (object);
GstTemplateMatch *filter = GST_TEMPLATE_MATCH (object);
switch (prop_id) {
case PROP_METHOD:
@ -223,7 +223,7 @@ gst_templatematch_set_property (GObject * object, guint prop_id,
break;
case PROP_TEMPLATE:
filter->template = (char *) g_value_get_string (value);
gst_templatematch_load_template (filter);
gst_template_match_load_template (filter);
break;
case PROP_DISPLAY:
filter->display = g_value_get_boolean (value);
@ -235,10 +235,10 @@ gst_templatematch_set_property (GObject * object, guint prop_id,
}
static void
gst_templatematch_get_property (GObject * object, guint prop_id,
gst_template_match_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstTemplateMatch *filter = GST_TEMPLATEMATCH (object);
GstTemplateMatch *filter = GST_TEMPLATE_MATCH (object);
switch (prop_id) {
case PROP_METHOD:
@ -260,14 +260,14 @@ gst_templatematch_get_property (GObject * object, guint prop_id,
/* this function handles the link with other elements */
static gboolean
gst_templatematch_set_caps (GstPad * pad, GstCaps * caps)
gst_template_match_set_caps (GstPad * pad, GstCaps * caps)
{
GstTemplateMatch *filter;
GstPad *otherpad;
gint width, height;
GstStructure *structure;
filter = GST_TEMPLATEMATCH (gst_pad_get_parent (pad));
filter = GST_TEMPLATE_MATCH (gst_pad_get_parent (pad));
structure = gst_caps_get_structure (caps, 0);
gst_structure_get_int (structure, "width", &width);
gst_structure_get_int (structure, "height", &height);
@ -282,10 +282,10 @@ gst_templatematch_set_caps (GstPad * pad, GstCaps * caps)
}
static void
gst_templatematch_finalize (GObject * object)
gst_template_match_finalize (GObject * object)
{
GstTemplateMatch *filter;
filter = GST_TEMPLATEMATCH (object);
filter = GST_TEMPLATE_MATCH (object);
if (filter->cvImage) {
cvReleaseImageHeader (&filter->cvImage);
@ -302,13 +302,13 @@ gst_templatematch_finalize (GObject * object)
* this function does the actual processing
*/
static GstFlowReturn
gst_templatematch_chain (GstPad * pad, GstBuffer * buf)
gst_template_match_chain (GstPad * pad, GstBuffer * buf)
{
GstTemplateMatch *filter;
CvPoint best_pos;
double best_res;
filter = GST_TEMPLATEMATCH (GST_OBJECT_PARENT (pad));
filter = GST_TEMPLATE_MATCH (GST_OBJECT_PARENT (pad));
/* FIXME Why template == NULL returns OK?
* shouldn't it be a passthrough instead? */
@ -344,7 +344,7 @@ gst_templatematch_chain (GstPad * pad, GstBuffer * buf)
GstStructure *s;
GstMessage *m;
gst_templatematch_match (filter->cvImage, filter->cvTemplateImage,
gst_template_match_match (filter->cvImage, filter->cvTemplateImage,
filter->cvDistImage, &best_res, &best_pos, filter->method);
s = gst_structure_new ("template_match",
@ -376,7 +376,7 @@ gst_templatematch_chain (GstPad * pad, GstBuffer * buf)
static void
gst_templatematch_match (IplImage * input, IplImage * template,
gst_template_match_match (IplImage * input, IplImage * template,
IplImage * dist_image, double *best_res, CvPoint * best_pos, int method)
{
double dist_min = 0, dist_max = 0;
@ -397,7 +397,7 @@ gst_templatematch_match (IplImage * input, IplImage * template,
static void
gst_templatematch_load_template (GstTemplateMatch * filter)
gst_template_match_load_template (GstTemplateMatch * filter)
{
if (filter->template) {
filter->cvTemplateImage =
@ -416,13 +416,13 @@ gst_templatematch_load_template (GstTemplateMatch * filter)
* register the element factories and other features
*/
gboolean
gst_templatematch_plugin_init (GstPlugin * templatematch)
gst_template_match_plugin_init (GstPlugin * templatematch)
{
/* debug category for fltering log messages */
GST_DEBUG_CATEGORY_INIT (gst_templatematch_debug, "templatematch",
GST_DEBUG_CATEGORY_INIT (gst_template_match_debug, "templatematch",
0,
"Performs template matching on videos and images, providing detected positions via bus messages");
return gst_element_register (templatematch, "templatematch", GST_RANK_NONE,
GST_TYPE_TEMPLATEMATCH);
GST_TYPE_TEMPLATE_MATCH);
}

View file

@ -43,8 +43,8 @@
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_TEMPLATEMATCH_H__
#define __GST_TEMPLATEMATCH_H__
#ifndef __GST_TEMPLATE_MATCH_H__
#define __GST_TEMPLATE_MATCH_H__
#include <gst/gst.h>
#include <cv.h>
@ -52,16 +52,16 @@
G_BEGIN_DECLS
/* #defines don't like whitespacey bits */
#define GST_TYPE_TEMPLATEMATCH \
(gst_templatematch_get_type())
#define GST_TEMPLATEMATCH(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEMPLATEMATCH,GstTemplateMatch))
#define GST_TEMPLATEMATCH_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEMPLATEMATCH,GstTemplateMatchClass))
#define GST_IS_TEMPLATEMATCH(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TEMPLATEMATCH))
#define GST_IS_TEMPLATEMATCH_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TEMPLATEMATCH))
#define GST_TYPE_TEMPLATE_MATCH \
(gst_template_match_get_type())
#define GST_TEMPLATE_MATCH(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TEMPLATE_MATCH,GstTemplateMatch))
#define GST_TEMPLATE_MATCH_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TEMPLATE_MATCH,GstTemplateMatchClass))
#define GST_IS_TEMPLATE_MATCH(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TEMPLATE_MATCH))
#define GST_IS_TEMPLATE_MATCH_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TEMPLATE_MATCH))
typedef struct _GstTemplateMatch GstTemplateMatch;
typedef struct _GstTemplateMatchClass GstTemplateMatchClass;
@ -84,9 +84,9 @@ struct _GstTemplateMatchClass
GstElementClass parent_class;
};
GType gst_templatematch_get_type (void);
GType gst_template_match_get_type (void);
gboolean gst_templatematch_plugin_init (GstPlugin * templatematch);
gboolean gst_template_match_plugin_init (GstPlugin * templatematch);
G_END_DECLS
#endif /* __GST_TEMPLATEMATCH_H__ */
#endif /* __GST_TEMPLATE_MATCH_H__ */

View file

@ -1,6 +1,6 @@
plugin_LTLIBRARIES = libgstopus.la
libgstopus_la_SOURCES = gstopus.c gstopusdec.c gstopusenc.c gstopusparse.c
libgstopus_la_SOURCES = gstopus.c gstopusdec.c gstopusenc.c gstopusparse.c gstopusheader.c
libgstopus_la_CFLAGS = \
-DGST_USE_UNSTABLE_API \
$(GST_PLUGINS_BASE_CFLAGS) \
@ -15,4 +15,4 @@ libgstopus_la_LIBADD = \
libgstopus_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) $(LIBM)
libgstopus_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstopusenc.h gstopusdec.h gstopusparse.h
noinst_HEADERS = gstopusenc.h gstopusdec.h gstopusparse.h gstopusheader.h

View file

@ -41,9 +41,10 @@
# include "config.h"
#endif
#include "gstopusdec.h"
#include <string.h>
#include <gst/tag/tag.h>
#include "gstopusheader.h"
#include "gstopusdec.h"
GST_DEBUG_CATEGORY_STATIC (opusdec_debug);
#define GST_CAT_DEFAULT opusdec_debug
@ -114,6 +115,8 @@ gst_opus_dec_reset (GstOpusDec * dec)
gst_buffer_replace (&dec->streamheader, NULL);
gst_buffer_replace (&dec->vorbiscomment, NULL);
dec->pre_skip = 0;
}
static void
@ -151,9 +154,17 @@ gst_opus_dec_stop (GstAudioDecoder * dec)
static GstFlowReturn
gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf)
{
g_return_val_if_fail (gst_opus_header_is_header (buf, "OpusHead", 8),
GST_FLOW_ERROR);
g_return_val_if_fail (GST_BUFFER_SIZE (buf) >= 19, GST_FLOW_ERROR);
dec->pre_skip = GST_READ_UINT16_LE (GST_BUFFER_DATA (buf) + 10);
GST_INFO_OBJECT (dec, "Found pre-skip of %u samples", dec->pre_skip);
return GST_FLOW_OK;
}
static GstFlowReturn
gst_opus_dec_parse_comments (GstOpusDec * dec, GstBuffer * buf)
{
@ -235,11 +246,18 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf)
size = 0;
}
samples =
opus_packet_get_samples_per_frame (data,
dec->sample_rate) * opus_packet_get_nb_frames (data, size);
GST_DEBUG ("bandwidth %d", opus_packet_get_bandwidth (data));
GST_DEBUG ("samples %d", samples);
if (data) {
samples =
opus_packet_get_samples_per_frame (data,
dec->sample_rate) * opus_packet_get_nb_frames (data, size);
packet_size = samples * dec->n_channels * 2;
GST_DEBUG_OBJECT (dec, "bandwidth %d", opus_packet_get_bandwidth (data));
GST_DEBUG_OBJECT (dec, "samples %d", samples);
} else {
/* use maximum size (120 ms) as we do now know in advance how many samples
will be returned */
samples = 120 * dec->sample_rate / 1000;
}
packet_size = samples * dec->n_channels * 2;
outbuf = gst_buffer_new_and_alloc (packet_size);
@ -249,8 +267,6 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf)
out_data = (gint16 *) gst_buffer_map (outbuf, &out_size, NULL, GST_MAP_WRITE);
GST_LOG_OBJECT (dec, "decoding %d samples, in size %u", samples, size);
n = opus_decode (dec->state, data, size, out_data, samples, 0);
gst_buffer_unmap (buf, data, size);
gst_buffer_unmap (outbuf, out_data, out_size);
@ -259,6 +275,25 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buf)
return GST_FLOW_ERROR;
}
GST_DEBUG_OBJECT (dec, "decoded %d samples", n);
GST_BUFFER_SIZE (outbuf) = n * 2 * dec->n_channels;
/* Skip any samples that need skipping */
if (dec->pre_skip > 0) {
guint scaled_pre_skip = dec->pre_skip * dec->sample_rate / 48000;
guint skip = scaled_pre_skip > n ? n : scaled_pre_skip;
guint scaled_skip = skip * 48000 / dec->sample_rate;
GST_BUFFER_SIZE (outbuf) -= skip * 2 * dec->n_channels;
GST_BUFFER_DATA (outbuf) += skip * 2 * dec->n_channels;
dec->pre_skip -= scaled_skip;
GST_INFO_OBJECT (dec,
"Skipping %u samples (%u at 48000 Hz, %u left to skip)", skip,
scaled_skip, dec->pre_skip);
if (GST_BUFFER_SIZE (outbuf) == 0) {
gst_buffer_unref (outbuf);
outbuf = NULL;
}
}
res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), outbuf, 1);
@ -337,21 +372,6 @@ memcmp_buffers (GstBuffer * buf1, GstBuffer * buf2)
return res;
}
static gboolean
gst_opus_dec_is_header (GstBuffer * buf, const char *magic, guint magic_size)
{
guint8 *data;
gsize size;
gboolean ret;
data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
if (!data)
return FALSE;
ret = (size >= magic_size && !memcmp (magic, data, magic_size));
gst_buffer_unmap (buf, data, size);
return ret;
}
static GstFlowReturn
gst_opus_dec_handle_frame (GstAudioDecoder * adec, GstBuffer * buf)
{
@ -384,10 +404,10 @@ gst_opus_dec_handle_frame (GstAudioDecoder * adec, GstBuffer * buf)
}
} else {
/* Otherwise fall back to packet counting and assume that the
* first two packets are the headers. */
* first two packets might be the headers, checking magic. */
switch (dec->packetno) {
case 0:
if (gst_opus_dec_is_header (buf, "OpusHead", 8)) {
if (gst_opus_header_is_header (buf, "OpusHead", 8)) {
GST_DEBUG_OBJECT (dec, "found streamheader");
res = gst_opus_dec_parse_header (dec, buf);
gst_audio_decoder_finish_frame (adec, NULL, 1);
@ -396,7 +416,7 @@ gst_opus_dec_handle_frame (GstAudioDecoder * adec, GstBuffer * buf)
}
break;
case 1:
if (gst_opus_dec_is_header (buf, "OpusTags", 8)) {
if (gst_opus_header_is_header (buf, "OpusTags", 8)) {
GST_DEBUG_OBJECT (dec, "counted vorbiscomments");
res = gst_opus_dec_parse_comments (dec, buf);
gst_audio_decoder_finish_frame (adec, NULL, 1);

View file

@ -53,6 +53,7 @@ struct _GstOpusDec {
int sample_rate;
int n_channels;
guint32 pre_skip;
};
struct _GstOpusDecClass {

View file

@ -1,6 +1,7 @@
/* GStreamer Opus Encoder
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk>
* Copyright (C) <2011> Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -46,14 +47,19 @@
#include <opus/opus.h>
#include <gst/gsttagsetter.h>
#include <gst/tag/tag.h>
#include <gst/base/gstbytewriter.h>
#include <gst/audio/audio.h>
#include "gstopusheader.h"
#include "gstopusenc.h"
GST_DEBUG_CATEGORY_STATIC (opusenc_debug);
#define GST_CAT_DEFAULT opusenc_debug
/* Some arbitrary bounds beyond which it really doesn't make sense.
The spec mentions 6 kb/s to 510 kb/s, so 4000 and 650000 ought to be
safe as property bounds. */
#define LOWEST_BITRATE 4000
#define HIGHEST_BITRATE 650000
#define GST_OPUS_ENC_TYPE_BANDWIDTH (gst_opus_enc_bandwidth_get_type())
static GType
gst_opus_enc_bandwidth_get_type (void)
@ -80,8 +86,33 @@ gst_opus_enc_bandwidth_get_type (void)
return id;
}
#define FORMAT_STR GST_AUDIO_NE(S16)
#define GST_OPUS_ENC_TYPE_FRAME_SIZE (gst_opus_enc_frame_size_get_type())
static GType
gst_opus_enc_frame_size_get_type (void)
{
static const GEnumValue values[] = {
{2, "2.5", "2.5"},
{5, "5", "5"},
{10, "10", "10"},
{20, "20", "20"},
{40, "40", "40"},
{60, "60", "60"},
{0, NULL, NULL}
};
static volatile GType id = 0;
if (g_once_init_enter ((gsize *) & id)) {
GType _id;
_id = g_enum_register_static ("GstOpusEncFrameSize", values);
g_once_init_leave ((gsize *) & id, _id);
}
return id;
}
#define FORMAT_STR GST_AUDIO_NE(S16)
static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
@ -107,6 +138,7 @@ static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src",
#define DEFAULT_INBAND_FEC FALSE
#define DEFAULT_DTX FALSE
#define DEFAULT_PACKET_LOSS_PERCENT 0
#define DEFAULT_MAX_PAYLOAD_SIZE 1024
enum
{
@ -120,7 +152,8 @@ enum
PROP_COMPLEXITY,
PROP_INBAND_FEC,
PROP_DTX,
PROP_PACKET_LOSS_PERCENT
PROP_PACKET_LOSS_PERCENT,
PROP_MAX_PAYLOAD_SIZE
};
static void gst_opus_enc_finalize (GObject * object);
@ -140,8 +173,6 @@ static gboolean gst_opus_enc_set_format (GstAudioEncoder * benc,
GstAudioInfo * info);
static GstFlowReturn gst_opus_enc_handle_frame (GstAudioEncoder * benc,
GstBuffer * buf);
static GstFlowReturn gst_opus_enc_pre_push (GstAudioEncoder * benc,
GstBuffer ** buffer);
static gint64 gst_opus_enc_get_latency (GstOpusEnc * enc);
static GstFlowReturn gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buffer);
@ -181,7 +212,6 @@ gst_opus_enc_class_init (GstOpusEncClass * klass)
base_class->stop = GST_DEBUG_FUNCPTR (gst_opus_enc_stop);
base_class->set_format = GST_DEBUG_FUNCPTR (gst_opus_enc_set_format);
base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_opus_enc_handle_frame);
base_class->pre_push = GST_DEBUG_FUNCPTR (gst_opus_enc_pre_push);
base_class->event = GST_DEBUG_FUNCPTR (gst_opus_enc_sink_event);
g_object_class_install_property (gobject_class, PROP_AUDIO,
@ -191,40 +221,56 @@ gst_opus_enc_class_init (GstOpusEncClass * klass)
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BITRATE,
g_param_spec_int ("bitrate", "Encoding Bit-rate",
"Specify an encoding bit-rate (in bps).",
1, 320000, DEFAULT_BITRATE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
LOWEST_BITRATE, HIGHEST_BITRATE, DEFAULT_BITRATE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_PLAYING));
g_object_class_install_property (gobject_class, PROP_BANDWIDTH,
g_param_spec_enum ("bandwidth", "Band Width",
"Audio Band Width", GST_OPUS_ENC_TYPE_BANDWIDTH, DEFAULT_BANDWIDTH,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_param_spec_enum ("bandwidth", "Band Width", "Audio Band Width",
GST_OPUS_ENC_TYPE_BANDWIDTH, DEFAULT_BANDWIDTH,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_PLAYING));
g_object_class_install_property (gobject_class, PROP_FRAME_SIZE,
g_param_spec_int ("frame-size", "Frame Size",
"The duration of an audio frame, in ms", 2, 60, DEFAULT_FRAMESIZE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_param_spec_enum ("frame-size", "Frame Size",
"The duration of an audio frame, in ms", GST_OPUS_ENC_TYPE_FRAME_SIZE,
DEFAULT_FRAMESIZE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_PLAYING));
g_object_class_install_property (gobject_class, PROP_CBR,
g_param_spec_boolean ("cbr", "Constant bit rate",
"Constant bit rate", DEFAULT_CBR,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_param_spec_boolean ("cbr", "Constant bit rate", "Constant bit rate",
DEFAULT_CBR,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_PLAYING));
g_object_class_install_property (gobject_class, PROP_CONSTRAINED_VBR,
g_param_spec_boolean ("constrained-vbr", "Constrained VBR",
"Constrained VBR", DEFAULT_CONSTRAINED_VBR,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_PLAYING));
g_object_class_install_property (gobject_class, PROP_COMPLEXITY,
g_param_spec_int ("complexity", "Complexity",
"Complexity", 0, 10, DEFAULT_COMPLEXITY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_param_spec_int ("complexity", "Complexity", "Complexity", 0, 10,
DEFAULT_COMPLEXITY,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_PLAYING));
g_object_class_install_property (gobject_class, PROP_INBAND_FEC,
g_param_spec_boolean ("inband-fec", "In-band FEC",
"Enable forward error correction", DEFAULT_INBAND_FEC,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_PLAYING));
g_object_class_install_property (gobject_class, PROP_DTX,
g_param_spec_boolean ("dtx", "DTX",
"DTX", DEFAULT_DTX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_param_spec_boolean ("dtx", "DTX", "DTX", DEFAULT_DTX,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_PLAYING));
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_PACKET_LOSS_PERCENT, g_param_spec_int ("packet-loss-percentage",
"Loss percentage", "Packet loss percentage", 0, 100,
DEFAULT_PACKET_LOSS_PERCENT,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_PLAYING));
g_object_class_install_property (G_OBJECT_CLASS (klass),
PROP_MAX_PAYLOAD_SIZE, g_param_spec_uint ("max-payload-size",
"Max payload size", "Maximum payload size in bytes", 2, 1275,
DEFAULT_MAX_PAYLOAD_SIZE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
GST_PARAM_MUTABLE_PLAYING));
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_opus_enc_finalize);
@ -238,6 +284,8 @@ gst_opus_enc_finalize (GObject * object)
enc = GST_OPUS_ENC (object);
g_mutex_free (enc->property_lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
@ -248,6 +296,8 @@ gst_opus_enc_init (GstOpusEnc * enc, GstOpusEncClass * klass)
GST_DEBUG_OBJECT (enc, "init");
enc->property_lock = g_mutex_new ();
enc->n_channels = -1;
enc->sample_rate = -1;
enc->frame_samples = 0;
@ -261,6 +311,7 @@ gst_opus_enc_init (GstOpusEnc * enc, GstOpusEncClass * klass)
enc->inband_fec = DEFAULT_INBAND_FEC;
enc->dtx = DEFAULT_DTX;
enc->packet_loss_percentage = DEFAULT_PACKET_LOSS_PERCENT;
enc->max_payload_size = DEFAULT_MAX_PAYLOAD_SIZE;
/* arrange granulepos marking (and required perfect ts) */
gst_audio_encoder_set_mark_granule (benc, TRUE);
@ -275,6 +326,7 @@ gst_opus_enc_start (GstAudioEncoder * benc)
GST_DEBUG_OBJECT (enc, "start");
enc->tags = gst_tag_list_new ();
enc->header_sent = FALSE;
return TRUE;
}
@ -293,6 +345,7 @@ gst_opus_enc_stop (GstAudioEncoder * benc)
enc->tags = NULL;
g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
enc->headers = NULL;
gst_tag_setter_reset_tags (GST_TAG_SETTER (enc));
return TRUE;
}
@ -306,6 +359,18 @@ gst_opus_enc_get_latency (GstOpusEnc * enc)
return latency;
}
static void
gst_opus_enc_setup_base_class (GstOpusEnc * enc, GstAudioEncoder * benc)
{
gst_audio_encoder_set_latency (benc,
gst_opus_enc_get_latency (enc), gst_opus_enc_get_latency (enc));
gst_audio_encoder_set_frame_samples_min (benc,
enc->frame_samples * enc->n_channels * 2);
gst_audio_encoder_set_frame_samples_max (benc,
enc->frame_samples * enc->n_channels * 2);
gst_audio_encoder_set_frame_max (benc, 0);
}
static gint
gst_opus_enc_get_frame_samples (GstOpusEnc * enc)
{
@ -344,6 +409,8 @@ gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
enc = GST_OPUS_ENC (benc);
g_mutex_lock (enc->property_lock);
enc->n_channels = GST_AUDIO_INFO_CHANNELS (info);
enc->sample_rate = GST_AUDIO_INFO_RATE (info);
GST_DEBUG_OBJECT (benc, "Setup with %d channels, %d Hz", enc->n_channels,
@ -360,72 +427,13 @@ gst_opus_enc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
enc->frame_samples = gst_opus_enc_get_frame_samples (enc);
/* feedback to base class */
gst_audio_encoder_set_latency (benc,
gst_opus_enc_get_latency (enc), gst_opus_enc_get_latency (enc));
gst_audio_encoder_set_frame_samples_min (benc,
enc->frame_samples * enc->n_channels * 2);
gst_audio_encoder_set_frame_samples_max (benc,
enc->frame_samples * enc->n_channels * 2);
gst_audio_encoder_set_frame_max (benc, 0);
gst_opus_enc_setup_base_class (enc, benc);
g_mutex_unlock (enc->property_lock);
return TRUE;
}
static GstBuffer *
gst_opus_enc_create_id_buffer (GstOpusEnc * enc)
{
GstBuffer *buffer;
GstByteWriter bw;
gst_byte_writer_init (&bw);
/* See http://wiki.xiph.org/OggOpus */
gst_byte_writer_put_string_utf8 (&bw, "OpusHead");
gst_byte_writer_put_uint8 (&bw, 0); /* version number */
gst_byte_writer_put_uint8 (&bw, enc->n_channels);
gst_byte_writer_put_uint16_le (&bw, 0); /* pre-skip *//* TODO: endianness ? */
gst_byte_writer_put_uint32_le (&bw, enc->sample_rate);
gst_byte_writer_put_uint16_le (&bw, 0); /* output gain *//* TODO: endianness ? */
gst_byte_writer_put_uint8 (&bw, 0); /* channel mapping *//* TODO: what is this ? */
buffer = gst_byte_writer_reset_and_get_buffer (&bw);
GST_BUFFER_OFFSET (buffer) = 0;
GST_BUFFER_OFFSET_END (buffer) = 0;
return buffer;
}
static GstBuffer *
gst_opus_enc_create_metadata_buffer (GstOpusEnc * enc)
{
const GstTagList *tags;
GstTagList *empty_tags = NULL;
GstBuffer *comments = NULL;
tags = gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc));
GST_DEBUG_OBJECT (enc, "tags = %" GST_PTR_FORMAT, tags);
if (tags == NULL) {
/* FIXME: better fix chain of callers to not write metadata at all,
* if there is none */
empty_tags = gst_tag_list_new_empty ();
tags = empty_tags;
}
comments =
gst_tag_list_to_vorbiscomment_buffer (tags, (const guint8 *) "OpusTags",
8, "Encoded with GStreamer Opusenc");
GST_BUFFER_OFFSET (comments) = 0;
GST_BUFFER_OFFSET_END (comments) = 0;
if (empty_tags)
gst_tag_list_free (empty_tags);
return comments;
}
static gboolean
gst_opus_enc_setup (GstOpusEnc * enc)
{
@ -490,78 +498,15 @@ gst_opus_enc_sink_event (GstAudioEncoder * benc, GstEvent * event)
return FALSE;
}
static GstFlowReturn
gst_opus_enc_pre_push (GstAudioEncoder * benc, GstBuffer ** buffer)
{
GstFlowReturn ret = GST_FLOW_OK;
GstOpusEnc *enc;
enc = GST_OPUS_ENC (benc);
/* FIXME 0.11 ? get rid of this special ogg stuff and have it
* put and use 'codec data' in caps like anything else,
* with all the usual out-of-band advantage etc */
if (G_UNLIKELY (enc->headers)) {
GSList *header = enc->headers;
/* try to push all of these, if we lose one, might as well lose all */
while (header) {
if (ret == GST_FLOW_OK)
ret = gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), header->data);
else
gst_pad_push (GST_AUDIO_ENCODER_SRC_PAD (enc), header->data);
header = g_slist_next (header);
}
g_slist_free (enc->headers);
enc->headers = NULL;
}
return ret;
}
static GstFlowReturn
gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf)
{
guint8 *bdata, *data, *mdata = NULL;
gsize bsize, size;
gsize bytes = enc->frame_samples * enc->n_channels * 2;
gsize bytes_per_packet =
(enc->bitrate * enc->frame_samples / enc->sample_rate + 4) / 8;
gint ret = GST_FLOW_OK;
if (G_LIKELY (buf)) {
bdata = GST_BUFFER_DATA (buf);
bsize = GST_BUFFER_SIZE (buf);
if (G_UNLIKELY (bsize % bytes)) {
GST_DEBUG_OBJECT (enc, "draining; adding silence samples");
size = ((bsize / bytes) + 1) * bytes;
mdata = g_malloc0 (size);
memcpy (mdata, bdata, bsize);
bdata = NULL;
data = mdata;
} else {
data = bdata;
size = bsize;
}
} else {
GST_DEBUG_OBJECT (enc, "nothing to drain");
goto done;
}
return ret;
}
static GstFlowReturn
gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf)
{
guint8 *bdata, *data, *mdata = NULL;
gsize bsize, size;
gsize bytes = enc->frame_samples * enc->n_channels * 2;
gsize bytes_per_packet =
(enc->bitrate * enc->frame_samples / enc->sample_rate + 4) / 8;
gint ret = GST_FLOW_OK;
g_mutex_lock (enc->property_lock);
if (G_LIKELY (buf)) {
bdata = gst_buffer_map (buf, &bsize, NULL, GST_MAP_READ);
@ -590,31 +535,33 @@ gst_opus_enc_encode (GstOpusEnc * enc, GstBuffer * buf)
gsize out_size;
GstBuffer *outbuf;
outbuf = gst_buffer_new_and_alloc (bytes_per_packet);
outbuf = gst_buffer_new_and_alloc (enc->max_payload_size);
if (!outbuf)
goto done;
GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes) to %d bytes",
enc->frame_samples, bytes, bytes_per_packet);
GST_DEBUG_OBJECT (enc, "encoding %d samples (%d bytes)",
enc->frame_samples);
out_data = gst_buffer_map (outbuf, &out_size, NULL, GST_MAP_WRITE);
encoded_size =
opus_encode (enc->state, (const gint16 *) data, enc->frame_samples,
out_data, bytes_per_packet);
out_data, enc->max_payload_size);
gst_buffer_unmap (outbuf, out_data, out_size);
if (encoded_size < 0) {
GST_ERROR_OBJECT (enc, "Encoding failed: %d", encoded_size);
ret = GST_FLOW_ERROR;
goto done;
} else if (encoded_size != bytes_per_packet) {
} else if (encoded_size > enc->max_payload_size) {
GST_WARNING_OBJECT (enc,
"Encoded size %d is different from %d bytes per packet", encoded_size,
bytes_per_packet);
"Encoded size %d is higher than max payload size (%d bytes)",
outsize, enc->max_payload_size);
ret = GST_FLOW_ERROR;
goto done;
}
GST_BUFFER_SIZE (outbuf) = outsize;
ret =
gst_audio_encoder_finish_frame (GST_AUDIO_ENCODER (enc), outbuf,
enc->frame_samples);
@ -630,69 +577,14 @@ done:
if (bdata)
gst_buffer_unmap (buf, bdata, bsize);
g_mutex_unlock (enc->property_lock);
if (mdata)
g_free (mdata);
return ret;
}
/*
* (really really) FIXME: move into core (dixit tpm)
*/
/**
* _gst_caps_set_buffer_array:
* @caps: a #GstCaps
* @field: field in caps to set
* @buf: header buffers
*
* Adds given buffers to an array of buffers set as the given @field
* on the given @caps. List of buffer arguments must be NULL-terminated.
*
* Returns: input caps with a streamheader field added, or NULL if some error
*/
static GstCaps *
_gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
GstBuffer * buf, ...)
{
GstStructure *structure = NULL;
va_list va;
GValue array = { 0 };
GValue value = { 0 };
g_return_val_if_fail (caps != NULL, NULL);
g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
g_return_val_if_fail (field != NULL, NULL);
caps = gst_caps_make_writable (caps);
structure = gst_caps_get_structure (caps, 0);
g_value_init (&array, GST_TYPE_ARRAY);
va_start (va, buf);
/* put buffers in a fixed list */
while (buf) {
g_assert (gst_buffer_is_writable (buf));
/* mark buffer */
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
g_value_init (&value, GST_TYPE_BUFFER);
buf = gst_buffer_copy (buf);
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
gst_value_set_buffer (&value, buf);
gst_buffer_unref (buf);
gst_value_array_append_value (&array, &value);
g_value_unset (&value);
buf = va_arg (va, GstBuffer *);
}
gst_structure_set_value (structure, field, &array);
g_value_unset (&array);
return caps;
}
static GstFlowReturn
gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
{
@ -703,32 +595,20 @@ gst_opus_enc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
GST_DEBUG_OBJECT (enc, "handle_frame");
if (!enc->header_sent) {
/* Opus streams in Ogg begin with two headers; the initial header (with
most of the codec setup parameters) which is mandated by the Ogg
bitstream spec. The second header holds any comment fields. */
GstBuffer *buf1, *buf2;
GstCaps *caps;
/* create header buffers */
buf1 = gst_opus_enc_create_id_buffer (enc);
buf2 = gst_opus_enc_create_metadata_buffer (enc);
g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
enc->headers = NULL;
gst_opus_header_create_caps (&caps, &enc->headers, enc->n_channels,
enc->sample_rate, gst_tag_setter_get_tag_list (GST_TAG_SETTER (enc)));
/* mark and put on caps */
caps = gst_caps_from_string ("audio/x-opus");
caps = _gst_caps_set_buffer_array (caps, "streamheader", buf1, buf2, NULL);
/* negotiate with these caps */
GST_DEBUG_OBJECT (enc, "here are the caps: %" GST_PTR_FORMAT, caps);
gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (enc), caps);
/* push out buffers */
/* store buffers for later pre_push sending */
g_slist_foreach (enc->headers, (GFunc) gst_buffer_unref, NULL);
enc->headers = NULL;
GST_DEBUG_OBJECT (enc, "storing header buffers");
enc->headers = g_slist_prepend (enc->headers, buf2);
enc->headers = g_slist_prepend (enc->headers, buf1);
enc->header_sent = TRUE;
}
@ -748,6 +628,8 @@ gst_opus_enc_get_property (GObject * object, guint prop_id, GValue * value,
enc = GST_OPUS_ENC (object);
g_mutex_lock (enc->property_lock);
switch (prop_id) {
case PROP_AUDIO:
g_value_set_boolean (value, enc->audio_or_voip);
@ -759,7 +641,7 @@ gst_opus_enc_get_property (GObject * object, guint prop_id, GValue * value,
g_value_set_enum (value, enc->bandwidth);
break;
case PROP_FRAME_SIZE:
g_value_set_int (value, enc->frame_size);
g_value_set_enum (value, enc->frame_size);
break;
case PROP_CBR:
g_value_set_boolean (value, enc->cbr);
@ -779,10 +661,15 @@ gst_opus_enc_get_property (GObject * object, guint prop_id, GValue * value,
case PROP_PACKET_LOSS_PERCENT:
g_value_set_int (value, enc->packet_loss_percentage);
break;
case PROP_MAX_PAYLOAD_SIZE:
g_value_set_uint (value, enc->max_payload_size);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
g_mutex_unlock (enc->property_lock);
}
static void
@ -793,39 +680,64 @@ gst_opus_enc_set_property (GObject * object, guint prop_id,
enc = GST_OPUS_ENC (object);
#define GST_OPUS_UPDATE_PROPERTY(prop,type,ctl) do { \
g_mutex_lock (enc->property_lock); \
enc->prop = g_value_get_##type (value); \
if (enc->state) { \
opus_encoder_ctl (enc->state, OPUS_SET_##ctl (enc->prop)); \
} \
g_mutex_unlock (enc->property_lock); \
} while(0)
switch (prop_id) {
case PROP_AUDIO:
enc->audio_or_voip = g_value_get_boolean (value);
break;
case PROP_BITRATE:
enc->bitrate = g_value_get_int (value);
GST_OPUS_UPDATE_PROPERTY (bitrate, int, BITRATE);
break;
case PROP_BANDWIDTH:
enc->bandwidth = g_value_get_enum (value);
GST_OPUS_UPDATE_PROPERTY (bandwidth, enum, BANDWIDTH);
break;
case PROP_FRAME_SIZE:
enc->frame_size = g_value_get_int (value);
g_mutex_lock (enc->property_lock);
enc->frame_size = g_value_get_enum (value);
enc->frame_samples = gst_opus_enc_get_frame_samples (enc);
gst_opus_enc_setup_base_class (enc, GST_AUDIO_ENCODER (enc));
g_mutex_unlock (enc->property_lock);
break;
case PROP_CBR:
/* this one has an opposite meaning to the opus ctl... */
g_mutex_lock (enc->property_lock);
enc->cbr = g_value_get_boolean (value);
opus_encoder_ctl (enc->state, OPUS_SET_VBR (!enc->cbr));
g_mutex_unlock (enc->property_lock);
break;
case PROP_CONSTRAINED_VBR:
enc->constrained_vbr = g_value_get_boolean (value);
GST_OPUS_UPDATE_PROPERTY (constrained_vbr, boolean, VBR_CONSTRAINT);
break;
case PROP_COMPLEXITY:
enc->complexity = g_value_get_int (value);
GST_OPUS_UPDATE_PROPERTY (complexity, int, COMPLEXITY);
break;
case PROP_INBAND_FEC:
enc->inband_fec = g_value_get_boolean (value);
GST_OPUS_UPDATE_PROPERTY (inband_fec, boolean, INBAND_FEC);
break;
case PROP_DTX:
enc->dtx = g_value_get_boolean (value);
GST_OPUS_UPDATE_PROPERTY (dtx, boolean, DTX);
break;
case PROP_PACKET_LOSS_PERCENT:
enc->packet_loss_percentage = g_value_get_int (value);
GST_OPUS_UPDATE_PROPERTY (packet_loss_percentage, int, PACKET_LOSS_PERC);
break;
case PROP_MAX_PAYLOAD_SIZE:
g_mutex_lock (enc->property_lock);
enc->max_payload_size = g_value_get_uint (value);
g_mutex_unlock (enc->property_lock);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
#undef GST_OPUS_UPDATE_PROPERTY
}

View file

@ -52,6 +52,9 @@ struct _GstOpusEnc {
OpusEncoder *state;
/* Locks those properties which may be changed at play time */
GMutex *property_lock;
/* properties */
gboolean audio_or_voip;
gint bitrate;
@ -63,6 +66,7 @@ struct _GstOpusEnc {
gboolean inband_fec;
gboolean dtx;
gint packet_loss_percentage;
guint max_payload_size;
gint frame_samples;
gint n_channels;

170
ext/opus/gstopusheader.c Normal file
View file

@ -0,0 +1,170 @@
/* GStreamer Opus Encoder
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk>
* Copyright (C) <2011> Vincent Penquerc'h <vincent.penquerch@collabora.co.uk>
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <gst/tag/tag.h>
#include <gst/base/gstbytewriter.h>
#include "gstopusheader.h"
static GstBuffer *
gst_opus_enc_create_id_buffer (gint nchannels, gint sample_rate)
{
GstBuffer *buffer;
GstByteWriter bw;
gst_byte_writer_init (&bw);
/* See http://wiki.xiph.org/OggOpus */
gst_byte_writer_put_data (&bw, (const guint8 *) "OpusHead", 8);
gst_byte_writer_put_uint8 (&bw, 0); /* version number */
gst_byte_writer_put_uint8 (&bw, nchannels);
gst_byte_writer_put_uint16_le (&bw, 0); /* pre-skip *//* TODO: endianness ? */
gst_byte_writer_put_uint32_le (&bw, sample_rate);
gst_byte_writer_put_uint16_le (&bw, 0); /* output gain *//* TODO: endianness ? */
gst_byte_writer_put_uint8 (&bw, 0); /* channel mapping *//* TODO: what is this ? */
buffer = gst_byte_writer_reset_and_get_buffer (&bw);
GST_BUFFER_OFFSET (buffer) = 0;
GST_BUFFER_OFFSET_END (buffer) = 0;
return buffer;
}
static GstBuffer *
gst_opus_enc_create_metadata_buffer (const GstTagList * tags)
{
GstTagList *empty_tags = NULL;
GstBuffer *comments = NULL;
GST_DEBUG ("tags = %" GST_PTR_FORMAT, tags);
if (tags == NULL) {
/* FIXME: better fix chain of callers to not write metadata at all,
* if there is none */
empty_tags = gst_tag_list_new ();
tags = empty_tags;
}
comments =
gst_tag_list_to_vorbiscomment_buffer (tags, (const guint8 *) "OpusTags",
8, "Encoded with GStreamer Opusenc");
GST_BUFFER_OFFSET (comments) = 0;
GST_BUFFER_OFFSET_END (comments) = 0;
if (empty_tags)
gst_tag_list_free (empty_tags);
return comments;
}
/*
* (really really) FIXME: move into core (dixit tpm)
*/
/**
* _gst_caps_set_buffer_array:
* @caps: a #GstCaps
* @field: field in caps to set
* @buf: header buffers
*
* Adds given buffers to an array of buffers set as the given @field
* on the given @caps. List of buffer arguments must be NULL-terminated.
*
* Returns: input caps with a streamheader field added, or NULL if some error
*/
static GstCaps *
_gst_caps_set_buffer_array (GstCaps * caps, const gchar * field,
GstBuffer * buf, ...)
{
GstStructure *structure = NULL;
va_list va;
GValue array = { 0 };
GValue value = { 0 };
g_return_val_if_fail (caps != NULL, NULL);
g_return_val_if_fail (gst_caps_is_fixed (caps), NULL);
g_return_val_if_fail (field != NULL, NULL);
caps = gst_caps_make_writable (caps);
structure = gst_caps_get_structure (caps, 0);
g_value_init (&array, GST_TYPE_ARRAY);
va_start (va, buf);
/* put buffers in a fixed list */
while (buf) {
g_assert (gst_buffer_is_writable (buf));
/* mark buffer */
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
g_value_init (&value, GST_TYPE_BUFFER);
buf = gst_buffer_copy (buf);
GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
gst_value_set_buffer (&value, buf);
gst_buffer_unref (buf);
gst_value_array_append_value (&array, &value);
g_value_unset (&value);
buf = va_arg (va, GstBuffer *);
}
gst_structure_set_value (structure, field, &array);
g_value_unset (&array);
return caps;
}
void
gst_opus_header_create_caps (GstCaps ** caps, GSList ** headers, gint nchannels,
gint sample_rate, const GstTagList * tags)
{
GstBuffer *buf1, *buf2;
g_return_if_fail (caps);
g_return_if_fail (headers && !*headers);
g_return_if_fail (nchannels > 0);
g_return_if_fail (sample_rate >= 0); /* 0 -> unset */
/* Opus streams in Ogg begin with two headers; the initial header (with
most of the codec setup parameters) which is mandated by the Ogg
bitstream spec. The second header holds any comment fields. */
/* create header buffers */
buf1 = gst_opus_enc_create_id_buffer (nchannels, sample_rate);
buf2 = gst_opus_enc_create_metadata_buffer (tags);
/* mark and put on caps */
*caps = gst_caps_from_string ("audio/x-opus");
*caps = _gst_caps_set_buffer_array (*caps, "streamheader", buf1, buf2, NULL);
*headers = g_slist_prepend (*headers, buf2);
*headers = g_slist_prepend (*headers, buf1);
}
gboolean
gst_opus_header_is_header (GstBuffer * buf, const char *magic, guint magic_size)
{
return (GST_BUFFER_SIZE (buf) >= magic_size
&& !memcmp (magic, GST_BUFFER_DATA (buf), magic_size));
}

View file

@ -1,11 +1,6 @@
/* -*- c-basic-offset: 2 -*-
*
* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2006 Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>
*
* gstfilter.h: element for filter plug-ins
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) <2008> Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -23,11 +18,17 @@
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_FILTER_H__
#define __GST_FILTER_H__
#ifndef __GST_OPUS_HEADER_H__
#define __GST_OPUS_HEADER_H__
#include <gst/gst.h>
GType gst_iir_get_type (void);
#endif /* __GST_FILTER_H__ */
G_BEGIN_DECLS
extern void gst_opus_header_create_caps (GstCaps **caps, GSList **headers, gint nchannels, gint sample_rate, const GstTagList *tags);
extern gboolean gst_opus_header_is_header (GstBuffer * buf, const char *magic, guint magic_size);
G_END_DECLS
#endif /* __GST_OPUS_HEADER_H__ */

View file

@ -38,6 +38,7 @@
#endif
#include <opus/opus.h>
#include "gstopusheader.h"
#include "gstopusparse.h"
GST_DEBUG_CATEGORY_STATIC (opusparse_debug);
@ -62,8 +63,11 @@ GST_STATIC_PAD_TEMPLATE ("sink",
G_DEFINE_TYPE (GstOpusParse, gst_opus_parse, GST_TYPE_BASE_PARSE);
static gboolean gst_opus_parse_start (GstBaseParse * parse);
static gboolean gst_opus_parse_stop (GstBaseParse * parse);
static gboolean gst_opus_parse_check_valid_frame (GstBaseParse * base,
GstBaseParseFrame * frame, guint * frame_size, gint * skip);
static GstFlowReturn gst_opus_parse_parse_frame (GstBaseParse * base,
GstBaseParseFrame * frame);
static void
gst_opus_parse_class_init (GstOpusParseClass * klass)
@ -75,8 +79,10 @@ gst_opus_parse_class_init (GstOpusParseClass * klass)
element_class = (GstElementClass *) klass;
bpclass->start = GST_DEBUG_FUNCPTR (gst_opus_parse_start);
bpclass->stop = GST_DEBUG_FUNCPTR (gst_opus_parse_stop);
bpclass->check_valid_frame =
GST_DEBUG_FUNCPTR (gst_opus_parse_check_valid_frame);
bpclass->parse_frame = GST_DEBUG_FUNCPTR (gst_opus_parse_parse_frame);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&opus_parse_src_factory));
@ -94,18 +100,34 @@ gst_opus_parse_class_init (GstOpusParseClass * klass)
static void
gst_opus_parse_init (GstOpusParse * parse)
{
parse->header_sent = FALSE;
}
static gboolean
gst_opus_parse_start (GstBaseParse * base)
{
GstOpusParse *parse = GST_OPUS_PARSE (base);
GstCaps *caps;
caps = gst_caps_new_empty_simple ("audio/x-opus");
gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (GST_BASE_PARSE (parse)), caps);
gst_caps_unref (caps);
parse->header_sent = FALSE;
parse->next_ts = 0;
return TRUE;
}
static gboolean
gst_opus_parse_stop (GstBaseParse * base)
{
GstOpusParse *parse = GST_OPUS_PARSE (base);
g_slist_foreach (parse->headers, (GFunc) gst_buffer_unref, NULL);
parse->headers = NULL;
parse->header_sent = FALSE;
return TRUE;
}
@ -118,41 +140,184 @@ gst_opus_parse_check_valid_frame (GstBaseParse * base,
gsize size;
guint32 packet_size;
int ret = FALSE;
int channels, bandwidth;
int channels;
const unsigned char *frames[48];
unsigned char toc;
short frame_sizes[48];
int payload_offset;
int nframes;
int packet_offset = 0;
gboolean is_header, is_idheader, is_commentheader;
parse = GST_OPUS_PARSE (base);
data = gst_buffer_map (frame->buffer, &size, NULL, GST_MAP_READ);
GST_DEBUG_OBJECT (parse, "Checking for frame, %u bytes in buffer", size);
if (size < 4) {
GST_DEBUG_OBJECT (parse, "Too small");
goto beach;
}
packet_size = GST_READ_UINT32_BE (data);
GST_DEBUG_OBJECT (parse, "Packet size: %u bytes", packet_size);
if (packet_size > MAX_PAYLOAD_BYTES) {
GST_DEBUG_OBJECT (parse, "Too large");
goto beach;
}
if (packet_size > size - 4) {
GST_DEBUG_OBJECT (parse, "Truncated");
goto beach;
/* check for headers */
is_idheader = gst_opus_header_is_header (frame->buffer, "OpusHead", 8);
is_commentheader = gst_opus_header_is_header (frame->buffer, "OpusTags", 8);
is_header = is_idheader || is_commentheader;
if (!is_header) {
/* Next, check if there's an Opus packet there */
nframes =
opus_packet_parse (data, size, &toc, frames, frame_sizes,
&payload_offset);
}
channels = opus_packet_get_nb_channels (data + 8);
bandwidth = opus_packet_get_bandwidth (data + 8);
if (channels < 0 || bandwidth < 0) {
GST_DEBUG_OBJECT (parse, "It looked like a packet, but it is not");
goto beach;
if (!is_header && nframes < 0) {
/* Then, check for the test vector framing */
GST_DEBUG_OBJECT (parse,
"No Opus packet found, trying test vector framing");
if (size < 4) {
GST_DEBUG_OBJECT (parse, "Too small");
goto beach;
}
packet_size = GST_READ_UINT32_BE (data);
GST_DEBUG_OBJECT (parse, "Packet size: %u bytes", packet_size);
if (packet_size > MAX_PAYLOAD_BYTES) {
GST_DEBUG_OBJECT (parse, "Too large");
goto beach;
}
if (packet_size > size - 4) {
GST_DEBUG_OBJECT (parse, "Truncated");
goto beach;
}
nframes =
opus_packet_parse (data + 8, packet_size, &toc, frames, frame_sizes,
&payload_offset);
if (nframes < 0) {
GST_DEBUG_OBJECT (parse, "No test vector framing either");
goto beach;
}
packet_offset = 8;
data += packet_offset;
}
GST_DEBUG_OBJECT (parse, "Got Opus packet, %d bytes");
if (!parse->header_sent) {
GstCaps *caps;
*skip = 8;
*frame_size = packet_size;
/* Opus streams can decode to 1 or 2 channels, so use the header
value if we have one, or 2 otherwise */
if (is_idheader) {
channels = data[9];
} else {
channels = 2;
}
g_slist_foreach (parse->headers, (GFunc) gst_buffer_unref, NULL);
parse->headers = NULL;
gst_opus_header_create_caps (&caps, &parse->headers, channels, 0, NULL);
gst_pad_set_caps (GST_BASE_PARSE_SRC_PAD (parse), caps);
parse->header_sent = TRUE;
}
if (is_header) {
*skip = 0;
*frame_size = size;
} else {
*skip = packet_offset;
*frame_size = payload_offset;
}
GST_DEBUG_OBJECT (parse, "Got Opus packet at offset %d, %d bytes", *skip,
*frame_size);
ret = TRUE;
beach:
gst_buffer_unmap (frame->buffer, data, size);
return ret;
}
/* Adapted copy of the one in gstoggstream.c... */
static guint64
packet_duration_opus (const guint8 * data, size_t len)
{
static const guint64 durations[32] = {
10000, 20000, 40000, 60000, /* Silk NB */
10000, 20000, 40000, 60000, /* Silk MB */
10000, 20000, 40000, 60000, /* Silk WB */
10000, 20000, /* Hybrid SWB */
10000, 20000, /* Hybrid FB */
2500, 5000, 10000, 20000, /* CELT NB */
2500, 5000, 10000, 20000, /* CELT NB */
2500, 5000, 10000, 20000, /* CELT NB */
2500, 5000, 10000, 20000, /* CELT NB */
};
gint64 duration;
gint64 frame_duration;
gint nframes;
guint8 toc;
if (len < 1)
return 0;
toc = data[0];
frame_duration = durations[toc >> 3] * 1000;
switch (toc & 3) {
case 0:
nframes = 1;
break;
case 1:
nframes = 2;
break;
case 2:
nframes = 2;
break;
case 3:
if (len < 2) {
GST_WARNING ("Code 3 Opus packet has less than 2 bytes");
return 0;
}
nframes = data[1] & 63;
break;
}
duration = nframes * frame_duration;
if (duration > 120 * GST_MSECOND) {
GST_WARNING ("Opus packet duration > 120 ms, invalid");
return 0;
}
GST_LOG ("Opus packet: frame size %.1f ms, %d frames, duration %.1f ms",
frame_duration / 1000000.f, nframes, duration / 1000000.f);
return duration;
}
static GstFlowReturn
gst_opus_parse_parse_frame (GstBaseParse * base, GstBaseParseFrame * frame)
{
guint64 duration;
GstOpusParse *parse;
parse = GST_OPUS_PARSE (base);
if (gst_opus_header_is_header (frame->buffer, "OpusHead", 8)
|| gst_opus_header_is_header (frame->buffer, "OpusTags", 8)) {
GST_BUFFER_TIMESTAMP (frame->buffer) = 0;
GST_BUFFER_DURATION (frame->buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET_END (frame->buffer) = GST_CLOCK_TIME_NONE;
GST_BUFFER_OFFSET (frame->buffer) = GST_CLOCK_TIME_NONE;
return GST_FLOW_OK;
}
GST_BUFFER_TIMESTAMP (frame->buffer) = parse->next_ts;
duration =
packet_duration_opus (GST_BUFFER_DATA (frame->buffer),
GST_BUFFER_SIZE (frame->buffer));
parse->next_ts += duration;
GST_BUFFER_DURATION (frame->buffer) = duration;
GST_BUFFER_OFFSET_END (frame->buffer) =
gst_util_uint64_scale (parse->next_ts, 48000, GST_SECOND);
GST_BUFFER_OFFSET (frame->buffer) = parse->next_ts;
return GST_FLOW_OK;
}

View file

@ -42,6 +42,10 @@ typedef struct _GstOpusParseClass GstOpusParseClass;
struct _GstOpusParse {
GstBaseParse element;
gboolean header_sent;
GSList *headers;
GstClockTime next_ts;
};
struct _GstOpusParseClass {

View file

@ -4,7 +4,7 @@ libgstvoaacenc_la_SOURCES = \
gstvoaac.c \
gstvoaacenc.c
libgstvoaacenc_la_CFLAGS = \
libgstvoaacenc_la_CFLAGS = -DGST_USE_UNSTABLE_API \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
$(GST_CFLAGS) \

View file

@ -91,18 +91,128 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_DEBUG_CATEGORY_STATIC (gst_voaacenc_debug);
#define GST_CAT_DEFAULT gst_voaacenc_debug
static void gst_voaacenc_finalize (GObject * object);
static GstFlowReturn gst_voaacenc_chain (GstPad * pad, GstBuffer * buffer);
static gboolean gst_voaacenc_setcaps (GstPad * pad, GstCaps * caps);
static GstStateChangeReturn gst_voaacenc_state_change (GstElement * element,
GstStateChange transition);
static gboolean voaacenc_core_init (GstVoAacEnc * voaacenc);
static gboolean voaacenc_core_set_parameter (GstVoAacEnc * voaacenc);
static void voaacenc_core_uninit (GstVoAacEnc * voaacenc);
static GstCaps *gst_voaacenc_getcaps (GstPad * pad);
static GstCaps *gst_voaacenc_create_source_pad_caps (GstVoAacEnc * voaacenc);
static gint voaacenc_get_rate_index (gint rate);
static gboolean gst_voaacenc_start (GstAudioEncoder * enc);
static gboolean gst_voaacenc_stop (GstAudioEncoder * enc);
static gboolean gst_voaacenc_set_format (GstAudioEncoder * enc,
GstAudioInfo * info);
static GstFlowReturn gst_voaacenc_handle_frame (GstAudioEncoder * enc,
GstBuffer * in_buf);
static GstCaps *gst_voaacenc_getcaps (GstAudioEncoder * enc);
GST_BOILERPLATE (GstVoAacEnc, gst_voaacenc, GstAudioEncoder,
GST_TYPE_AUDIO_ENCODER);
static void
gst_voaacenc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstVoAacEnc *self = GST_VOAACENC (object);
switch (prop_id) {
case PROP_BITRATE:
self->bitrate = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
return;
}
static void
gst_voaacenc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstVoAacEnc *self = GST_VOAACENC (object);
switch (prop_id) {
case PROP_BITRATE:
g_value_set_int (value, self->bitrate);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
return;
}
static void
gst_voaacenc_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_template));
gst_element_class_set_details_simple (element_class, "AAC audio encoder",
"Codec/Encoder/Audio", "AAC audio encoder", "Kan Hu <kan.hu@linaro.org>");
}
static void
gst_voaacenc_class_init (GstVoAacEncClass * klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GstAudioEncoderClass *base_class = GST_AUDIO_ENCODER_CLASS (klass);
object_class->set_property = GST_DEBUG_FUNCPTR (gst_voaacenc_set_property);
object_class->get_property = GST_DEBUG_FUNCPTR (gst_voaacenc_get_property);
base_class->start = GST_DEBUG_FUNCPTR (gst_voaacenc_start);
base_class->stop = GST_DEBUG_FUNCPTR (gst_voaacenc_stop);
base_class->set_format = GST_DEBUG_FUNCPTR (gst_voaacenc_set_format);
base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_voaacenc_handle_frame);
base_class->getcaps = GST_DEBUG_FUNCPTR (gst_voaacenc_getcaps);
g_object_class_install_property (object_class, PROP_BITRATE,
g_param_spec_int ("bitrate",
"Bitrate",
"Target Audio Bitrate",
0, G_MAXINT, VOAAC_ENC_DEFAULT_BITRATE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
gst_voaacenc_init (GstVoAacEnc * voaacenc, GstVoAacEncClass * klass)
{
voaacenc->bitrate = VOAAC_ENC_DEFAULT_BITRATE;
voaacenc->output_format = VOAAC_ENC_DEFAULT_OUTPUTFORMAT;
/* init rest */
voaacenc->handle = NULL;
}
static gboolean
gst_voaacenc_start (GstAudioEncoder * enc)
{
GstVoAacEnc *voaacenc = GST_VOAACENC (enc);
GST_DEBUG_OBJECT (enc, "start");
if (voaacenc_core_init (voaacenc) == FALSE)
return FALSE;
voaacenc->rate = 0;
voaacenc->channels = 0;
return TRUE;
}
static gboolean
gst_voaacenc_stop (GstAudioEncoder * enc)
{
GstVoAacEnc *voaacenc = GST_VOAACENC (enc);
GST_DEBUG_OBJECT (enc, "stop");
voaacenc_core_uninit (voaacenc);
return TRUE;
}
static gpointer
gst_voaacenc_generate_sink_caps (gpointer data)
@ -200,134 +310,13 @@ gst_voaacenc_get_sink_caps (void)
g_once (&g_once, gst_voaacenc_generate_sink_caps, NULL);
caps = g_once.retval;
return gst_caps_ref (caps);
return caps;
}
static void
_do_init (GType object_type)
static GstCaps *
gst_voaacenc_getcaps (GstAudioEncoder * benc)
{
const GInterfaceInfo preset_interface_info = {
NULL, /* interface init */
NULL, /* interface finalize */
NULL /* interface_data */
};
g_type_add_interface_static (object_type, GST_TYPE_PRESET,
&preset_interface_info);
GST_DEBUG_CATEGORY_INIT (gst_voaacenc_debug, "voaacenc", 0,
"AAC audio encoder");
}
GST_BOILERPLATE_FULL (GstVoAacEnc, gst_voaacenc, GstElement, GST_TYPE_ELEMENT,
_do_init);
static void
gst_voaacenc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstVoAacEnc *self = GST_VOAACENC (object);
switch (prop_id) {
case PROP_BITRATE:
self->bitrate = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
return;
}
static void
gst_voaacenc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstVoAacEnc *self = GST_VOAACENC (object);
switch (prop_id) {
case PROP_BITRATE:
g_value_set_int (value, self->bitrate);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
return;
}
static void
gst_voaacenc_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_template));
gst_element_class_set_details_simple (element_class, "AAC audio encoder",
"Codec/Encoder/Audio", "AAC audio encoder", "Kan Hu <kan.hu@linaro.org>");
}
static void
gst_voaacenc_class_init (GstVoAacEncClass * klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
object_class->set_property = GST_DEBUG_FUNCPTR (gst_voaacenc_set_property);
object_class->get_property = GST_DEBUG_FUNCPTR (gst_voaacenc_get_property);
object_class->finalize = GST_DEBUG_FUNCPTR (gst_voaacenc_finalize);
g_object_class_install_property (object_class, PROP_BITRATE,
g_param_spec_int ("bitrate",
"Bitrate",
"Target Audio Bitrate",
0, G_MAXINT, VOAAC_ENC_DEFAULT_BITRATE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
element_class->change_state = GST_DEBUG_FUNCPTR (gst_voaacenc_state_change);
}
static void
gst_voaacenc_init (GstVoAacEnc * voaacenc, GstVoAacEncClass * klass)
{
/* create the sink pad */
voaacenc->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
gst_pad_set_setcaps_function (voaacenc->sinkpad,
GST_DEBUG_FUNCPTR (gst_voaacenc_setcaps));
gst_pad_set_getcaps_function (voaacenc->sinkpad,
GST_DEBUG_FUNCPTR (gst_voaacenc_getcaps));
gst_pad_set_chain_function (voaacenc->sinkpad,
GST_DEBUG_FUNCPTR (gst_voaacenc_chain));
gst_element_add_pad (GST_ELEMENT (voaacenc), voaacenc->sinkpad);
/* create the src pad */
voaacenc->srcpad = gst_pad_new_from_static_template (&src_template, "src");
gst_pad_use_fixed_caps (voaacenc->srcpad);
gst_element_add_pad (GST_ELEMENT (voaacenc), voaacenc->srcpad);
voaacenc->adapter = gst_adapter_new ();
voaacenc->bitrate = VOAAC_ENC_DEFAULT_BITRATE;
voaacenc->output_format = VOAAC_ENC_DEFAULT_OUTPUTFORMAT;
/* init rest */
voaacenc->handle = NULL;
}
static void
gst_voaacenc_finalize (GObject * object)
{
GstVoAacEnc *voaacenc;
voaacenc = GST_VOAACENC (object);
g_object_unref (G_OBJECT (voaacenc->adapter));
voaacenc->adapter = NULL;
G_OBJECT_CLASS (parent_class)->finalize (object);
return gst_audio_encoder_proxy_getcaps (benc, gst_voaacenc_get_sink_caps ());
}
/* check downstream caps to configure format */
@ -336,7 +325,7 @@ gst_voaacenc_negotiate (GstVoAacEnc * voaacenc)
{
GstCaps *caps;
caps = gst_pad_get_allowed_caps (voaacenc->srcpad);
caps = gst_pad_get_allowed_caps (GST_AUDIO_ENCODER_SRC_PAD (voaacenc));
GST_DEBUG_OBJECT (voaacenc, "allowed caps: %" GST_PTR_FORMAT, caps);
@ -362,184 +351,20 @@ gst_voaacenc_negotiate (GstVoAacEnc * voaacenc)
gst_caps_unref (caps);
}
static GstCaps *
gst_voaacenc_getcaps (GstPad * pad)
static gint
gst_voaacenc_get_rate_index (gint rate)
{
return gst_voaacenc_get_sink_caps ();
}
static gboolean
gst_voaacenc_setcaps (GstPad * pad, GstCaps * caps)
{
gboolean ret = FALSE;
GstStructure *structure;
GstVoAacEnc *voaacenc;
GstCaps *src_caps;
voaacenc = GST_VOAACENC (GST_PAD_PARENT (pad));
structure = gst_caps_get_structure (caps, 0);
/* get channel count */
gst_structure_get_int (structure, "channels", &voaacenc->channels);
gst_structure_get_int (structure, "rate", &voaacenc->rate);
/* precalc duration as it's constant now */
voaacenc->duration =
gst_util_uint64_scale_int (1024, GST_SECOND, voaacenc->rate);
voaacenc->inbuf_size = voaacenc->channels * 2 * 1024;
gst_voaacenc_negotiate (voaacenc);
/* create reverse caps */
src_caps = gst_voaacenc_create_source_pad_caps (voaacenc);
if (src_caps) {
gst_pad_set_caps (voaacenc->srcpad, src_caps);
gst_caps_unref (src_caps);
ret = voaacenc_core_set_parameter (voaacenc);
}
return ret;
}
static GstFlowReturn
gst_voaacenc_chain (GstPad * pad, GstBuffer * buffer)
{
GstVoAacEnc *voaacenc;
GstFlowReturn ret;
guint64 timestamp, distance = 0;
voaacenc = GST_VOAACENC (GST_PAD_PARENT (pad));
g_return_val_if_fail (voaacenc->handle, GST_FLOW_WRONG_STATE);
if (voaacenc->rate == 0 || voaacenc->channels == 0)
goto not_negotiated;
/* discontinuity clears adapter, FIXME, maybe we can set some
* encoder flag to mask the discont. */
if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
gst_adapter_clear (voaacenc->adapter);
voaacenc->discont = TRUE;
}
ret = GST_FLOW_OK;
gst_adapter_push (voaacenc->adapter, buffer);
/* Collect samples until we have enough for an output frame */
while (gst_adapter_available (voaacenc->adapter) >= voaacenc->inbuf_size) {
GstBuffer *out;
guint8 *data;
VO_CODECBUFFER input = { 0 }
, output = {
0};
VO_AUDIO_OUTPUTINFO output_info = { {0}
};
/* max size */
if ((ret =
gst_pad_alloc_buffer_and_set_caps (voaacenc->srcpad, 0,
voaacenc->inbuf_size, GST_PAD_CAPS (voaacenc->srcpad),
&out)) != GST_FLOW_OK) {
return ret;
static const gint rate_table[] = {
96000, 88200, 64000, 48000, 44100, 32000,
24000, 22050, 16000, 12000, 11025, 8000
};
gint i;
for (i = 0; i < G_N_ELEMENTS (rate_table); ++i) {
if (rate == rate_table[i]) {
return i;
}
output.Buffer = GST_BUFFER_DATA (out);
output.Length = voaacenc->inbuf_size;
if (voaacenc->discont) {
GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DISCONT);
voaacenc->discont = FALSE;
}
data =
(guint8 *) gst_adapter_peek (voaacenc->adapter, voaacenc->inbuf_size);
input.Buffer = data;
input.Length = voaacenc->inbuf_size;
voaacenc->codec_api.SetInputData (voaacenc->handle, &input);
/* encode */
if (voaacenc->codec_api.GetOutputData (voaacenc->handle, &output,
&output_info) != VO_ERR_NONE) {
gst_buffer_unref (out);
return GST_FLOW_ERROR;
}
/* get timestamp from adapter */
timestamp = gst_adapter_prev_timestamp (voaacenc->adapter, &distance);
if (G_LIKELY (GST_CLOCK_TIME_IS_VALID (timestamp))) {
GST_BUFFER_TIMESTAMP (out) =
timestamp +
GST_FRAMES_TO_CLOCK_TIME (distance / voaacenc->channels /
VOAAC_ENC_BITS_PER_SAMPLE, voaacenc->rate);
}
GST_BUFFER_DURATION (out) =
GST_FRAMES_TO_CLOCK_TIME (voaacenc->inbuf_size / voaacenc->channels /
VOAAC_ENC_BITS_PER_SAMPLE, voaacenc->rate);
GST_LOG_OBJECT (voaacenc, "Pushing out buffer time: %" GST_TIME_FORMAT
" duration: %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)),
GST_TIME_ARGS (GST_BUFFER_DURATION (out)));
GST_BUFFER_SIZE (out) = output.Length;
/* flush the among of data we have peek */
gst_adapter_flush (voaacenc->adapter, voaacenc->inbuf_size);
/* play */
if ((ret = gst_pad_push (voaacenc->srcpad, out)) != GST_FLOW_OK)
break;
}
return ret;
/* ERRORS */
not_negotiated:
{
GST_ELEMENT_ERROR (voaacenc, STREAM, TYPE_NOT_FOUND,
(NULL), ("unknown type"));
return GST_FLOW_NOT_NEGOTIATED;
}
}
static GstStateChangeReturn
gst_voaacenc_state_change (GstElement * element, GstStateChange transition)
{
GstVoAacEnc *voaacenc;
GstStateChangeReturn ret;
voaacenc = GST_VOAACENC (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (voaacenc_core_init (voaacenc) == FALSE)
return GST_STATE_CHANGE_FAILURE;
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
voaacenc->rate = 0;
voaacenc->channels = 0;
voaacenc->discont = FALSE;
gst_adapter_clear (voaacenc->adapter);
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_NULL:
voaacenc_core_uninit (voaacenc);
gst_adapter_clear (voaacenc->adapter);
break;
default:
break;
}
return ret;
return -1;
}
static GstCaps *
@ -550,7 +375,7 @@ gst_voaacenc_create_source_pad_caps (GstVoAacEnc * voaacenc)
gint index;
guint8 data[VOAAC_ENC_CODECDATA_LEN];
if ((index = voaacenc_get_rate_index (voaacenc->rate)) >= 0) {
if ((index = gst_voaacenc_get_rate_index (voaacenc->rate)) >= 0) {
/* LC profile only */
data[0] = ((0x02 << 3) | (index >> 1));
data[1] = ((index & 0x01) << 7) | (voaacenc->channels << 3);
@ -580,6 +405,124 @@ gst_voaacenc_create_source_pad_caps (GstVoAacEnc * voaacenc)
return caps;
}
static gboolean
gst_voaacenc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
{
gboolean ret = FALSE;
GstVoAacEnc *voaacenc;
GstCaps *src_caps;
voaacenc = GST_VOAACENC (benc);
/* get channel count */
voaacenc->channels = GST_AUDIO_INFO_CHANNELS (info);
voaacenc->rate = GST_AUDIO_INFO_RATE (info);
/* precalc buffer size as it's constant now */
voaacenc->inbuf_size = voaacenc->channels * 2 * 1024;
gst_voaacenc_negotiate (voaacenc);
/* create reverse caps */
src_caps = gst_voaacenc_create_source_pad_caps (voaacenc);
if (src_caps) {
gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (voaacenc), src_caps);
gst_caps_unref (src_caps);
ret = voaacenc_core_set_parameter (voaacenc);
}
/* report needs to base class */
gst_audio_encoder_set_frame_samples_min (benc, 1024);
gst_audio_encoder_set_frame_samples_max (benc, 1024);
gst_audio_encoder_set_frame_max (benc, 1);
return ret;
}
static GstFlowReturn
gst_voaacenc_handle_frame (GstAudioEncoder * benc, GstBuffer * buf)
{
GstVoAacEnc *voaacenc;
GstFlowReturn ret = GST_FLOW_OK;
GstBuffer *out;
VO_AUDIO_OUTPUTINFO output_info = { {0} };
VO_CODECBUFFER input = { 0 };
VO_CODECBUFFER output = { 0 };
voaacenc = GST_VOAACENC (benc);
g_return_val_if_fail (voaacenc->handle, GST_FLOW_NOT_NEGOTIATED);
if (voaacenc->rate == 0 || voaacenc->channels == 0)
goto not_negotiated;
/* we don't deal with squeezing remnants, so simply discard those */
if (G_UNLIKELY (buf == NULL)) {
GST_DEBUG_OBJECT (benc, "no data");
goto exit;
}
if (G_UNLIKELY (GST_BUFFER_SIZE (buf) < voaacenc->inbuf_size)) {
GST_DEBUG_OBJECT (voaacenc, "discarding trailing data %d",
buf ? GST_BUFFER_SIZE (buf) : 0);
ret = gst_audio_encoder_finish_frame (benc, NULL, -1);
goto exit;
}
/* max size */
if ((ret =
gst_pad_alloc_buffer_and_set_caps (GST_AUDIO_ENCODER_SRC_PAD
(voaacenc), 0, voaacenc->inbuf_size,
GST_PAD_CAPS (GST_AUDIO_ENCODER_SRC_PAD (voaacenc)),
&out)) != GST_FLOW_OK) {
goto exit;
}
output.Buffer = GST_BUFFER_DATA (out);
output.Length = voaacenc->inbuf_size;
g_assert (GST_BUFFER_SIZE (buf) == voaacenc->inbuf_size);
input.Buffer = GST_BUFFER_DATA (buf);
input.Length = voaacenc->inbuf_size;
voaacenc->codec_api.SetInputData (voaacenc->handle, &input);
/* encode */
if (voaacenc->codec_api.GetOutputData (voaacenc->handle, &output,
&output_info) != VO_ERR_NONE) {
gst_buffer_unref (out);
goto encode_failed;
}
GST_LOG_OBJECT (voaacenc, "encoded to %d bytes", output.Length);
GST_BUFFER_SIZE (out) = output.Length;
GST_LOG_OBJECT (voaacenc, "Pushing out buffer time: %" GST_TIME_FORMAT
" duration: %" GST_TIME_FORMAT,
GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (out)),
GST_TIME_ARGS (GST_BUFFER_DURATION (out)));
ret = gst_audio_encoder_finish_frame (benc, out, 1024);
exit:
return ret;
/* ERRORS */
not_negotiated:
{
GST_ELEMENT_ERROR (voaacenc, STREAM, TYPE_NOT_FOUND,
(NULL), ("unknown type"));
ret = GST_FLOW_NOT_NEGOTIATED;
goto exit;
}
encode_failed:
{
GST_ELEMENT_ERROR (voaacenc, STREAM, ENCODE, (NULL), ("encode failed"));
ret = GST_FLOW_ERROR;
goto exit;
}
}
static VO_U32
voaacenc_core_mem_alloc (VO_S32 uID, VO_MEM_INFO * pMemInfo)
{
@ -672,19 +615,3 @@ voaacenc_core_uninit (GstVoAacEnc * voaacenc)
voaacenc->handle = NULL;
}
}
static gint
voaacenc_get_rate_index (gint rate)
{
static const gint rate_table[] = {
96000, 88200, 64000, 48000, 44100, 32000,
24000, 22050, 16000, 12000, 11025, 8000
};
gint i;
for (i = 0; i < G_N_ELEMENTS (rate_table); ++i) {
if (rate == rate_table[i]) {
return i;
}
}
return -1;
}

View file

@ -21,11 +21,11 @@
#define __GST_VOAACENC_H__
#include <gst/gst.h>
#include <gst/audio/gstaudioencoder.h>
#include <vo-aacenc/voAAC.h>
#include <vo-aacenc/cmnMemory.h>
#include <gst/base/gstadapter.h>
G_BEGIN_DECLS
#define GST_TYPE_VOAACENC \
@ -43,14 +43,10 @@ typedef struct _GstVoAacEnc GstVoAacEnc;
typedef struct _GstVoAacEncClass GstVoAacEncClass;
struct _GstVoAacEnc {
GstElement element;
GstAudioEncoder element;
/* pads */
GstPad *sinkpad, *srcpad;
gboolean discont;
GstAdapter *adapter;
/* desired bitrate */
gint bitrate;
@ -58,7 +54,6 @@ struct _GstVoAacEnc {
gint channels;
gint rate;
gint output_format;
gint duration;
gint inbuf_size;
@ -70,7 +65,7 @@ struct _GstVoAacEnc {
};
struct _GstVoAacEncClass {
GstElementClass parent_class;
GstAudioEncoderClass parent_class;
};
GType gst_voaacenc_get_type (void);

View file

@ -4,8 +4,10 @@ libgstvoamrwbenc_la_SOURCES = \
gstvoamrwb.c \
gstvoamrwbenc.c
libgstvoamrwbenc_la_CFLAGS = $(GST_CFLAGS) $(VOAMRWBENC_CFLAGS)
libgstvoamrwbenc_la_LIBADD = $(GST_BASE_LIBS) $(VOAMRWBENC_LIBS)
libgstvoamrwbenc_la_CFLAGS = -DGST_USE_UNSTABLE_API \
$(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(VOAMRWBENC_CFLAGS)
libgstvoamrwbenc_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
-lgstaudio-$(GST_MAJORMINOR) $(GST_BASE_LIBS) $(VOAMRWBENC_LIBS)
libgstvoamrwbenc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstvoamrwbenc_la_LIBTOOLFLAGS = --tag=disable-static

View file

@ -109,31 +109,15 @@ static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_DEBUG_CATEGORY_STATIC (gst_voamrwbenc_debug);
#define GST_CAT_DEFAULT gst_voamrwbenc_debug
static void gst_voamrwbenc_finalize (GObject * object);
static gboolean gst_voamrwbenc_start (GstAudioEncoder * enc);
static gboolean gst_voamrwbenc_stop (GstAudioEncoder * enc);
static gboolean gst_voamrwbenc_set_format (GstAudioEncoder * enc,
GstAudioInfo * info);
static GstFlowReturn gst_voamrwbenc_handle_frame (GstAudioEncoder * enc,
GstBuffer * in_buf);
static GstFlowReturn gst_voamrwbenc_chain (GstPad * pad, GstBuffer * buffer);
static gboolean gst_voamrwbenc_setcaps (GstPad * pad, GstCaps * caps);
static GstStateChangeReturn gst_voamrwbenc_state_change (GstElement * element,
GstStateChange transition);
static void
_do_init (GType object_type)
{
const GInterfaceInfo preset_interface_info = {
NULL, /* interface init */
NULL, /* interface finalize */
NULL /* interface_data */
};
g_type_add_interface_static (object_type, GST_TYPE_PRESET,
&preset_interface_info);
GST_DEBUG_CATEGORY_INIT (gst_voamrwbenc_debug, "amrwbenc", 0,
"AMR-WB audio encoder");
}
GST_BOILERPLATE_FULL (GstVoAmrWbEnc, gst_voamrwbenc, GstElement,
GST_TYPE_ELEMENT, _do_init);
GST_BOILERPLATE (GstVoAmrWbEnc, gst_voamrwbenc, GstAudioEncoder,
GST_TYPE_AUDIO_ENCODER);
static void
gst_voamrwbenc_set_property (GObject * object, guint prop_id,
@ -191,71 +175,74 @@ static void
gst_voamrwbenc_class_init (GstVoAmrWbEncClass * klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstAudioEncoderClass *base_class = GST_AUDIO_ENCODER_CLASS (klass);
object_class->finalize = gst_voamrwbenc_finalize;
object_class->set_property = gst_voamrwbenc_set_property;
object_class->get_property = gst_voamrwbenc_get_property;
base_class->start = GST_DEBUG_FUNCPTR (gst_voamrwbenc_start);
base_class->stop = GST_DEBUG_FUNCPTR (gst_voamrwbenc_stop);
base_class->set_format = GST_DEBUG_FUNCPTR (gst_voamrwbenc_set_format);
base_class->handle_frame = GST_DEBUG_FUNCPTR (gst_voamrwbenc_handle_frame);
g_object_class_install_property (object_class, PROP_BANDMODE,
g_param_spec_enum ("band-mode", "Band Mode",
"Encoding Band Mode (Kbps)", GST_VOAMRWBENC_BANDMODE_TYPE,
BANDMODE_DEFAULT,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
element_class->change_state = GST_DEBUG_FUNCPTR (gst_voamrwbenc_state_change);
}
static void
gst_voamrwbenc_init (GstVoAmrWbEnc * amrwbenc, GstVoAmrWbEncClass * klass)
{
/* create the sink pad */
amrwbenc->sinkpad = gst_pad_new_from_static_template (&sink_template, "sink");
gst_pad_set_setcaps_function (amrwbenc->sinkpad, gst_voamrwbenc_setcaps);
gst_pad_set_chain_function (amrwbenc->sinkpad, gst_voamrwbenc_chain);
gst_element_add_pad (GST_ELEMENT (amrwbenc), amrwbenc->sinkpad);
/* create the src pad */
amrwbenc->srcpad = gst_pad_new_from_static_template (&src_template, "src");
gst_pad_use_fixed_caps (amrwbenc->srcpad);
gst_element_add_pad (GST_ELEMENT (amrwbenc), amrwbenc->srcpad);
amrwbenc->adapter = gst_adapter_new ();
/* init rest */
amrwbenc->handle = NULL;
amrwbenc->channels = 0;
amrwbenc->rate = 0;
amrwbenc->ts = 0;
}
static void
gst_voamrwbenc_finalize (GObject * object)
{
GstVoAmrWbEnc *amrwbenc;
amrwbenc = GST_VOAMRWBENC (object);
g_object_unref (G_OBJECT (amrwbenc->adapter));
amrwbenc->adapter = NULL;
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
gst_voamrwbenc_setcaps (GstPad * pad, GstCaps * caps)
gst_voamrwbenc_start (GstAudioEncoder * enc)
{
GstVoAmrWbEnc *voamrwbenc = GST_VOAMRWBENC (enc);
GST_DEBUG_OBJECT (enc, "start");
if (!(voamrwbenc->handle = E_IF_init ()))
return FALSE;
voamrwbenc->rate = 0;
voamrwbenc->channels = 0;
return TRUE;
}
static gboolean
gst_voamrwbenc_stop (GstAudioEncoder * enc)
{
GstVoAmrWbEnc *voamrwbenc = GST_VOAMRWBENC (enc);
GST_DEBUG_OBJECT (enc, "stop");
if (voamrwbenc->handle) {
E_IF_exit (voamrwbenc->handle);
voamrwbenc->handle = NULL;
}
return TRUE;
}
static gboolean
gst_voamrwbenc_set_format (GstAudioEncoder * benc, GstAudioInfo * info)
{
GstStructure *structure;
GstVoAmrWbEnc *amrwbenc;
GstCaps *copy;
amrwbenc = GST_VOAMRWBENC (GST_PAD_PARENT (pad));
structure = gst_caps_get_structure (caps, 0);
amrwbenc = GST_VOAMRWBENC (benc);
/* get channel count */
gst_structure_get_int (structure, "channels", &amrwbenc->channels);
gst_structure_get_int (structure, "rate", &amrwbenc->rate);
amrwbenc->channels = GST_AUDIO_INFO_CHANNELS (info);
amrwbenc->rate = GST_AUDIO_INFO_RATE (info);
/* this is not wrong but will sound bad */
if (amrwbenc->channels != 1) {
@ -270,116 +257,59 @@ gst_voamrwbenc_setcaps (GstPad * pad, GstCaps * caps)
"channels", G_TYPE_INT, amrwbenc->channels,
"rate", G_TYPE_INT, amrwbenc->rate, NULL);
gst_pad_set_caps (amrwbenc->srcpad, copy);
gst_pad_set_caps (GST_AUDIO_ENCODER_SRC_PAD (amrwbenc), copy);
gst_caps_unref (copy);
/* report needs to base class: one frame at a time */
gst_audio_encoder_set_frame_samples_min (benc, L_FRAME16k);
gst_audio_encoder_set_frame_samples_max (benc, L_FRAME16k);
gst_audio_encoder_set_frame_max (benc, 1);
return TRUE;
}
static GstFlowReturn
gst_voamrwbenc_chain (GstPad * pad, GstBuffer * buffer)
gst_voamrwbenc_handle_frame (GstAudioEncoder * benc, GstBuffer * buffer)
{
GstVoAmrWbEnc *amrwbenc;
GstFlowReturn ret = GST_FLOW_OK;
const int buffer_size = sizeof (short) * L_FRAME16k;
GstBuffer *out;
gint outsize;
amrwbenc = GST_VOAMRWBENC (gst_pad_get_parent (pad));
amrwbenc = GST_VOAMRWBENC (benc);
g_return_val_if_fail (amrwbenc->handle, GST_FLOW_WRONG_STATE);
g_return_val_if_fail (amrwbenc->handle, GST_FLOW_NOT_NEGOTIATED);
if (amrwbenc->rate == 0 || amrwbenc->channels == 0) {
ret = GST_FLOW_NOT_NEGOTIATED;
goto done;
}
/* discontinuity clears adapter, FIXME, maybe we can set some
* encoder flag to mask the discont. */
if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DISCONT)) {
gst_adapter_clear (amrwbenc->adapter);
amrwbenc->ts = 0;
amrwbenc->discont = TRUE;
/* we don't deal with squeezing remnants, so simply discard those */
if (G_UNLIKELY (buffer == NULL)) {
GST_DEBUG_OBJECT (amrwbenc, "no data");
goto done;
}
if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
amrwbenc->ts = GST_BUFFER_TIMESTAMP (buffer);
ret = GST_FLOW_OK;
gst_adapter_push (amrwbenc->adapter, buffer);
/* Collect samples until we have enough for an output frame */
while (gst_adapter_available (amrwbenc->adapter) >= buffer_size) {
GstBuffer *out;
guint8 *data;
gint outsize;
out = gst_buffer_new_and_alloc (buffer_size);
GST_BUFFER_DURATION (out) = GST_SECOND * L_FRAME16k /
(amrwbenc->rate * amrwbenc->channels);
GST_BUFFER_TIMESTAMP (out) = amrwbenc->ts;
if (amrwbenc->ts != -1) {
amrwbenc->ts += GST_BUFFER_DURATION (out);
}
if (amrwbenc->discont) {
GST_BUFFER_FLAG_SET (out, GST_BUFFER_FLAG_DISCONT);
amrwbenc->discont = FALSE;
}
gst_buffer_set_caps (out, gst_pad_get_caps (amrwbenc->srcpad));
data = (guint8 *) gst_adapter_peek (amrwbenc->adapter, buffer_size);
/* encode */
outsize =
E_IF_encode (amrwbenc->handle, amrwbenc->bandmode, (const short *) data,
(unsigned char *) GST_BUFFER_DATA (out), 0);
gst_adapter_flush (amrwbenc->adapter, buffer_size);
GST_BUFFER_SIZE (out) = outsize;
/* play */
if ((ret = gst_pad_push (amrwbenc->srcpad, out)) != GST_FLOW_OK)
break;
if (G_UNLIKELY (GST_BUFFER_SIZE (buffer) < buffer_size)) {
GST_DEBUG_OBJECT (amrwbenc, "discarding trailing data %d",
buffer ? GST_BUFFER_SIZE (buffer) : 0);
ret = gst_audio_encoder_finish_frame (benc, NULL, -1);
goto done;
}
out = gst_buffer_new_and_alloc (buffer_size);
/* encode */
outsize = E_IF_encode (amrwbenc->handle, amrwbenc->bandmode,
(const short *) GST_BUFFER_DATA (buffer),
(unsigned char *) GST_BUFFER_DATA (out), 0);
GST_LOG_OBJECT (amrwbenc, "encoded to %d bytes", outsize);
GST_BUFFER_SIZE (out) = outsize;
ret = gst_audio_encoder_finish_frame (benc, out, L_FRAME16k);
done:
gst_object_unref (amrwbenc);
return ret;
}
static GstStateChangeReturn
gst_voamrwbenc_state_change (GstElement * element, GstStateChange transition)
{
GstVoAmrWbEnc *amrwbenc;
GstStateChangeReturn ret;
amrwbenc = GST_VOAMRWBENC (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
if (!(amrwbenc->handle = E_IF_init ()))
return GST_STATE_CHANGE_FAILURE;
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
amrwbenc->rate = 0;
amrwbenc->channels = 0;
amrwbenc->ts = 0;
amrwbenc->discont = FALSE;
gst_adapter_clear (amrwbenc->adapter);
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
switch (transition) {
case GST_STATE_CHANGE_READY_TO_NULL:
E_IF_exit (amrwbenc->handle);
break;
default:
break;
}
return ret;
}

View file

@ -21,7 +21,8 @@
#define __GST_VOAMRWBENC_H__
#include <gst/gst.h>
#include <gst/base/gstadapter.h>
#include <gst/audio/gstaudioencoder.h>
#include <vo-amrwbenc/enc_if.h>
G_BEGIN_DECLS
@ -41,14 +42,7 @@ typedef struct _GstVoAmrWbEnc GstVoAmrWbEnc;
typedef struct _GstVoAmrWbEncClass GstVoAmrWbEncClass;
struct _GstVoAmrWbEnc {
GstElement element;
/* pads */
GstPad *sinkpad, *srcpad;
guint64 ts;
gboolean discont;
GstAdapter *adapter;
GstAudioEncoder element;
/* library handle */
void *handle;
@ -59,7 +53,7 @@ struct _GstVoAmrWbEnc {
};
struct _GstVoAmrWbEncClass {
GstElementClass parent_class;
GstAudioEncoderClass parent_class;
};
GType gst_voamrwbenc_get_type (void);

View file

@ -1365,6 +1365,7 @@ gst_h264_parse_sps (GstH264NalUnit * nalu, GstH264SPS * sps,
sps->frame_crop_right_offset = 0;
sps->frame_crop_top_offset = 0;
sps->frame_crop_bottom_offset = 0;
sps->delta_pic_order_always_zero_flag = 0;
READ_UINT8 (&nr, sps->profile_idc, 8);
READ_UINT8 (&nr, sps->constraint_set0_flag, 1);

View file

@ -1389,11 +1389,7 @@ gst_base_video_decoder_finish_frame (GstBaseVideoDecoder * base_video_decoder,
GstVideoFrameState *tmp = l->data;
if (tmp->events) {
GList *k;
for (k = g_list_last (tmp->events); k; k = k->prev)
events = g_list_prepend (events, k->data);
g_list_free (tmp->events);
events = tmp->events;
tmp->events = NULL;
}
@ -1401,7 +1397,7 @@ gst_base_video_decoder_finish_frame (GstBaseVideoDecoder * base_video_decoder,
break;
}
for (l = g_list_last (events); l; l = l->next)
for (l = g_list_last (events); l; l = l->prev)
gst_pad_push_event (GST_BASE_VIDEO_CODEC_SRC_PAD (base_video_decoder),
l->data);
g_list_free (events);
@ -2055,7 +2051,7 @@ gst_base_video_decoder_alloc_src_frame (GstBaseVideoDecoder *
* @frame: a #GstVideoFrameState
*
* Determines maximum possible decoding time for @frame that will
* allow it to decode and arrive in time (as determined by QoS messages).
* allow it to decode and arrive in time (as determined by QoS events).
* In particular, a negative result means decoding in time is no longer possible
* and should therefore occur as soon/skippy as possible.
*

View file

@ -788,7 +788,6 @@ gst_base_video_encoder_change_state (GstElement * element,
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
gst_base_video_encoder_reset (base_video_encoder);
gst_base_video_encoder_reset (base_video_encoder);
if (base_video_encoder_class->start) {
if (!base_video_encoder_class->start (base_video_encoder))

View file

@ -17,7 +17,7 @@ libgstaudiovisualizers_la_LIBADD = \
libgstaudiovisualizers_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstaudiovisualizers_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstbaseaudiovisualizer.h \
noinst_HEADERS = gstbaseaudiovisualizer.h gstdrawhelpers.h \
gstspacescope.h gstspectrascope.h gstsynaescope.h gstwavescope.h
Android.mk: Makefile.am $(BUILT_SOURCES)

View file

@ -0,0 +1,37 @@
/* GStreamer
* Copyright (C) <2011> Stefan Sauer <ensonic@users.sf.net>
*
* gstdrawhelpers.h: simple drawing helpers
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#define draw_dot(_vd, _x, _y, _st, _c) G_STMT_START { \
_vd[(_y * _st) + _x] = _c; \
} G_STMT_END
#define draw_line(_vd, _x1, _x2, _y1, _y2, _st, _c) G_STMT_START { \
guint _i, _j, _x, _y; \
gint _dx = _x2 - _x1, _dy = _y2 - _y1; \
gfloat _f; \
\
_j = abs (_dx) > abs (_dy) ? abs (_dx) : abs (_dy); \
for (_i = 0; _i < _j; _i++) { \
_f = (gfloat) _i / (gfloat) _j; \
_x = _x1 + _dx * _f; \
_y = _y1 + _dy * _f; \
draw_dot (_vd, _x, _y, _st, _c); \
} \
} G_STMT_END

View file

@ -35,6 +35,7 @@
#include "config.h"
#endif
#include <stdlib.h>
#include "gstwavescope.h"
static GstStaticPadTemplate gst_wave_scope_src_template =
@ -61,26 +62,76 @@ GST_STATIC_PAD_TEMPLATE ("sink",
GST_DEBUG_CATEGORY_STATIC (wave_scope_debug);
#define GST_CAT_DEFAULT wave_scope_debug
static gboolean gst_wave_scope_render (GstBaseAudioVisualizer * scope,
GstBuffer * audio, GstBuffer * video);
enum
{
PROP_0,
PROP_STYLE
};
enum
{
STYLE_DOTS = 0,
STYLE_LINES,
NUM_STYLES
};
#define GST_TYPE_WAVE_SCOPE_STYLE (gst_wave_scope_style_get_type ())
static GType
gst_wave_scope_style_get_type (void)
{
static GType gtype = 0;
if (gtype == 0) {
static const GEnumValue values[] = {
{STYLE_DOTS, "draw dots (default)", "dots"},
{STYLE_LINES, "draw lines", "lines"},
{0, NULL, NULL}
};
gtype = g_enum_register_static ("GstWaveScopeStyle", values);
}
return gtype;
}
static void gst_wave_scope_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_wave_scope_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void render_dots (GstBaseAudioVisualizer * scope, guint32 * vdata,
gint16 * adata, guint num_samples);
static void render_lines (GstBaseAudioVisualizer * scope, guint32 * vdata,
gint16 * adata, guint num_samples);
static gboolean gst_wave_scope_render (GstBaseAudioVisualizer * base,
GstBuffer * audio, GstBuffer * video);
G_DEFINE_TYPE (GstWaveScope, gst_wave_scope, GST_TYPE_BASE_AUDIO_VISUALIZER);
static void
gst_wave_scope_class_init (GstWaveScopeClass * g_class)
{
GstElementClass *element_class = (GstElementClass *) g_class;
GObjectClass *gobject_class = (GObjectClass *) g_class;
GstElementClass *gstelement_class = (GstElementClass *) g_class;
GstBaseAudioVisualizerClass *scope_class =
(GstBaseAudioVisualizerClass *) g_class;
gst_element_class_set_details_simple (element_class, "Waveform oscilloscope",
"Visualization",
"Simple waveform oscilloscope", "Stefan Kost <ensonic@users.sf.net>");
gobject_class->set_property = gst_wave_scope_set_property;
gobject_class->get_property = gst_wave_scope_get_property;
gst_element_class_add_pad_template (element_class,
g_object_class_install_property (gobject_class, PROP_STYLE,
g_param_spec_enum ("style", "drawing style",
"Drawing styles for the wave form display.",
GST_TYPE_WAVE_SCOPE_STYLE, STYLE_DOTS,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_details_simple (gstelement_class,
"Waveform oscilloscope", "Visualization", "Simple waveform oscilloscope",
"Stefan Kost <ensonic@users.sf.net>");
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_wave_scope_src_template));
gst_element_class_add_pad_template (element_class,
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_wave_scope_sink_template));
scope_class->render = GST_DEBUG_FUNCPTR (gst_wave_scope_render);
@ -92,35 +143,120 @@ gst_wave_scope_init (GstWaveScope * scope)
/* do nothing */
}
static gboolean
gst_wave_scope_render (GstBaseAudioVisualizer * scope, GstBuffer * audio,
GstBuffer * video)
static void
gst_wave_scope_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
gsize asize;
guint32 *vdata =
(guint32 *) gst_buffer_map (video, NULL, NULL, GST_MAP_WRITE);
gint16 *adata = (gint16 *) gst_buffer_map (audio, &asize, NULL, GST_MAP_READ);
guint i, c, s, x, y, off, oy;
guint num_samples;
GstWaveScope *scope = GST_WAVE_SCOPE (object);
switch (prop_id) {
case PROP_STYLE:
scope->style = g_value_get_enum (value);
switch (scope->style) {
case STYLE_DOTS:
scope->process = render_dots;
break;
case STYLE_LINES:
scope->process = render_lines;
break;
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_wave_scope_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstWaveScope *scope = GST_WAVE_SCOPE (object);
switch (prop_id) {
case PROP_STYLE:
g_value_set_enum (value, scope->style);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
#include "gstdrawhelpers.h"
static void
render_dots (GstBaseAudioVisualizer * scope, guint32 * vdata, gint16 * adata,
guint num_samples)
{
gint channels = scope->channels;
guint i, c, s, x, y, oy;
gfloat dx, dy;
guint w = scope->width;
/* draw dots */
num_samples = asize / (scope->channels * sizeof (gint16));
dx = (gfloat) scope->width / (gfloat) num_samples;
dx = (gfloat) w / (gfloat) num_samples;
dy = scope->height / 65536.0;
oy = scope->height / 2;
s = 0;
for (i = 0; i < num_samples; i++) {
x = (guint) ((gfloat) i * dx);
for (c = 0; c < scope->channels; c++) {
y = (guint) (oy + (gfloat) adata[s++] * dy);
off = (y * w) + x;
vdata[off] = 0x00FFFFFF;
for (c = 0; c < channels; c++) {
s = c;
for (i = 0; i < num_samples; i++) {
x = (guint) ((gfloat) i * dx);
y = (guint) (oy + (gfloat) adata[s] * dy);
s += channels;
draw_dot (vdata, x, y, w, 0x00FFFFFF);
}
}
}
static void
render_lines (GstBaseAudioVisualizer * scope, guint32 * vdata, gint16 * adata,
guint num_samples)
{
gint channels = scope->channels;
guint i, c, s, x, y, oy;
gfloat dx, dy;
guint w = scope->width;
gint x2, y2;
/* draw lines */
dx = (gfloat) w / (gfloat) num_samples;
dy = scope->height / 65536.0;
oy = scope->height / 2;
for (c = 0; c < channels; c++) {
s = c;
x2 = 0;
y2 = (guint) (oy + (gfloat) adata[s] * dy);
for (i = 1; i < num_samples; i++) {
x = (guint) ((gfloat) i * dx);
y = (guint) (oy + (gfloat) adata[s] * dy);
s += channels;
draw_line (vdata, x2, x, y2, y, w, 0x00FFFFFF);
x2 = x;
y2 = y;
}
}
}
static gboolean
gst_wave_scope_render (GstBaseAudioVisualizer * base, GstBuffer * audio,
GstBuffer * video)
{
GstWaveScope *scope = GST_WAVE_SCOPE (base);
guint32 *vdata;
gsize asize;
gint16 *adata;
guint num_samples;
adata = gst_buffer_map (audio, &asize, NULL, GST_MAP_READ);
vdata = gst_buffer_map (video, NULL, NULL, GST_MAP_WRITE);
num_samples = asize / (base->channels * sizeof (gint16));
scope->process (base, vdata, adata, num_samples);
gst_buffer_unmap (video, vdata, -1);
gst_buffer_unmap (audio, adata, -1);
return TRUE;
}

View file

@ -33,9 +33,15 @@ G_BEGIN_DECLS
typedef struct _GstWaveScope GstWaveScope;
typedef struct _GstWaveScopeClass GstWaveScopeClass;
typedef void (*GstWaveScopeProcessFunc) (GstBaseAudioVisualizer *, guint32 *, gint16 *, guint);
struct _GstWaveScope
{
GstBaseAudioVisualizer parent;
/* < private > */
GstWaveScopeProcessFunc process;
gint style;
};
struct _GstWaveScopeClass

View file

@ -984,6 +984,10 @@ gst_camera_bin_video_reset_elements (gpointer u_data)
/* reset element states to clear eos/flushing pads */
gst_element_set_state (camerabin->video_encodebin, GST_STATE_READY);
gst_element_set_state (camerabin->videobin_capsfilter, GST_STATE_READY);
if (camerabin->video_filter) {
gst_element_set_state (camerabin->video_filter, GST_STATE_READY);
gst_element_sync_state_with_parent (camerabin->video_filter);
}
gst_element_sync_state_with_parent (camerabin->videobin_capsfilter);
gst_element_sync_state_with_parent (camerabin->video_encodebin);
@ -999,6 +1003,11 @@ gst_camera_bin_video_reset_elements (gpointer u_data)
* and running until we really need them */
gst_element_set_state (camerabin->audio_src, GST_STATE_NULL);
if (camerabin->audio_filter) {
gst_element_set_state (camerabin->audio_filter, GST_STATE_READY);
gst_element_sync_state_with_parent (camerabin->audio_filter);
}
gst_element_sync_state_with_parent (camerabin->audio_capsfilter);
gst_element_sync_state_with_parent (camerabin->audio_volume);

View file

@ -1,16 +0,0 @@
plugin_LTLIBRARIES = libgstfilter.la
libgstfilter_la_SOURCES = gstfilter.c gstiir.c iir.c
libgstfilter_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
libgstfilter_la_LIBADD = \
$(GST_BASE_LIBS) \
$(GST_LIBS) \
$(GST_PLUGINS_BASE_LIBS) \
-lgstaudio-$(GST_MAJORMINOR) \
$(LIBM)
libgstfilter_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstfilter_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstfilter.h gstiir.h iir.h

View file

@ -1,157 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="filter"
ProjectGUID="{979C216F-0ACF-4956-AE00-055A42D678B2}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="../../win32/Debug"
IntermediateDirectory="../../win32/Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;&quot;../../gst-libs&quot;;../../../popt/include;../../../libxml2/include/libxml2"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;filter_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
OutputFile="$(OutDir)/gstfilter.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="../../../gstreamer/win32/Debug;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib"
ModuleDefinitionFile=""
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/filter.pdb"
SubSystem="2"
OptimizeReferences="2"
ImportLibrary="$(OutDir)/gstfilter.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="../../win32/Release"
IntermediateDirectory="../../win32/Release"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;&quot;../../gst-libs&quot;;../../../popt/include;../../../libxml2/include/libxml2"
PreprocessorDefinitions="WIN32;NDEBUG;GST_DISABLE_GST_DEBUG;_WINDOWS;_USRDLL;filter_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
OutputFile="$(OutDir)/gstfilter.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../gstreamer/win32/Release;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib"
ModuleDefinitionFile=""
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/gstfilter.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\gstfilter.c">
</File>
<File
RelativePath=".\gstiir.c">
</File>
<File
RelativePath=".\iir.c">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\iir.h">
</File>
<File
RelativePath=".\gstfilter.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -1,63 +0,0 @@
/* -*- c-basic-offset: 2 -*-
*
* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2000 Wim Taymans <wtay@chello.be>
* 2006 Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>
*
* gstfilter.c: element for filter plug-ins
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "gstfilter.h"
#include <gst/audio/audio.h>
struct _elements_entry
{
gchar *name;
GType (*type) (void);
};
static struct _elements_entry _elements[] = {
{"iir", gst_iir_get_type},
{NULL, 0},
};
static gboolean
plugin_init (GstPlugin * plugin)
{
gint i = 0;
while (_elements[i].name) {
if (!gst_element_register (plugin, _elements[i].name, GST_RANK_NONE,
_elements[i].type ()))
return FALSE;
i++;
}
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"filter",
"IIR audio filter element",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);

View file

@ -1,253 +0,0 @@
/* -*- c-basic-offset: 2 -*-
*
* GStreamer
* Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
* 2006 Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>
*
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <math.h>
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <gst/controller/gstcontroller.h>
#include "gstiir.h"
#define GST_CAT_DEFAULT gst_iir_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
/* Filter signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_A,
PROP_B,
PROP_GAIN,
PROP_STAGES
};
static GstStaticPadTemplate iir_sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-float, "
"rate = (int) [ 1, MAX ], "
"channels = (int) [ 1, MAX ], "
"endianness = (int) BYTE_ORDER, " "width = (int) 32")
);
static GstStaticPadTemplate iir_src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-float, "
"rate = (int) [ 1, MAX ], "
"channels = (int) [ 1, MAX ], "
"endianness = (int) BYTE_ORDER, " "width = (int) 32")
);
#define DEBUG_INIT(bla) \
GST_DEBUG_CATEGORY_INIT (gst_iir_debug, "iir", 0, "Infinite Impulse Response (IIR) filter plugin");
GST_BOILERPLATE_FULL (GstIIR, gst_iir, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
static void iir_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void iir_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstFlowReturn iir_transform_ip (GstBaseTransform * base,
GstBuffer * outbuf);
static gboolean iir_set_caps (GstBaseTransform * base, GstCaps * incaps,
GstCaps * outcaps);
/* Element class */
static void
gst_iir_dispose (GObject * object)
{
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_iir_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&iir_src_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&iir_sink_template));
gst_element_class_set_details_simple (element_class,
"Infinite Impulse Response (IIR) filter", "Filter/Effect/Audio",
"IIR filter based on vorbis code",
"Monty <monty@xiph.org>, "
"Thomas Vander Stichele <thomas at apestaart dot org>, "
"Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>");
}
static void
gst_iir_class_init (GstIIRClass * klass)
{
GObjectClass *gobject_class;
GstBaseTransformClass *trans_class;
gobject_class = (GObjectClass *) klass;
trans_class = (GstBaseTransformClass *) klass;
gobject_class->set_property = iir_set_property;
gobject_class->get_property = iir_get_property;
gobject_class->dispose = gst_iir_dispose;
g_object_class_install_property (gobject_class, PROP_A,
g_param_spec_double ("A", "A", "A filter coefficient",
-G_MAXDOUBLE, G_MAXDOUBLE, 0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_B,
g_param_spec_double ("B", "B", "B filter coefficient",
-G_MAXDOUBLE, G_MAXDOUBLE, 0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_GAIN,
g_param_spec_double ("gain", "Gain", "Filter gain",
-G_MAXDOUBLE, G_MAXDOUBLE, 0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_STAGES,
g_param_spec_int ("stages", "Stages", "Number of filter stages",
1, G_MAXINT, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
trans_class->transform_ip = GST_DEBUG_FUNCPTR (iir_transform_ip);
trans_class->set_caps = GST_DEBUG_FUNCPTR (iir_set_caps);
}
static void
gst_iir_init (GstIIR * this, GstIIRClass * g_class)
{
this->A = 0.0;
this->B = 0.0;
this->gain = 1.0; /* unity gain as default */
this->stages = 1;
this->state = NULL;
}
/* GstBaseTransform vmethod implementations */
/* get notified of caps and plug in the correct process function */
static gboolean
iir_set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps)
{
GstIIR *this = GST_IIR (base);
GST_DEBUG_OBJECT (this,
"set_caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps);
/* FIXME: remember to free it */
this->state = (IIR_state *) g_malloc (sizeof (IIR_state));
IIR_init (this->state, this->stages, this->gain, &(this->A), &(this->B));
return TRUE;
}
static GstFlowReturn
iir_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
{
GstIIR *this = GST_IIR (base);
GstClockTime timestamp;
gfloat *src;
int i;
/* don't process data in passthrough-mode */
if (gst_base_transform_is_passthrough (base))
return GST_FLOW_OK;
/* FIXME: subdivide GST_BUFFER_SIZE into small chunks for smooth fades */
timestamp = GST_BUFFER_TIMESTAMP (outbuf);
if (GST_CLOCK_TIME_IS_VALID (timestamp))
gst_object_sync_values (GST_OBJECT (this), timestamp);
src = (gfloat *) GST_BUFFER_DATA (outbuf);
/* do an in-place edit */
for (i = 0; i < GST_BUFFER_SIZE (outbuf) / sizeof (gfloat); ++i)
*(src + i) = (gfloat) IIR_filter (this->state, (double) *(src + i));
return GST_FLOW_OK;
}
static void
iir_set_property (GObject * object, guint prop_id, const GValue * value,
GParamSpec * pspec)
{
GstIIR *this = GST_IIR (object);
g_return_if_fail (GST_IS_IIR (this));
switch (prop_id) {
case PROP_A:
this->A = g_value_get_double (value);
break;
case PROP_B:
this->B = g_value_get_double (value);
break;
case PROP_GAIN:
this->gain = g_value_get_double (value);
break;
case PROP_STAGES:
this->stages = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
iir_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstIIR *this = GST_IIR (object);
switch (prop_id) {
case PROP_A:
g_value_set_double (value, this->A);
break;
case PROP_B:
g_value_set_double (value, this->B);
break;
case PROP_GAIN:
g_value_set_double (value, this->gain);
break;
case PROP_STAGES:
g_value_set_int (value, this->stages);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}

View file

@ -1,67 +0,0 @@
/* -*- c-basic-offset: 2 -*-
*
* GStreamer
* Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
* 2006 Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>
*
* 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_IIR_H__
#define __GST_IIR_H__
#include "gstfilter.h"
#include "iir.h"
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
G_BEGIN_DECLS
#define GST_TYPE_IIR \
(gst_iir_get_type())
#define GST_IIR(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IIR,GstIIR))
#define GST_IIR_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_IIR,GstIIRClass))
#define GST_IS_IIR(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IIR))
#define GST_IS_IIR_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IIR))
typedef struct _GstIIR GstIIR;
typedef struct _GstIIRClass GstIIRClass;
/**
* GstIIR:
*
* Opaque data structure.
*/
struct _GstIIR {
GstBaseTransform element;
double A, B;
double gain;
int stages;
IIR_state *state;
};
struct _GstIIRClass {
GstBaseTransformClass parent_class;
};
G_END_DECLS
#endif /* __GST_IIR_H__ */

View file

@ -1,348 +0,0 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
* THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
* PLEASE READ THESE TERMS DISTRIBUTING. *
* *
* THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
* by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
* http://www.xiph.org/ *
* *
********************************************************************
function: Direct Form I, II IIR filters, plus some specializations
last mod: $Id$
********************************************************************/
/* LPC is actually a degenerate case of form I/II filters, but we need
both */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "iir.h"
void
IIR_init (IIR_state * s, int stages, double gain, double *A, double *B)
{
memset (s, 0, sizeof (IIR_state));
s->stages = stages;
s->gain = gain;
s->coeff_A = malloc (stages * sizeof (double));
s->coeff_B = malloc ((stages + 1) * sizeof (double));
s->z_A = calloc (stages * 2, sizeof (double));
s->z_B = calloc (stages * 2, sizeof (double));
memcpy (s->coeff_A, A, stages * sizeof (double));
memcpy (s->coeff_B, B, (stages + 1) * sizeof (double));
}
void
IIR_clear (IIR_state * s)
{
if (s) {
free (s->coeff_A);
free (s->coeff_B);
free (s->z_A);
free (s->z_B);
memset (s, 0, sizeof (IIR_state));
}
}
double
IIR_filter (IIR_state * s, double in)
{
int stages = s->stages, i;
double newA;
double newB = 0;
double *zA = s->z_A + s->ring;
newA = in /= s->gain;
for (i = 0; i < stages; i++) {
newA += s->coeff_A[i] * zA[i];
newB += s->coeff_B[i] * zA[i];
}
newB += newA * s->coeff_B[stages];
zA[0] = zA[stages] = newA;
if (++s->ring >= stages)
s->ring = 0;
return (newB);
}
/* this assumes the symmetrical structure of the feed-forward stage of
a Chebyshev bandpass to save multiplies */
double
IIR_filter_ChebBand (IIR_state * s, double in)
{
int stages = s->stages, i;
double newA;
double newB = 0;
double *zA = s->z_A + s->ring;
newA = in /= s->gain;
newA += s->coeff_A[0] * zA[0];
for (i = 1; i < (stages >> 1); i++) {
newA += s->coeff_A[i] * zA[i];
newB += s->coeff_B[i] * (zA[i] - zA[stages - i]);
}
newB += s->coeff_B[i] * zA[i];
for (; i < stages; i++)
newA += s->coeff_A[i] * zA[i];
newB += newA - zA[0];
zA[0] = zA[stages] = newA;
if (++s->ring >= stages)
s->ring = 0;
return (newB);
}
#ifdef _V_SELFTEST
/* z^-stage, z^-stage+1... */
static double cheb_bandpass_B[] =
{ -1., 0., 5., 0., -10., 0., 10., 0., -5., 0., 1 };
static double cheb_bandpass_A[] = { -0.6665900311,
1.0070146601,
-3.1262875409,
3.5017171569,
-6.2779211945,
5.2966481740,
-6.7570216587,
4.0760335768,
-3.9134284363,
1.3997338886
};
static double data[128] = {
0.0426331,
0.0384521,
0.0345764,
0.0346069,
0.0314636,
0.0310059,
0.0318604,
0.0336304,
0.036438,
0.0348511,
0.0354919,
0.0343628,
0.0325623,
0.0318909,
0.0263367,
0.0225525,
0.0195618,
0.0160828,
0.0168762,
0.0145569,
0.0126343,
0.0127258,
0.00820923,
0.00787354,
0.00558472,
0.00204468,
3.05176e-05,
-0.00357056,
-0.00570679,
-0.00991821,
-0.0101013,
-0.00881958,
-0.0108948,
-0.0110168,
-0.0119324,
-0.0161438,
-0.0194702,
-0.0229187,
-0.0260315,
-0.0282288,
-0.0306091,
-0.0330505,
-0.0364685,
-0.0385742,
-0.0428772,
-0.043457,
-0.0425415,
-0.0462341,
-0.0467529,
-0.0489807,
-0.0520325,
-0.0558167,
-0.0596924,
-0.0591431,
-0.0612793,
-0.0618591,
-0.0615845,
-0.0634155,
-0.0639648,
-0.0683594,
-0.0718079,
-0.0729675,
-0.0791931,
-0.0860901,
-0.0885315,
-0.088623,
-0.089386,
-0.0899353,
-0.0886841,
-0.0910645,
-0.0948181,
-0.0919495,
-0.0891418,
-0.0916443,
-0.096344,
-0.100464,
-0.105499,
-0.108612,
-0.112213,
-0.117676,
-0.120911,
-0.124329,
-0.122162,
-0.120605,
-0.12326,
-0.12619,
-0.128998,
-0.13205,
-0.134247,
-0.137939,
-0.143555,
-0.14389,
-0.14859,
-0.153717,
-0.159851,
-0.164551,
-0.162811,
-0.164276,
-0.156952,
-0.140564,
-0.123291,
-0.10321,
-0.0827637,
-0.0652466,
-0.053772,
-0.0509949,
-0.0577698,
-0.0818176,
-0.114929,
-0.148895,
-0.181122,
-0.200714,
-0.21048,
-0.203644,
-0.179413,
-0.145325,
-0.104492,
-0.0658264,
-0.0332031,
-0.0106201,
-0.00363159,
-0.00909424,
-0.0244141,
-0.0422058,
-0.0537415,
-0.0610046,
-0.0609741,
-0.0547791
};
/* comparison test code from http://www-users.cs.york.ac.uk/~fisher/mkfilter/
(the above page kicks ass, BTW)*/
#define NZEROS 10
#define NPOLES 10
#define GAIN 4.599477515e+02
static float xv[NZEROS + 1], yv[NPOLES + 1];
static double
filterloop (double next)
{
xv[0] = xv[1];
xv[1] = xv[2];
xv[2] = xv[3];
xv[3] = xv[4];
xv[4] = xv[5];
xv[5] = xv[6];
xv[6] = xv[7];
xv[7] = xv[8];
xv[8] = xv[9];
xv[9] = xv[10];
xv[10] = next / GAIN;
yv[0] = yv[1];
yv[1] = yv[2];
yv[2] = yv[3];
yv[3] = yv[4];
yv[4] = yv[5];
yv[5] = yv[6];
yv[6] = yv[7];
yv[7] = yv[8];
yv[8] = yv[9];
yv[9] = yv[10];
yv[10] = (xv[10] - xv[0]) + 5 * (xv[2] - xv[8]) + 10 * (xv[6] - xv[4])
+ (-0.6665900311 * yv[0]) + (1.0070146601 * yv[1])
+ (-3.1262875409 * yv[2]) + (3.5017171569 * yv[3])
+ (-6.2779211945 * yv[4]) + (5.2966481740 * yv[5])
+ (-6.7570216587 * yv[6]) + (4.0760335768 * yv[7])
+ (-3.9134284363 * yv[8]) + (1.3997338886 * yv[9]);
return (yv[10]);
}
#include <stdio.h>
int
main ()
{
/* run the pregenerated Chebyshev filter, then our own distillation
through the generic and specialized code */
double *work = malloc (128 * sizeof (double));
IIR_state iir;
int i;
for (i = 0; i < 128; i++)
work[i] = filterloop (data[i]);
{
FILE *out = fopen ("IIR_ref.m", "w");
for (i = 0; i < 128; i++)
fprintf (out, "%g\n", work[i]);
fclose (out);
}
IIR_init (&iir, NPOLES, GAIN, cheb_bandpass_A, cheb_bandpass_B);
for (i = 0; i < 128; i++)
work[i] = IIR_filter (&iir, data[i]);
{
FILE *out = fopen ("IIR_gen.m", "w");
for (i = 0; i < 128; i++)
fprintf (out, "%g\n", work[i]);
fclose (out);
}
IIR_clear (&iir);
IIR_init (&iir, NPOLES, GAIN, cheb_bandpass_A, cheb_bandpass_B);
for (i = 0; i < 128; i++)
work[i] = IIR_filter_ChebBand (&iir, data[i]);
{
FILE *out = fopen ("IIR_cheb.m", "w");
for (i = 0; i < 128; i++)
fprintf (out, "%g\n", work[i]);
fclose (out);
}
IIR_clear (&iir);
return (0);
}
#endif

View file

@ -1,37 +0,0 @@
/********************************************************************
* *
* THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
* USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
* THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
* PLEASE READ THESE TERMS DISTRIBUTING. *
* *
* THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
* by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
* http://www.xiph.org/ *
* *
********************************************************************
function: Direct Form I, II IIR filters, plus some specializations
last mod: $Id$
********************************************************************/
#ifndef _V_IIR_H_
#define _V_IIR_H_
typedef struct {
int stages;
double *coeff_A;
double *coeff_B;
double *z_A;
double *z_B;
int ring;
double gain;
} IIR_state;
void IIR_init(IIR_state *s,int stages,double gain, double *A, double *B);
void IIR_clear(IIR_state *s);
double IIR_filter(IIR_state *s,double in);
double IIR_filter_ChebBand(IIR_state *s,double in);
#endif

28
gst/freeverb/Makefile.am Normal file
View file

@ -0,0 +1,28 @@
plugin_LTLIBRARIES = libgstfreeverb.la
# sources used to compile this plug-in
libgstfreeverb_la_SOURCES = gstfreeverb.c
# flags used to compile this plugin
# add other _CFLAGS and _LIBS as needed
libgstfreeverb_la_CFLAGS = $(GST_CFLAGS) $(GST_CONTROLLER_CFLAGS)
libgstfreeverb_la_LIBADD = $(GST_BASE_LIBS) $(GST_CONTROLLER_LIBS) $(GST_LIBS)
libgstfreeverb_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstfreeverb_la_LIBTOOLFLAGS = --tag=disable-static
# headers we need but don't want installed
noinst_HEADERS = gstfreeverb.h
Android.mk: Makefile.am $(BUILT_SOURCES)
androgenizer \
-:PROJECT libgstfreeverb -:SHARED libgstfreeverb \
-:TAGS eng debug \
-:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
-:SOURCES $(libgstfreeverb_la_SOURCES) \
-:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstfreeverb_la_CFLAGS) \
-:LDFLAGS $(libgstfreeverb_la_LDFLAGS) \
$(libgstfreeverb_la_LIBADD) \
-ldl \
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
> $@

972
gst/freeverb/gstfreeverb.c Normal file
View file

@ -0,0 +1,972 @@
/*
* GStreamer
* Copyright (C) 2011 Stefan Sauer <ensonic@users.sf.net>
*
* 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.
*/
/*
* Freeverb
*
* Written by Jezar at Dreampoint, June 2000
* http://www.dreampoint.co.uk
* This code is public domain
*
* Translated to C by Peter Hanappe, Mai 2001
* Transformed into a GStreamer plugin by Stefan Sauer, Nov 2011
*/
/**
* SECTION:element-freeverb
*
* Reverberation/room effect.
*
* <refsect2>
* <title>Example launch line</title>
* |[
* gst-launch audiotestsrc wave=saw ! freeverb ! autoaudiosink
* gst-launch filesrc location="melo1.ogg" ! decodebin ! audioconvert ! freeverb ! autoaudiosink
* ]|
* </refsect2>
*/
/* FIXME:
* - add mono-to-mono, then we might also need stereo-to-mono ?
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <math.h>
#include <stdlib.h>
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <gst/controller/gstcontroller.h>
#include "gstfreeverb.h"
#define GST_CAT_DEFAULT gst_freeverb_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
enum
{
PROP_0,
PROP_ROOM_SIZE,
PROP_DAMPING,
PROP_PAN_WIDTH,
PROP_LEVEL
};
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-float, "
"rate = (int) [ 1, MAX ], "
"channels = (int) [ 1, 2 ], "
"endianness = (int) BYTE_ORDER, " "width = (int) 32; "
"audio/x-raw-int, "
"rate = (int) [ 1, MAX ], "
"channels = (int) [ 1, 2 ], "
"endianness = (int) BYTE_ORDER, "
"width = (int) 16, " "depth = (int) 16, " "signed = (boolean) true")
);
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-float, "
"rate = (int) [ 1, MAX ], "
"channels = (int) 2, "
"endianness = (int) BYTE_ORDER, " "width = (int) 32; "
"audio/x-raw-int, "
"rate = (int) [ 1, MAX ], "
"channels = (int) 2, "
"endianness = (int) BYTE_ORDER, "
"width = (int) 16, " "depth = (int) 16, " "signed = (boolean) true")
);
#define _do_init(type) { \
const GInterfaceInfo preset_interface_info = { NULL, NULL, NULL }; \
g_type_add_interface_static (type, GST_TYPE_PRESET, &preset_interface_info); \
\
GST_DEBUG_CATEGORY_INIT (gst_freeverb_debug, "freeverb", 0, \
"freeverb element"); \
}
GST_BOILERPLATE_FULL (GstFreeverb, gst_freeverb, GstBaseTransform,
GST_TYPE_BASE_TRANSFORM, _do_init);
static void gst_freeverb_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_freeverb_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_freeverb_finalize (GObject * object);
static gboolean gst_freeverb_get_unit_size (GstBaseTransform * base,
GstCaps * caps, guint * size);
static GstCaps *gst_freeverb_transform_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps);
static gboolean gst_freeverb_set_caps (GstBaseTransform * base,
GstCaps * incaps, GstCaps * outcaps);
static GstFlowReturn gst_freeverb_transform (GstBaseTransform * base,
GstBuffer * inbuf, GstBuffer * outbuf);
static gboolean gst_freeverb_transform_m2s_int (GstFreeverb * filter,
gint16 * idata, gint16 * odata, guint num_samples);
static gboolean gst_freeverb_transform_s2s_int (GstFreeverb * filter,
gint16 * idata, gint16 * odata, guint num_samples);
static gboolean gst_freeverb_transform_m2s_float (GstFreeverb * filter,
gfloat * idata, gfloat * odata, guint num_samples);
static gboolean gst_freeverb_transform_s2s_float (GstFreeverb * filter,
gfloat * idata, gfloat * odata, guint num_samples);
/* Table with processing functions: [channels][format] */
static GstFreeverbProcessFunc process_functions[2][2] = {
{
(GstFreeverbProcessFunc) gst_freeverb_transform_m2s_int,
(GstFreeverbProcessFunc) gst_freeverb_transform_m2s_float,
},
{
(GstFreeverbProcessFunc) gst_freeverb_transform_s2s_int,
(GstFreeverbProcessFunc) gst_freeverb_transform_s2s_float,
}
};
/***************************************************************
*
* REVERB
*/
/* Denormalising:
*
* Another method fixes the problem cheaper: Use a small DC-offset in
* the filter calculations. Now the signals converge not against 0,
* but against the offset. The constant offset is invisible from the
* outside world (i.e. it does not appear at the output. There is a
* very small turn-on transient response, which should not cause
* problems.
*/
//#define DC_OFFSET 0
#define DC_OFFSET 1e-8
//#define DC_OFFSET 0.001f
/* all pass filter */
typedef struct _freeverb_allpass
{
gfloat feedback;
gfloat *buffer;
gint bufsize;
gint bufidx;
} freeverb_allpass;
static void
freeverb_allpass_setbuffer (freeverb_allpass * allpass, gint size)
{
allpass->bufidx = 0;
allpass->buffer = g_new (gfloat, size);
allpass->bufsize = size;
}
static void
freeverb_allpass_release (freeverb_allpass * allpass)
{
g_free (allpass->buffer);
}
static void
freeverb_allpass_init (freeverb_allpass * allpass)
{
gint i, len = allpass->bufsize;
gfloat *buf = allpass->buffer;
for (i = 0; i < len; i++) {
buf[i] = DC_OFFSET; /* this is not 100 % correct. */
}
}
static void
freeverb_allpass_setfeedback (freeverb_allpass * allpass, gfloat val)
{
allpass->feedback = val;
}
/*
static gfloat
freeverb_allpass_getfeedback(freeverb_allpass* allpass)
{
return allpass->feedback;
}*/
#define freeverb_allpass_process(_allpass, _input_1) \
{ \
gfloat output; \
gfloat bufout; \
bufout = _allpass.buffer[_allpass.bufidx]; \
output = bufout-_input_1; \
_allpass.buffer[_allpass.bufidx] = _input_1 + (bufout * _allpass.feedback); \
if (++_allpass.bufidx >= _allpass.bufsize) { \
_allpass.bufidx = 0; \
} \
_input_1 = output; \
}
/* comb filter */
typedef struct _freeverb_comb
{
gfloat feedback;
gfloat filterstore;
gfloat damp1;
gfloat damp2;
gfloat *buffer;
gint bufsize;
gint bufidx;
} freeverb_comb;
static void
freeverb_comb_setbuffer (freeverb_comb * comb, gint size)
{
comb->filterstore = 0;
comb->bufidx = 0;
comb->buffer = g_new (gfloat, size);
comb->bufsize = size;
}
static void
freeverb_comb_release (freeverb_comb * comb)
{
g_free (comb->buffer);
}
static void
freeverb_comb_init (freeverb_comb * comb)
{
gint i, len = comb->bufsize;
gfloat *buf = comb->buffer;
for (i = 0; i < len; i++) {
buf[i] = DC_OFFSET; /* This is not 100 % correct. */
}
}
static void
freeverb_comb_setdamp (freeverb_comb * comb, gfloat val)
{
comb->damp1 = val;
comb->damp2 = 1 - val;
}
/*
static gfloat
freeverb_comb_getdamp(freeverb_comb* comb)
{
return comb->damp1;
}*/
static void
freeverb_comb_setfeedback (freeverb_comb * comb, gfloat val)
{
comb->feedback = val;
}
/*
static gfloat
freeverb_comb_getfeedback(freeverb_comb* comb)
{
return comb->feedback;
}*/
#define freeverb_comb_process(_comb, _input_1, _output) \
{ \
gfloat _tmp = _comb.buffer[_comb.bufidx]; \
_comb.filterstore = (_tmp * _comb.damp2) + (_comb.filterstore * _comb.damp1); \
_comb.buffer[_comb.bufidx] = _input_1 + (_comb.filterstore * _comb.feedback); \
if (++_comb.bufidx >= _comb.bufsize) { \
_comb.bufidx = 0; \
} \
_output += _tmp; \
}
#define numcombs 8
#define numallpasses 4
#define fixedgain 0.015f
#define scalewet 1.0f
#define scaledry 1.0f
#define scaledamp 1.0f
#define scaleroom 0.28f
#define offsetroom 0.7f
#define stereospread 23
/* These values assume 44.1KHz sample rate
* they will need scaling for 96KHz (or other) sample rates.
* The values were obtained by listening tests.
*/
#define combtuningL1 1116
#define combtuningR1 (1116 + stereospread)
#define combtuningL2 1188
#define combtuningR2 (1188 + stereospread)
#define combtuningL3 1277
#define combtuningR3 (1277 + stereospread)
#define combtuningL4 1356
#define combtuningR4 (1356 + stereospread)
#define combtuningL5 1422
#define combtuningR5 (1422 + stereospread)
#define combtuningL6 1491
#define combtuningR6 (1491 + stereospread)
#define combtuningL7 1557
#define combtuningR7 (1557 + stereospread)
#define combtuningL8 1617
#define combtuningR8 (1617 + stereospread)
#define allpasstuningL1 556
#define allpasstuningR1 (556 + stereospread)
#define allpasstuningL2 441
#define allpasstuningR2 (441 + stereospread)
#define allpasstuningL3 341
#define allpasstuningR3 (341 + stereospread)
#define allpasstuningL4 225
#define allpasstuningR4 (225 + stereospread)
struct _GstFreeverbPrivate
{
gfloat roomsize;
gfloat damp;
gfloat wet, wet1, wet2, dry;
gfloat width;
gfloat gain;
/*
The following are all declared inline
to remove the need for dynamic allocation
with its subsequent error-checking messiness
*/
/* Comb filters */
freeverb_comb combL[numcombs];
freeverb_comb combR[numcombs];
/* Allpass filters */
freeverb_allpass allpassL[numallpasses];
freeverb_allpass allpassR[numallpasses];
};
static void
freeverb_revmodel_init (GstFreeverb * filter)
{
GstFreeverbPrivate *priv = filter->priv;
gint i;
for (i = 0; i < numcombs; i++) {
freeverb_comb_init (&priv->combL[i]);
freeverb_comb_init (&priv->combR[i]);
}
for (i = 0; i < numallpasses; i++) {
freeverb_allpass_init (&priv->allpassL[i]);
freeverb_allpass_init (&priv->allpassR[i]);
}
}
static void
freeverb_revmodel_free (GstFreeverb * filter)
{
GstFreeverbPrivate *priv = filter->priv;
gint i;
for (i = 0; i < numcombs; i++) {
freeverb_comb_release (&priv->combL[i]);
freeverb_comb_release (&priv->combR[i]);
}
for (i = 0; i < numallpasses; i++) {
freeverb_allpass_release (&priv->allpassL[i]);
freeverb_allpass_release (&priv->allpassR[i]);
}
}
/* GObject vmethod implementations */
static void
gst_freeverb_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_template));
gst_element_class_set_details_simple (element_class, "Stereo positioning",
"Filter/Effect/Audio",
"Reverberation/room effect", "Stefan Sauer <ensonic@users.sf.net>");
}
static void
gst_freeverb_class_init (GstFreeverbClass * klass)
{
GObjectClass *gobject_class;
g_type_class_add_private (klass, sizeof (GstFreeverbPrivate));
gobject_class = (GObjectClass *) klass;
gobject_class->set_property = gst_freeverb_set_property;
gobject_class->get_property = gst_freeverb_get_property;
gobject_class->finalize = gst_freeverb_finalize;
g_object_class_install_property (gobject_class, PROP_ROOM_SIZE,
g_param_spec_float ("room-size", "Room size",
"Size of the simulated room", 0.0, 1.0, 0.5,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_DAMPING,
g_param_spec_float ("damping", "Damping", "Damping of high frequencies",
0.0, 1.0, 0.2,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_PAN_WIDTH,
g_param_spec_float ("width", "Width", "Stereo panorama width", 0.0, 1.0,
1.0,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_LEVEL,
g_param_spec_float ("level", "Level", "dry/wet level", 0.0, 1.0, 0.5,
G_PARAM_CONSTRUCT | G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE |
G_PARAM_STATIC_STRINGS));
GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size =
GST_DEBUG_FUNCPTR (gst_freeverb_get_unit_size);
GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
GST_DEBUG_FUNCPTR (gst_freeverb_transform_caps);
GST_BASE_TRANSFORM_CLASS (klass)->set_caps =
GST_DEBUG_FUNCPTR (gst_freeverb_set_caps);
GST_BASE_TRANSFORM_CLASS (klass)->transform =
GST_DEBUG_FUNCPTR (gst_freeverb_transform);
}
static void
gst_freeverb_init (GstFreeverb * filter, GstFreeverbClass * klass)
{
filter->priv =
G_TYPE_INSTANCE_GET_PRIVATE (filter, GST_TYPE_FREEVERB,
GstFreeverbPrivate);
filter->width = 0;
filter->channels = 0;
filter->format_float = FALSE;
filter->process = NULL;
gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (filter), TRUE);
freeverb_revmodel_init (filter);
}
static void
gst_freeverb_finalize (GObject * object)
{
GstFreeverb *filter = GST_FREEVERB (object);
freeverb_revmodel_free (filter);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static gboolean
gst_freeverb_set_process_function (GstFreeverb * filter)
{
gint channel_index, format_index;
/* set processing function */
channel_index = filter->channels - 1;
if (channel_index > 1 || channel_index < 0) {
filter->process = NULL;
return FALSE;
}
format_index = (filter->format_float) ? 1 : 0;
filter->process = process_functions[channel_index][format_index];
g_assert (filter->process);
return TRUE;
}
static void
gst_freeverb_init_rev_model (GstFreeverb * filter)
{
gfloat srfactor = filter->rate / 44100.0f;
GstFreeverbPrivate *priv = filter->priv;
freeverb_revmodel_free (filter);
priv->gain = fixedgain;
freeverb_comb_setbuffer (&priv->combL[0], combtuningL1 * srfactor);
freeverb_comb_setbuffer (&priv->combR[0], combtuningR1 * srfactor);
freeverb_comb_setbuffer (&priv->combL[1], combtuningL2 * srfactor);
freeverb_comb_setbuffer (&priv->combR[1], combtuningR2 * srfactor);
freeverb_comb_setbuffer (&priv->combL[2], combtuningL3 * srfactor);
freeverb_comb_setbuffer (&priv->combR[2], combtuningR3 * srfactor);
freeverb_comb_setbuffer (&priv->combL[3], combtuningL4 * srfactor);
freeverb_comb_setbuffer (&priv->combR[3], combtuningR4 * srfactor);
freeverb_comb_setbuffer (&priv->combL[4], combtuningL5 * srfactor);
freeverb_comb_setbuffer (&priv->combR[4], combtuningR5 * srfactor);
freeverb_comb_setbuffer (&priv->combL[5], combtuningL6 * srfactor);
freeverb_comb_setbuffer (&priv->combR[5], combtuningR6 * srfactor);
freeverb_comb_setbuffer (&priv->combL[6], combtuningL7 * srfactor);
freeverb_comb_setbuffer (&priv->combR[6], combtuningR7 * srfactor);
freeverb_comb_setbuffer (&priv->combL[7], combtuningL8 * srfactor);
freeverb_comb_setbuffer (&priv->combR[7], combtuningR8 * srfactor);
freeverb_allpass_setbuffer (&priv->allpassL[0], allpasstuningL1 * srfactor);
freeverb_allpass_setbuffer (&priv->allpassR[0], allpasstuningR1 * srfactor);
freeverb_allpass_setbuffer (&priv->allpassL[1], allpasstuningL2 * srfactor);
freeverb_allpass_setbuffer (&priv->allpassR[1], allpasstuningR2 * srfactor);
freeverb_allpass_setbuffer (&priv->allpassL[2], allpasstuningL3 * srfactor);
freeverb_allpass_setbuffer (&priv->allpassR[2], allpasstuningR3 * srfactor);
freeverb_allpass_setbuffer (&priv->allpassL[3], allpasstuningL4 * srfactor);
freeverb_allpass_setbuffer (&priv->allpassR[3], allpasstuningR4 * srfactor);
/* clear buffers */
freeverb_revmodel_init (filter);
/* set default values */
freeverb_allpass_setfeedback (&priv->allpassL[0], 0.5f);
freeverb_allpass_setfeedback (&priv->allpassR[0], 0.5f);
freeverb_allpass_setfeedback (&priv->allpassL[1], 0.5f);
freeverb_allpass_setfeedback (&priv->allpassR[1], 0.5f);
freeverb_allpass_setfeedback (&priv->allpassL[2], 0.5f);
freeverb_allpass_setfeedback (&priv->allpassR[2], 0.5f);
freeverb_allpass_setfeedback (&priv->allpassL[3], 0.5f);
freeverb_allpass_setfeedback (&priv->allpassR[3], 0.5f);
}
static void
gst_freeverb_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstFreeverb *filter = GST_FREEVERB (object);
GstFreeverbPrivate *priv = filter->priv;
gint i;
switch (prop_id) {
case PROP_ROOM_SIZE:
filter->room_size = g_value_get_float (value);
priv->roomsize = (filter->room_size * scaleroom) + offsetroom;
for (i = 0; i < numcombs; i++) {
freeverb_comb_setfeedback (&priv->combL[i], priv->roomsize);
freeverb_comb_setfeedback (&priv->combR[i], priv->roomsize);
}
break;
case PROP_DAMPING:
filter->damping = g_value_get_float (value);
priv->damp = filter->damping * scaledamp;
for (i = 0; i < numcombs; i++) {
freeverb_comb_setdamp (&priv->combL[i], priv->damp);
freeverb_comb_setdamp (&priv->combR[i], priv->damp);
}
break;
case PROP_PAN_WIDTH:
filter->pan_width = g_value_get_float (value);
priv->width = filter->pan_width;
priv->wet1 = priv->wet * (priv->width / 2.0f + 0.5f);
priv->wet2 = priv->wet * ((1.0f - priv->width) / 2.0f);
break;
case PROP_LEVEL:
filter->level = g_value_get_float (value);
priv->wet = filter->level * scalewet;
priv->dry = (1.0 - filter->level) * scaledry;
priv->wet1 = priv->wet * (priv->width / 2.0f + 0.5f);
priv->wet2 = priv->wet * ((1.0f - priv->width) / 2.0f);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_freeverb_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstFreeverb *filter = GST_FREEVERB (object);
switch (prop_id) {
case PROP_ROOM_SIZE:
g_value_set_float (value, filter->room_size);
break;
case PROP_DAMPING:
g_value_set_float (value, filter->damping);
break;
case PROP_PAN_WIDTH:
g_value_set_float (value, filter->pan_width);
break;
case PROP_LEVEL:
g_value_set_float (value, filter->level);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/* GstBaseTransform vmethod implementations */
static gboolean
gst_freeverb_get_unit_size (GstBaseTransform * base, GstCaps * caps,
guint * size)
{
gint width, channels;
GstStructure *structure;
gboolean ret;
g_assert (size);
/* this works for both float and int */
structure = gst_caps_get_structure (caps, 0);
ret = gst_structure_get_int (structure, "width", &width);
ret &= gst_structure_get_int (structure, "channels", &channels);
*size = width * channels / 8;
GST_INFO_OBJECT (base, "unit size: %u", *size);
return ret;
}
static GstCaps *
gst_freeverb_transform_caps (GstBaseTransform * base,
GstPadDirection direction, GstCaps * caps)
{
GstCaps *res;
GstStructure *structure;
/* transform caps gives one single caps so we can just replace
* the channel property with our range. */
res = gst_caps_copy (caps);
structure = gst_caps_get_structure (res, 0);
if (direction == GST_PAD_SRC) {
GST_INFO_OBJECT (base, "allow 1-2 channels");
gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, 2, NULL);
} else {
GST_INFO_OBJECT (base, "allow 2 channels");
gst_structure_set (structure, "channels", G_TYPE_INT, 2, NULL);
}
return res;
}
static gboolean
gst_freeverb_set_caps (GstBaseTransform * base, GstCaps * incaps,
GstCaps * outcaps)
{
GstFreeverb *filter = GST_FREEVERB (base);
const GstStructure *structure;
gboolean ret;
gint width, rate;
const gchar *fmt;
/*GST_INFO ("incaps are %" GST_PTR_FORMAT, incaps); */
structure = gst_caps_get_structure (incaps, 0);
ret = gst_structure_get_int (structure, "channels", &filter->channels);
if (!ret)
goto no_channels;
ret = gst_structure_get_int (structure, "width", &width);
if (!ret)
goto no_width;
filter->width = width / 8;
ret = gst_structure_get_int (structure, "rate", &rate);
if (!ret)
goto no_rate;
filter->rate = rate;
fmt = gst_structure_get_name (structure);
if (!strcmp (fmt, "audio/x-raw-int"))
filter->format_float = FALSE;
else
filter->format_float = TRUE;
GST_DEBUG_OBJECT (filter, "try to process %s input_1 with %d channels", fmt,
filter->channels);
ret = gst_freeverb_set_process_function (filter);
if (!ret)
GST_WARNING_OBJECT (filter, "can't process input_1 with %d channels",
filter->channels);
gst_freeverb_init_rev_model (filter);
filter->drained = FALSE;
GST_INFO_OBJECT (base, "model configured");
return ret;
no_channels:
GST_DEBUG_OBJECT (filter, "no channels in caps");
return ret;
no_width:
GST_DEBUG_OBJECT (filter, "no width in caps");
return ret;
no_rate:
GST_DEBUG_OBJECT (filter, "no rate in caps");
return ret;
}
static gboolean
gst_freeverb_transform_m2s_int (GstFreeverb * filter,
gint16 * idata, gint16 * odata, guint num_samples)
{
GstFreeverbPrivate *priv = filter->priv;
gint i, k;
gfloat out_l1, out_r1, input_1;
gfloat out_l2, out_r2, input_2;
gboolean drained = TRUE;
for (k = 0; k < num_samples; k++) {
out_l1 = out_r1 = 0.0;
/* The original Freeverb code expects a stereo signal and 'input_1'
* is set to the sum of the left and right input_1 sample. Since
* this code works on a mono signal, 'input_1' is set to twice the
* input_1 sample. */
input_2 = (gfloat) * idata++;
input_1 = (2.0f * input_2 + DC_OFFSET) * priv->gain;
/* Accumulate comb filters in parallel */
for (i = 0; i < numcombs; i++) {
freeverb_comb_process (priv->combL[i], input_1, out_l1);
freeverb_comb_process (priv->combR[i], input_1, out_r1);
}
/* Feed through allpasses in series */
for (i = 0; i < numallpasses; i++) {
freeverb_allpass_process (priv->allpassL[i], out_l1);
freeverb_allpass_process (priv->allpassR[i], out_r1);
}
/* Remove the DC offset */
out_l1 -= DC_OFFSET;
out_r1 -= DC_OFFSET;
/* Calculate output */
out_l2 = out_l1 * priv->wet1 + out_r1 * priv->wet2 + input_2 * priv->dry;
out_r2 = out_r1 * priv->wet1 + out_l1 * priv->wet2 + input_2 * priv->dry;
*odata++ = (gint16) CLAMP (out_l2, G_MININT16, G_MAXINT16);
*odata++ = (gint16) CLAMP (out_r2, G_MININT16, G_MAXINT16);
if (abs (out_l2) > 0 || abs (out_r2) > 0)
drained = FALSE;
}
return drained;
}
static gboolean
gst_freeverb_transform_s2s_int (GstFreeverb * filter,
gint16 * idata, gint16 * odata, guint num_samples)
{
GstFreeverbPrivate *priv = filter->priv;
gint i, k;
gfloat out_l1, out_r1, input_1l, input_1r;
gfloat out_l2, out_r2, input_2l, input_2r;
gboolean drained = TRUE;
for (k = 0; k < num_samples; k++) {
out_l1 = out_r1 = 0.0;
input_2l = (gfloat) * idata++;
input_2r = (gfloat) * idata++;
input_1l = (input_2l + DC_OFFSET) * priv->gain;
input_1r = (input_2r + DC_OFFSET) * priv->gain;
/* Accumulate comb filters in parallel */
for (i = 0; i < numcombs; i++) {
freeverb_comb_process (priv->combL[i], input_1l, out_l1);
freeverb_comb_process (priv->combR[i], input_1r, out_r1);
}
/* Feed through allpasses in series */
for (i = 0; i < numallpasses; i++) {
freeverb_allpass_process (priv->allpassL[i], out_l1);
freeverb_allpass_process (priv->allpassR[i], out_r1);
}
/* Remove the DC offset */
out_l1 -= DC_OFFSET;
out_r1 -= DC_OFFSET;
/* Calculate output */
out_l2 = out_l1 * priv->wet1 + out_r1 * priv->wet2 + input_2l * priv->dry;
out_r2 = out_r1 * priv->wet1 + out_l1 * priv->wet2 + input_2r * priv->dry;
*odata++ = (gint16) CLAMP (out_l2, G_MININT16, G_MAXINT16);
*odata++ = (gint16) CLAMP (out_r2, G_MININT16, G_MAXINT16);
if (abs (out_l2) > 0 || abs (out_r2) > 0)
drained = FALSE;
}
return drained;
}
static gboolean
gst_freeverb_transform_m2s_float (GstFreeverb * filter,
gfloat * idata, gfloat * odata, guint num_samples)
{
GstFreeverbPrivate *priv = filter->priv;
gint i, k;
gfloat out_l1, out_r1, input_1;
gfloat out_l2, out_r2, input_2;
gboolean drained = TRUE;
for (k = 0; k < num_samples; k++) {
out_l1 = out_r1 = 0.0;
/* The original Freeverb code expects a stereo signal and 'input_1'
* is set to the sum of the left and right input_1 sample. Since
* this code works on a mono signal, 'input_1' is set to twice the
* input_1 sample. */
input_2 = *idata++;
input_1 = (2.0f * input_2 + DC_OFFSET) * priv->gain;
/* Accumulate comb filters in parallel */
for (i = 0; i < numcombs; i++) {
freeverb_comb_process (priv->combL[i], input_1, out_l1);
freeverb_comb_process (priv->combR[i], input_1, out_r1);
}
/* Feed through allpasses in series */
for (i = 0; i < numallpasses; i++) {
freeverb_allpass_process (priv->allpassL[i], out_l1);
freeverb_allpass_process (priv->allpassR[i], out_r1);
}
/* Remove the DC offset */
out_l1 -= DC_OFFSET;
out_r1 -= DC_OFFSET;
/* Calculate output */
out_l2 = out_l1 * priv->wet1 + out_r1 * priv->wet2 + input_2 * priv->dry;
out_r2 = out_r1 * priv->wet1 + out_l1 * priv->wet2 + input_2 * priv->dry;
*odata++ = out_l2;
*odata++ = out_r2;
if (fabs (out_l2) > 0 || fabs (out_r2) > 0)
drained = FALSE;
}
return drained;
}
static gboolean
gst_freeverb_transform_s2s_float (GstFreeverb * filter,
gfloat * idata, gfloat * odata, guint num_samples)
{
GstFreeverbPrivate *priv = filter->priv;
gint i, k;
gfloat out_l1, out_r1, input_1l, input_1r;
gfloat out_l2, out_r2, input_2l, input_2r;
gboolean drained = TRUE;
for (k = 0; k < num_samples; k++) {
out_l1 = out_r1 = 0.0;
input_2l = *idata++;
input_2r = *idata++;
input_1l = (input_2l + DC_OFFSET) * priv->gain;
input_1r = (input_2r + DC_OFFSET) * priv->gain;
/* Accumulate comb filters in parallel */
for (i = 0; i < numcombs; i++) {
freeverb_comb_process (priv->combL[i], input_1l, out_l1);
freeverb_comb_process (priv->combR[i], input_1r, out_r1);
}
/* Feed through allpasses in series */
for (i = 0; i < numallpasses; i++) {
freeverb_allpass_process (priv->allpassL[i], out_l1);
freeverb_allpass_process (priv->allpassR[i], out_r1);
}
/* Remove the DC offset */
out_l1 -= DC_OFFSET;
out_r1 -= DC_OFFSET;
/* Calculate output */
out_l2 = out_l1 * priv->wet1 + out_r1 * priv->wet2 + input_2l * priv->dry;
out_r2 = out_r1 * priv->wet1 + out_l1 * priv->wet2 + input_2r * priv->dry;
*odata++ = out_l2;
*odata++ = out_r2;
if (fabs (out_l2) > 0 || fabs (out_r2) > 0)
drained = FALSE;
}
return drained;
}
/* this function does the actual processing
*/
static GstFlowReturn
gst_freeverb_transform (GstBaseTransform * base, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstFreeverb *filter = GST_FREEVERB (base);
guint num_samples = GST_BUFFER_SIZE (outbuf) / (2 * filter->width);
GstClockTime timestamp;
timestamp = GST_BUFFER_TIMESTAMP (inbuf);
timestamp =
gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
GST_DEBUG_OBJECT (filter, "processing %u samples at %" GST_TIME_FORMAT,
num_samples, GST_TIME_ARGS (timestamp));
if (GST_CLOCK_TIME_IS_VALID (timestamp))
gst_object_sync_values (G_OBJECT (filter), timestamp);
if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT))) {
filter->drained = FALSE;
}
if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP))) {
if (filter->drained) {
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
memset (GST_BUFFER_DATA (outbuf), 0, GST_BUFFER_SIZE (outbuf));
return GST_FLOW_OK;
}
} else {
filter->drained = FALSE;
}
filter->drained = filter->process (filter, GST_BUFFER_DATA (inbuf),
GST_BUFFER_DATA (outbuf), num_samples);
if (filter->drained) {
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
}
return GST_FLOW_OK;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
gst_controller_init (NULL, NULL);
return gst_element_register (plugin, "freeverb",
GST_RANK_NONE, GST_TYPE_FREEVERB);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"freeverb",
"Reverberation/room effect",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -0,0 +1,71 @@
/*
* GStreamer
* Copyright (C) 2011 Stefan Sauer <ensonic@users.sf.net>
*
* 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_FREEVERB_H__
#define __GST_FREEVERB_H__
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
G_BEGIN_DECLS
#define GST_TYPE_FREEVERB (gst_freeverb_get_type())
#define GST_FREEVERB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_FREEVERB,GstFreeverb))
#define GST_IS_FREEVERB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_FREEVERB))
#define GST_FREEVERB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_FREEVERB,GstFreeverbClass))
#define GST_IS_FREEVERB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_FREEVERB))
#define GST_FREEVERB_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_FREEVERB,GstFreeverbClass))
typedef struct _GstFreeverb GstFreeverb;
typedef struct _GstFreeverbClass GstFreeverbClass;
typedef struct _GstFreeverbPrivate GstFreeverbPrivate;
typedef gboolean (*GstFreeverbProcessFunc)(GstFreeverb*, guint8*, guint8*, guint);
struct _GstFreeverb {
GstBaseTransform element;
/* < private > */
gfloat room_size;
gfloat damping;
gfloat pan_width;
gfloat level;
GstFreeverbProcessFunc process;
gint channels;
gboolean format_float;
gint width;
gint method;
gint rate;
gboolean drained;
GstFreeverbPrivate *priv;
};
struct _GstFreeverbClass {
GstBaseTransformClass parent_class;
};
GType gst_freeverb_get_type (void);
G_END_DECLS
#endif /* __GST_FREEVERB_H__ */

View file

@ -1,5 +1,5 @@
/* GStreamer
* Copyright (C) 2011 FIXME <fixme@example.com>
* Copyright (C) 2011 David A. Schleef <ds@schleef.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public

View file

@ -1,5 +1,5 @@
/* GStreamer
* Copyright (C) 2011 FIXME <fixme@example.com>
* Copyright (C) 2011 David A. Schleef <ds@schleef.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public

View file

@ -2390,13 +2390,22 @@ get_encoding (const gchar * text, guint * start_text, gboolean * is_multibyte)
*start_text = 1;
*is_multibyte = TRUE;
} else if (firstbyte == 0x12) {
/* That's korean encoding.
* The spec says it's encoded in KSC 5601, but iconv only knows KSC 5636.
* Couldn't find any information about either of them.
*/
encoding = NULL;
/* EUC-KR implements KSX1001 */
encoding = g_strdup ("EUC-KR");
*start_text = 1;
*is_multibyte = TRUE;
} else if (firstbyte == 0x13) {
encoding = g_strdup ("GB2312");
*start_text = 1;
*is_multibyte = FALSE;
} else if (firstbyte == 0x14) {
encoding = g_strdup ("UTF-16BE");
*start_text = 1;
*is_multibyte = TRUE;
} else if (firstbyte == 0x15) {
encoding = g_strdup ("ISO-10646/UTF8");
*start_text = 1;
*is_multibyte = FALSE;
} else {
/* reserved */
encoding = NULL;
@ -2448,7 +2457,7 @@ convert_to_utf8 (const gchar * text, gint length, guint start,
/* skip it */
break;
case 0xE08A:{
guint8 nl[] = { 0x0A, 0x00 }; /* new line */
guint8 nl[] = { 0x00, 0x0A }; /* new line */
g_byte_array_append (sb, nl, 2);
break;
}
@ -2469,7 +2478,7 @@ convert_to_utf8 (const gchar * text, gint length, guint start,
/* skip it */
break;
case 0xE08A:{
guint8 nl[] = { 0x0A, 0x00 }; /* new line */
guint8 nl[] = { 0x00, 0x0A }; /* new line */
g_byte_array_append (sb, nl, 2);
break;
}

View file

@ -1,7 +0,0 @@
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs

View file

@ -1,10 +0,0 @@
plugin_LTLIBRARIES = libgstpassthrough.la
libgstpassthrough_la_SOURCES = gstpassthrough.c
libgstpassthrough_la_CFLAGS = $(GST_CFLAGS)
libgstpassthrough_la_LIBADD =
libgstpassthrough_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstpassthrough_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstpassthrough.h filter.func

View file

@ -1,18 +0,0 @@
{
guint j;
static long int sample = 0; /* you can use this to count samples */
/*
* process data here
* *data contains the original 8 or 16 bit samples and is modified in place
* channels are interleaved in input data
*/
/* do nothing */
for (j = 0; j < num_samples; j++)
{
data[j] = data[j];
}
sample += num_samples;
}

View file

@ -1,306 +0,0 @@
/* -*- c-basic-offset: 2 -*-
* GStreamer
* Copyright (C) 1999-2001 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/gst.h>
#include <gst/audio/audio.h>
#include "gstpassthrough.h"
#define PASSTHRU_BUF_SIZE 4096
#define PASSTHRU_NUM_BUFS 4
enum
{
/* FILL ME */
LAST_SIGNAL
};
/* static guint gst_filter_signals[LAST_SIGNAL] = { 0 }; */
enum
{
ARG_0,
ARG_SILENT
};
static GstStaticPadTemplate passthrough_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS)
);
static GstStaticPadTemplate passthrough_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS)
);
static void passthrough_class_init (GstPassthroughClass * klass);
static void passthrough_base_init (GstPassthroughClass * klass);
static void passthrough_init (GstPassthrough * filter);
static void passthrough_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void passthrough_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstPadLinkReturn passthrough_connect_sink (GstPad * pad,
const GstCaps * caps);
static void passthrough_chain (GstPad * pad, GstData * _data);
static void inline passthrough_fast_float_chain (gfloat * data,
guint numsamples);
static void inline passthrough_fast_16bit_chain (gint16 * data,
guint numsamples);
static void inline passthrough_fast_8bit_chain (gint8 * data, guint numsamples);
static GstElementClass *parent_class = NULL;
static GstPadLinkReturn
passthrough_connect_sink (GstPad * pad, const GstCaps * caps)
{
const gchar *mimetype;
GstPassthrough *filter;
GstStructure *structure;
g_return_val_if_fail (pad != NULL, GST_PAD_LINK_DELAYED);
g_return_val_if_fail (caps != NULL, GST_PAD_LINK_DELAYED);
filter = GST_PASSTHROUGH (gst_pad_get_parent (pad));
g_return_val_if_fail (filter != NULL, GST_PAD_LINK_REFUSED);
g_return_val_if_fail (GST_IS_PASSTHROUGH (filter), GST_PAD_LINK_REFUSED);
structure = gst_caps_get_structure (caps, 0);
mimetype = gst_structure_get_name (structure);
gst_structure_get_int (structure, "rate", &filter->rate);
gst_structure_get_int (structure, "channels", &filter->channels);
gst_structure_get_int (structure, "width", &filter->width);
gst_structure_get_int (structure, "endianness", &filter->endianness);
if (strcmp (mimetype, "audio/x-raw-int") == 0) {
filter->format = GST_PASSTHROUGH_FORMAT_INT;
gst_structure_get_int (structure, "depth", &filter->depth);
gst_structure_get_boolean (structure, "signed", &filter->is_signed);
if (!filter->silent) {
g_print ("Passthrough : channels %d, rate %d\n", filter->channels,
filter->rate);
g_print
("Passthrough : format int, bit width %d, endianness %d, signed %s\n",
filter->width, filter->endianness, filter->is_signed ? "yes" : "no");
}
} else if (strcmp (mimetype, "audio/x-raw-float") == 0) {
filter->format = GST_PASSTHROUGH_FORMAT_FLOAT;
if (!filter->silent) {
g_print ("Passthrough : channels %d, rate %d\n", filter->channels,
filter->rate);
g_print ("Passthrough : format float, width %d\n", filter->width);
}
}
return gst_pad_try_set_caps (filter->srcpad, caps);
}
GType
gst_passthrough_get_type (void)
{
static GType passthrough_type = 0;
if (!passthrough_type) {
static const GTypeInfo passthrough_info = {
sizeof (GstPassthroughClass),
(GBaseInitFunc) passthrough_base_init,
NULL,
(GClassInitFunc) passthrough_class_init,
NULL,
NULL,
sizeof (GstPassthrough),
0,
(GInstanceInitFunc) passthrough_init,
};
passthrough_type =
g_type_register_static (GST_TYPE_ELEMENT, "GstPassthrough",
&passthrough_info, 0);
}
return passthrough_type;
}
static void
passthrough_base_init (GstPassthroughClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&passthrough_src_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&passthrough_sink_template));
gst_element_class_set_details_simple (element_class, "Passthrough",
"Filter/Effect/Audio",
"Transparent filter for audio/raw (boilerplate for effects)",
"Thomas <thomas@apestaart.org>, " "Andy Wingo <apwingo@eos.ncsu.edu>");
}
static void
passthrough_class_init (GstPassthroughClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
parent_class = g_type_class_peek_parent (klass);
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SILENT,
g_param_spec_boolean ("silent", "silent", "silent", TRUE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gobject_class->set_property = passthrough_set_property;
gobject_class->get_property = passthrough_get_property;
}
static void
passthrough_init (GstPassthrough * filter)
{
filter->srcpad =
gst_pad_new_from_static_template (&passthrough_src_template, "src");
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
filter->sinkpad =
gst_pad_new_from_static_template (&passthrough_sink_template, "sink");
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
gst_pad_set_link_function (filter->sinkpad, passthrough_connect_sink);
gst_pad_set_chain_function (filter->sinkpad, passthrough_chain);
filter->silent = FALSE;
}
static void
passthrough_chain (GstPad * pad, GstData * _data)
{
GstBuffer *buf = GST_BUFFER (_data);
GstPassthrough *filter;
gint16 *int_data;
gfloat *float_data;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
filter = GST_PASSTHROUGH (gst_pad_get_parent (pad));
g_return_if_fail (filter != NULL);
g_return_if_fail (GST_IS_PASSTHROUGH (filter));
switch (filter->format) {
case GST_PASSTHROUGH_FORMAT_INT:
int_data = (gint16 *) GST_BUFFER_DATA (buf);
switch (filter->width) {
case 16:
passthrough_fast_16bit_chain (int_data, GST_BUFFER_SIZE (buf) / 2);
break;
case 8:
passthrough_fast_8bit_chain ((gint8 *) int_data,
GST_BUFFER_SIZE (buf));
break;
}
break;
case GST_PASSTHROUGH_FORMAT_FLOAT:
float_data = (gfloat *) GST_BUFFER_DATA (buf);
passthrough_fast_float_chain (float_data,
GST_BUFFER_SIZE (buf) / sizeof (gfloat));
break;
}
gst_pad_push (filter->srcpad, GST_DATA (buf));
}
static void inline
passthrough_fast_float_chain (gfloat * data, guint num_samples)
#include "filter.func"
static void inline
passthrough_fast_16bit_chain (gint16 * data, guint num_samples)
#include "filter.func"
static void inline
passthrough_fast_8bit_chain (gint8 * data, guint num_samples)
#include "filter.func"
static void
passthrough_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstPassthrough *filter;
g_return_if_fail (GST_IS_PASSTHROUGH (object));
filter = GST_PASSTHROUGH (object);
switch (prop_id) {
case ARG_SILENT:
filter->silent = g_value_get_boolean (value);
break;
default:
break;
}
}
static void
passthrough_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstPassthrough *filter;
g_return_if_fail (GST_IS_PASSTHROUGH (object));
filter = GST_PASSTHROUGH (object);
switch (prop_id) {
case ARG_SILENT:
g_value_set_boolean (value, filter->silent);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, "passthrough",
GST_RANK_NONE, GST_TYPE_PASSTHROUGH);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"passthrough",
"Transparent filter for audio/raw (boilerplate for effects)",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,79 +0,0 @@
/* -*- c-basic-offset: 2 -*-
* GStreamer
* 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_PASSTHROUGH_H__
#define __GST_PASSTHROUGH_H__
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_PASSTHROUGH \
(gst_passthrough_get_type())
#define GST_PASSTHROUGH(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PASSTHROUGH,GstPassthrough))
#define GST_PASSTHROUGH_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PASSTHROUGH,GstPassthroughClass))
#define GST_PASSTHROUGH_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_PASSTHROUGH,GstPassthroughClass))
#define GST_IS_PASSTHROUGH(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PASSTHROUGH))
#define GST_IS_PASSTHROUGH_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PASSTHROUGH))
typedef struct _GstPassthrough GstPassthrough;
typedef struct _GstPassthroughClass GstPassthroughClass;
typedef enum _GstPassthroughFormat GstPassthroughFormat;
enum _GstPassthroughFormat {
GST_PASSTHROUGH_FORMAT_INT,
GST_PASSTHROUGH_FORMAT_FLOAT
};
struct _GstPassthrough {
GstElement element;
GstPad *sinkpad, *srcpad;
gboolean silent;
/* the next are valid for both int and float */
GstPassthroughFormat format;
guint rate;
guint channels;
guint width;
guint endianness;
guint buffer_size;
/* the next are valid only for int formats */
guint depth;
gboolean is_signed;
};
struct _GstPassthroughClass {
GstElementClass parent_class;
};
GType gst_passthrough_get_type(void);
G_END_DECLS
#endif /* __GST_PASSTHROUGH_H__ */

View file

@ -1,151 +0,0 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="7.10"
Name="passthrgouh"
ProjectGUID="{979C216F-0ACF-4956-AE00-055A42D678C3}"
Keyword="Win32Proj">
<Platforms>
<Platform
Name="Win32"/>
</Platforms>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="../../win32/Debug"
IntermediateDirectory="../../win32/Debug"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;&quot;../../gst-libs&quot;;../../../popt/include;../../../libxml2/include/libxml2"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;passthrgouh_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES"
MinimalRebuild="TRUE"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="4"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
OutputFile="$(OutDir)/gstpassthrgouh.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="../../../gstreamer/win32/Debug;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib"
ModuleDefinitionFile=""
GenerateDebugInformation="TRUE"
ProgramDatabaseFile="$(OutDir)/passthrgouh.pdb"
SubSystem="2"
OptimizeReferences="2"
ImportLibrary="$(OutDir)/gstpassthrgouh.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="../../win32/Release"
IntermediateDirectory="../../win32/Release"
ConfigurationType="2"
CharacterSet="2">
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="../../../gstreamer/win32;../../../gstreamer;../../../gstreamer/libs;../../../glib;../../../glib/glib;../../../glib/gmodule;&quot;../../gst-libs&quot;;../../../popt/include;../../../libxml2/include/libxml2"
PreprocessorDefinitions="WIN32;NDEBUG;GST_DISABLE_GST_DEBUG;_WINDOWS;_USRDLL;passthrgouh_EXPORTS;HAVE_CONFIG_H;_USE_MATH_DEFINES"
RuntimeLibrary="2"
UsePrecompiledHeader="0"
WarningLevel="3"
Detect64BitPortabilityProblems="TRUE"
DebugInformationFormat="3"/>
<Tool
Name="VCCustomBuildTool"/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="glib-2.0.lib gmodule-2.0.lib gthread-2.0.lib gobject-2.0.lib libgstreamer.lib gstbytestream.lib iconv.lib intl.lib"
OutputFile="$(OutDir)/gstpassthrgouh.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="../../../gstreamer/win32/Release;../../../glib/glib;../../../glib/gmodule;../../../glib/gthread;../../../glib/gobject;../../../gettext/lib;../../../libiconv/lib"
ModuleDefinitionFile=""
GenerateDebugInformation="TRUE"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/gstpassthrgouh.lib"
TargetMachine="1"/>
<Tool
Name="VCMIDLTool"/>
<Tool
Name="VCPostBuildEventTool"
CommandLine="copy /Y $(TargetPath) c:\gstreamer\plugins"/>
<Tool
Name="VCPreBuildEventTool"/>
<Tool
Name="VCPreLinkEventTool"/>
<Tool
Name="VCResourceCompilerTool"/>
<Tool
Name="VCWebServiceProxyGeneratorTool"/>
<Tool
Name="VCXMLDataGeneratorTool"/>
<Tool
Name="VCWebDeploymentTool"/>
<Tool
Name="VCManagedWrapperGeneratorTool"/>
<Tool
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
<File
RelativePath=".\gstpassthrough.c">
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
<File
RelativePath=".\filter.func">
</File>
<File
RelativePath=".\gstpassthrough.h">
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View file

@ -1 +0,0 @@
demo_mp3

View file

@ -1,19 +0,0 @@
plugin_LTLIBRARIES = libgstplayondemand.la
libgstplayondemand_la_SOURCES = gstplayondemand.c
libgstplayondemand_la_CFLAGS = $(GST_CFLAGS)
libgstplayondemand_la_LIBADD =
libgstplayondemand_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstplayondemand_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstplayondemand.h filter.func
if HAVE_GTK
noinst_PROGRAMS = demo_mp3
endif
demo_mp3_SOURCES = demo-mp3.c gstplayondemand.h
## putting GTK_CFLAGS first fixes a weird compilation error with GTK and XML
demo_mp3_CFLAGS = $(GTK_CFLAGS) $(GST_CFLAGS)
demo_mp3_LDFLAGS = $(GST_LIBS) $(GTK_LIBS)

View file

@ -1,187 +0,0 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <glib.h>
#include <gtk/gtk.h>
#include <gst/gst.h>
#define NUM_BEATS 12
#define TICK_RATE(x) (x * 1e-6)
GtkWidget *window, *vbox, *beat_box, *button_box;
GtkWidget *play_button, *clear_button, *reset_button, *quit_button;
GtkWidget **beat_button;
GtkWidget *speed_scale;
GtkObject *speed_adj;
GstElement *src, *dec, *pod, *sink, *pipeline;
GstClock *element_clock;
guint32 *beats;
void
played (GstElement * pod, gpointer data)
{
gint i;
g_print ("Played beat at %02u, beats are ",
(guint) (gst_clock_get_time (element_clock) / GST_SECOND *
(GTK_ADJUSTMENT (speed_adj))->value) % NUM_BEATS);
for (i = 0; i <= NUM_BEATS / 32; i++)
g_print ("%08x ", beats[i]);
g_print ("\n");
}
void
play (GtkButton * button, gpointer data)
{
g_signal_emit_by_name (G_OBJECT (pod), "play", NULL, NULL);
}
void
clear (GtkButton * button, gpointer data)
{
g_signal_emit_by_name (G_OBJECT (pod), "clear", NULL, NULL);
}
void
reset (GtkButton * button, gpointer data)
{
guint i;
g_signal_emit_by_name (G_OBJECT (pod), "reset", NULL, NULL);
for (i = 0; i < NUM_BEATS; i++)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (beat_button[i]), 0);
}
void
beat (GtkToggleButton * button, gpointer data)
{
guint b = GPOINTER_TO_UINT (data);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
beats[b / 32] |= 1 << (b % 32);
else
beats[b / 32] &= ~(1 << (b % 32));
}
void
speed (GtkAdjustment * adjustment, gpointer data)
{
/*g_signal_stop_emission_by_name(G_OBJECT(pod), "deep-notify"); */
g_object_set (G_OBJECT (pod), "tick-rate", TICK_RATE (adjustment->value),
NULL);
/*gst_clock_set_speed(element_clock, adjustment->value); */
}
void
setup_pipeline (gchar * filename)
{
src = gst_element_factory_make ("filesrc", "source");
dec = gst_element_factory_make ("vorbisfile", "decoder");
pod = gst_element_factory_make ("playondemand", "sequencer");
sink = gst_element_factory_make (DEFAULT_AUDIOSINK, "sink");
g_object_set (G_OBJECT (src), "location", filename, NULL);
g_object_set (G_OBJECT (sink), "period-count", 64, "period-size", 512, NULL);
g_object_set (G_OBJECT (pod), "total-ticks", NUM_BEATS,
"tick-rate", 1.0e-6, "max-plays", NUM_BEATS * 2, NULL);
g_object_get (G_OBJECT (pod), "ticks", &beats, NULL);
pipeline = gst_pipeline_new ("app");
gst_bin_add_many (GST_BIN (pipeline), src, dec, pod, sink, NULL);
gst_element_link_many (src, dec, pod, sink, NULL);
element_clock = gst_element_get_clock (GST_ELEMENT (sink));
gst_element_set_clock (GST_ELEMENT (pod), element_clock);
}
void
setup_gui (void)
{
guint i;
beat_button = g_new (GtkWidget *, NUM_BEATS);
/* initialize gui elements ... */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_container_set_border_width (GTK_CONTAINER (window), 12);
vbox = gtk_vbox_new (TRUE, 0);
gtk_box_set_spacing (GTK_BOX (vbox), 12);
beat_box = gtk_hbox_new (TRUE, 0);
button_box = gtk_hbox_new (TRUE, 0);
play_button = gtk_button_new_with_label ("Play");
clear_button = gtk_button_new_with_label ("Reset Sound");
reset_button = gtk_button_new_with_label ("Reset All");
quit_button = gtk_button_new_with_label ("Quit");
for (i = 0; i < NUM_BEATS; i++)
beat_button[i] =
gtk_toggle_button_new_with_label (g_strdup_printf ("%2d", i + 1));
speed_adj = gtk_adjustment_new (1, 0.0, 10.0, 0.1, 1.0, 0.0);
speed_scale = gtk_hscale_new (GTK_ADJUSTMENT (speed_adj));
gtk_scale_set_digits (GTK_SCALE (speed_scale), 4);
gtk_range_set_update_policy (GTK_RANGE (speed_scale),
GTK_UPDATE_DISCONTINUOUS);
/* do the packing stuff ... */
gtk_window_set_default_size (GTK_WINDOW (window), 96, 96);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_box_pack_start (GTK_BOX (button_box), play_button, TRUE, TRUE, 2);
gtk_box_pack_start (GTK_BOX (button_box), clear_button, TRUE, TRUE, 2);
gtk_box_pack_start (GTK_BOX (button_box), reset_button, TRUE, TRUE, 2);
gtk_box_pack_start (GTK_BOX (button_box), quit_button, TRUE, TRUE, 2);
for (i = 0; i < NUM_BEATS; i++)
gtk_box_pack_start (GTK_BOX (beat_box), beat_button[i], TRUE, TRUE, 2);
gtk_box_pack_start (GTK_BOX (vbox), button_box, TRUE, FALSE, 2);
gtk_box_pack_start (GTK_BOX (vbox), beat_box, TRUE, FALSE, 2);
gtk_box_pack_start (GTK_BOX (vbox), speed_scale, TRUE, FALSE, 2);
/* connect things ... */
g_signal_connect (G_OBJECT (play_button), "clicked", G_CALLBACK (play), NULL);
g_signal_connect (G_OBJECT (clear_button), "clicked", G_CALLBACK (clear),
NULL);
g_signal_connect (G_OBJECT (reset_button), "clicked", G_CALLBACK (reset),
NULL);
g_signal_connect (G_OBJECT (quit_button), "clicked", gtk_main_quit, NULL);
g_signal_connect (G_OBJECT (pod), "played", G_CALLBACK (played), NULL);
g_signal_connect (G_OBJECT (speed_adj), "value_changed", G_CALLBACK (speed),
NULL);
for (i = 0; i < NUM_BEATS; i++)
g_signal_connect (G_OBJECT (beat_button[i]), "toggled", G_CALLBACK (beat),
GUINT_TO_POINTER (i));
/* show the gui. */
gtk_widget_show_all (window);
gtk_idle_add ((GtkFunction) gst_bin_iterate, pipeline);
}
int
main (int argc, char **argv)
{
gst_init (&argc, &argv);
gtk_init (&argc, &argv);
if (argc != 2) {
g_print ("usage: %s <mp3-filename>\n", argv[0]);
exit (-1);
}
setup_pipeline (argv[1]);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
setup_gui ();
gtk_main ();
g_free (beat_button);
return 0;
}

View file

@ -1,113 +0,0 @@
/* -*- C -*- */
_TYPE_ *data_in, *data_out, *filter_data;
filter_data = (_TYPE_ *) filter->buffer;
num_filter = filter->buffer_bytes / sizeof(_TYPE_);
do {
/* see if we've got any events coming through ... */
while (! filter->eos && in != NULL && GST_IS_EVENT (in)) {
GstEvent *event = GST_EVENT (in);
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
gst_data_unref (in);
in = NULL;
filter->eos = TRUE;
} else if ((GST_EVENT_TYPE (event) == GST_EVENT_DISCONTINUOUS) ||
(GST_EVENT_TYPE (event) == GST_EVENT_FLUSH)) {
gst_data_unref (in);
in = NULL;
filter->eos = FALSE;
filter->write = 0;
} else {
gst_pad_push(filter->srcpad, in);
}
in = (in == NULL && ! filter->eos) ? gst_pad_pull(filter->sinkpad) : NULL;
}
/* handle data from the input buffer. */
if (! filter->eos) {
register guint j, w = filter->write;
data_in = (_TYPE_ *) GST_BUFFER_DATA (GST_BUFFER (in));
num_in = GST_BUFFER_SIZE (in) / sizeof(_TYPE_);
for (j = 0; (j < num_in) && (w+j < num_filter); j++)
filter_data[w+j] = data_in[j];
filter->write += j;
if (filter->write >= num_filter) filter->eos = TRUE;
out = GST_BUFFER (in);
} else {
out = gst_buffer_new_and_alloc (GST_POD_BUFPOOL_SIZE);
}
in = NULL;
/* check to see if we have to add new play pointers. */
if (filter->clock) {
register gint t, tick_offset;
guint total_ticks = filter->total_ticks;
guint current_tick = \
((guint) (gst_clock_get_time(filter->clock) * \
filter->tick_rate / GST_SECOND)) % total_ticks;
tick_offset = current_tick - last_tick;
if (tick_offset < 0) tick_offset += total_ticks;
for (tick_offset -= 1, t = current_tick - tick_offset;
tick_offset >= 0;
tick_offset--, t--) {
if (t < 0) t += total_ticks;
if (filter->ticks[t / 32] & (1 << t % 32))
play_on_demand_add_play_pointer(
filter, filter->rate * tick_offset / filter->tick_rate);
}
last_tick = current_tick;
}
/* handle output data. */
{
register guint k, p;
data_out = (_TYPE_ *) GST_BUFFER_DATA (out);
num_out = GST_BUFFER_SIZE (out) / sizeof(_TYPE_);
for (k = 0; k < num_out; k++) data_out[k] = zero;
for (p = 0; p < filter->max_plays; p++) {
guint offset = filter->plays[p];
if (offset != G_MAXUINT) {
/* only copy audio data if the element's not muted. */
if (! filter->mute)
for (k = 0; (k < num_out) && (offset+k < num_filter); k++)
data_out[k] = CLAMP(data_out[k] + filter_data[offset+k], min, max);
/* update the play pointer. k > 0 even if the filter is muted. */
filter->plays[p] = (offset+k >= num_filter) ? G_MAXUINT : offset + k;
}
}
}
/* push out the buffer and get a new buffer if we're allowed to loop. */
gst_pad_push(filter->srcpad, GST_DATA (out));
if (gst_element_interrupt (GST_ELEMENT (filter))) break;
in = (in == NULL && ! filter->eos) ? gst_pad_pull(filter->sinkpad) : NULL;
} while (TRUE);

View file

@ -1,570 +0,0 @@
/* GStreamer
* Copyright (C) 1999-2001 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/gst.h>
#include <gst/audio/audio.h>
#include "gstplayondemand.h"
/* in these files, a 'tick' is a discrete unit of time, usually around the 1ms
* range. a tick is not divisible into smaller units of time. 1ms is probably
* way beyond what a real computer can actually keep track of, but hey ... */
/* some default values */
#define GST_POD_MAX_PLAYS 100 /* maximum simultaneous plays */
#define GST_POD_BUFFER_TIME 5.0 /* buffer length in seconds */
#define GST_POD_TICK_RATE 1e-6 /* ticks per second */
/* buffer pool fallback values ... use if no buffer pool is available */
#define GST_POD_BUFPOOL_SIZE 4096
#define GST_POD_BUFPOOL_NUM 6
static GstStaticPadTemplate play_on_demand_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS)
);
static GstStaticPadTemplate play_on_demand_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_AUDIO_INT_PAD_TEMPLATE_CAPS "; "
GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS)
);
/* GObject functionality */
static void play_on_demand_class_init (GstPlayOnDemandClass * klass);
static void play_on_demand_base_init (GstPlayOnDemandClass * klass);
static void play_on_demand_init (GstPlayOnDemand * filter);
static void play_on_demand_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void play_on_demand_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void play_on_demand_finalize (GObject * object);
/* GStreamer functionality */
static GstPadLinkReturn play_on_demand_pad_link (GstPad * pad,
const GstCaps * caps);
static void play_on_demand_loop (GstElement * elem);
static gboolean play_on_demand_set_clock (GstElement * elem, GstClock * clock);
/* signal handlers */
static void play_on_demand_play_handler (GstElement * elem);
static void play_on_demand_clear_handler (GstElement * elem);
static void play_on_demand_reset_handler (GstElement * elem);
/* utility functions */
static void play_on_demand_add_play_pointer (GstPlayOnDemand * filter,
guint pos);
static void play_on_demand_resize_buffer (GstPlayOnDemand * filter);
GType
gst_play_on_demand_get_type (void)
{
static GType play_on_demand_type = 0;
if (!play_on_demand_type) {
static const GTypeInfo play_on_demand_info = {
sizeof (GstPlayOnDemandClass),
(GBaseInitFunc) play_on_demand_base_init,
NULL,
(GClassInitFunc) play_on_demand_class_init,
NULL,
NULL,
sizeof (GstPlayOnDemand),
0,
(GInstanceInitFunc) play_on_demand_init,
};
play_on_demand_type = g_type_register_static (GST_TYPE_ELEMENT,
"GstPlayOnDemand", &play_on_demand_info, 0);
}
return play_on_demand_type;
}
/* signals and properties */
enum
{
/* add signals here */
PLAYED_SIGNAL,
STOPPED_SIGNAL,
PLAY_SIGNAL,
CLEAR_SIGNAL,
RESET_SIGNAL,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_MUTE,
PROP_BUFFER_TIME,
PROP_MAX_PLAYS,
PROP_TICK_RATE,
PROP_TOTAL_TICKS,
PROP_TICKS
};
static guint gst_pod_filter_signals[LAST_SIGNAL] = { 0 };
static GstElementClass *parent_class = NULL;
static void
play_on_demand_base_init (GstPlayOnDemandClass * klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&play_on_demand_src_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&play_on_demand_sink_template));
gst_element_class_set_details_simple (element_class, "Play On Demand",
"Filter/Editor/Audio",
"Schedule a stream to play at specific times, or when a signal is received",
"Leif Morgan Johnson <leif@ambient.2y.net>");
}
static void
play_on_demand_class_init (GstPlayOnDemandClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gst_pod_filter_signals[PLAYED_SIGNAL] =
g_signal_new ("played", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstPlayOnDemandClass, played),
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
gst_pod_filter_signals[STOPPED_SIGNAL] =
g_signal_new ("stopped", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstPlayOnDemandClass, stopped),
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
gst_pod_filter_signals[PLAY_SIGNAL] =
g_signal_new ("play", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstPlayOnDemandClass, play),
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
gst_pod_filter_signals[CLEAR_SIGNAL] =
g_signal_new ("clear", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstPlayOnDemandClass, clear),
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
gst_pod_filter_signals[RESET_SIGNAL] =
g_signal_new ("reset", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstPlayOnDemandClass, reset),
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
klass->play = play_on_demand_play_handler;
klass->clear = play_on_demand_clear_handler;
klass->reset = play_on_demand_reset_handler;
parent_class = g_type_class_peek_parent (klass);
gobject_class->set_property = play_on_demand_set_property;
gobject_class->get_property = play_on_demand_get_property;
gobject_class->finalize = play_on_demand_finalize;
gstelement_class->set_clock = play_on_demand_set_clock;
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MUTE,
g_param_spec_boolean ("mute", "Silence output", "Do not output any sound",
FALSE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BUFFER_TIME,
g_param_spec_float ("buffer-time", "Buffer length in seconds",
"Number of seconds of audio the buffer holds", 0.0, G_MAXFLOAT,
GST_POD_BUFFER_TIME,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_PLAYS,
g_param_spec_uint ("max-plays", "Maximum simultaneous playbacks",
"Maximum allowed number of simultaneous plays from the buffer", 1,
G_MAXUINT, GST_POD_MAX_PLAYS,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TICK_RATE,
g_param_spec_float ("tick-rate", "Tick rate (ticks/second)",
"The rate of musical ticks, the smallest time unit in a song", 0,
G_MAXFLOAT, GST_POD_TICK_RATE,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TOTAL_TICKS,
g_param_spec_uint ("total-ticks", "Total number of ticks",
"Total number of ticks in the tick array", 1, G_MAXUINT, 1,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TICKS,
g_param_spec_pointer ("ticks", "Ticks to play sample on",
"An array of ticks (musical times) at which to play the sample",
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
play_on_demand_init (GstPlayOnDemand * filter)
{
filter->srcpad =
gst_pad_new_from_static_template (&play_on_demand_src_template, "src");
filter->sinkpad =
gst_pad_new_from_static_template (&play_on_demand_sink_template, "sink");
gst_pad_set_link_function (filter->sinkpad, play_on_demand_pad_link);
gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
gst_element_set_loop_function (GST_ELEMENT (filter), play_on_demand_loop);
filter->clock = NULL;
filter->rate = 0;
filter->ticks = g_new (guint32, filter->total_ticks / 32 + 1);
filter->plays = g_new (guint, filter->max_plays);
play_on_demand_resize_buffer (filter);
play_on_demand_reset_handler (GST_ELEMENT (filter));
}
static void
play_on_demand_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstPlayOnDemand *filter;
register guint i;
guint new_size, min_size, *new_plays;
guint *new_ticks;
g_return_if_fail (GST_IS_PLAYONDEMAND (object));
filter = GST_PLAYONDEMAND (object);
switch (prop_id) {
case PROP_MUTE:
filter->mute = g_value_get_boolean (value);
break;
case PROP_BUFFER_TIME:
filter->buffer_time = g_value_get_float (value);
play_on_demand_resize_buffer (filter);
/* clear out now-invalid play pointers */
for (i = 0; i < filter->max_plays; i++)
filter->plays[i] = G_MAXUINT;
break;
case PROP_MAX_PLAYS:
new_size = g_value_get_uint (value);
min_size = (new_size < filter->max_plays) ? new_size : filter->max_plays;
new_plays = g_new (guint, new_size);
for (i = 0; i < min_size; i++)
new_plays[i] = filter->plays[i];
for (i = min_size; i < new_size; i++)
new_plays[i] = G_MAXUINT;
g_free (filter->plays);
filter->plays = new_plays;
filter->max_plays = new_size;
break;
case PROP_TICK_RATE:
filter->tick_rate = g_value_get_float (value);
break;
case PROP_TOTAL_TICKS:
new_size = g_value_get_uint (value);
min_size =
(new_size < filter->total_ticks) ? new_size : filter->total_ticks;
new_ticks = g_new (guint32, new_size / 32 + 1);
for (i = 0; i <= min_size / 32; i++)
new_ticks[i] = filter->ticks[i];
for (i = min_size / 32 + 1; i <= new_size / 32; i++)
new_ticks[i] = 0;
g_free (filter->ticks);
filter->ticks = new_ticks;
filter->total_ticks = new_size;
break;
case PROP_TICKS:
new_ticks = (guint *) g_value_get_pointer (value);
if (new_ticks) {
g_free (filter->ticks);
filter->ticks = new_ticks;
}
break;
default:
break;
}
}
static void
play_on_demand_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec)
{
GstPlayOnDemand *filter;
g_return_if_fail (GST_IS_PLAYONDEMAND (object));
filter = GST_PLAYONDEMAND (object);
switch (prop_id) {
case PROP_MUTE:
g_value_set_boolean (value, filter->mute);
break;
case PROP_BUFFER_TIME:
g_value_set_float (value, filter->buffer_time);
break;
case PROP_MAX_PLAYS:
g_value_set_uint (value, filter->max_plays);
break;
case PROP_TICK_RATE:
g_value_set_float (value, filter->tick_rate);
break;
case PROP_TOTAL_TICKS:
g_value_set_uint (value, filter->total_ticks);
break;
case PROP_TICKS:
g_value_set_pointer (value, (gpointer) filter->ticks);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
play_on_demand_finalize (GObject * object)
{
GstPlayOnDemand *filter = GST_PLAYONDEMAND (object);
g_free (filter->ticks);
g_free (filter->plays);
g_free (filter->buffer);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static GstPadLinkReturn
play_on_demand_pad_link (GstPad * pad, const GstCaps * caps)
{
const gchar *mimetype;
GstPlayOnDemand *filter;
GstStructure *structure;
g_return_val_if_fail (caps != NULL, GST_PAD_LINK_DELAYED);
g_return_val_if_fail (pad != NULL, GST_PAD_LINK_DELAYED);
filter = GST_PLAYONDEMAND (GST_PAD_PARENT (pad));
structure = gst_caps_get_structure (caps, 0);
mimetype = gst_structure_get_name (structure);
gst_structure_get_int (structure, "rate", &filter->rate);
gst_structure_get_int (structure, "channels", &filter->channels);
if (strcmp (mimetype, "audio/x-raw-int") == 0) {
filter->format = GST_PLAYONDEMAND_FORMAT_INT;
gst_structure_get_int (structure, "width", &filter->width);
} else if (strcmp (mimetype, "audio/x-raw-float") == 0) {
filter->format = GST_PLAYONDEMAND_FORMAT_FLOAT;
}
play_on_demand_resize_buffer (filter);
return gst_pad_try_set_caps (filter->srcpad, caps);
}
inline static void
play_on_demand_add_play_pointer (GstPlayOnDemand * filter, guint pos)
{
register guint i;
if (filter->rate && ((filter->buffer_time * filter->rate) > pos)) {
for (i = 0; i < filter->max_plays; i++) {
if (filter->plays[i] == G_MAXUINT) {
filter->plays[i] = pos;
/* emit a signal to indicate a sample being played */
g_signal_emit (filter, gst_pod_filter_signals[PLAYED_SIGNAL], 0);
break;
}
}
}
}
static void
play_on_demand_loop (GstElement * elem)
{
GstPlayOnDemand *filter = GST_PLAYONDEMAND (elem);
guint num_in, num_out, num_filter;
GstData *in = NULL;
GstBuffer *out = NULL;
static guint last_tick = 0;
g_return_if_fail (filter != NULL);
g_return_if_fail (GST_IS_PLAYONDEMAND (filter));
in = (in == NULL && !filter->eos) ? gst_pad_pull (filter->sinkpad) : NULL;
if (filter->format == GST_PLAYONDEMAND_FORMAT_INT) {
if (filter->width == 16) {
gint16 min = 0xffff;
gint16 max = 0x7fff;
gint16 zero = 0;
#define _TYPE_ gint16
#include "filter.func"
#undef _TYPE_
} else if (filter->width == 8) {
gint8 min = 0xff;
gint8 max = 0x7f;
gint8 zero = 0;
#define _TYPE_ gint8
#include "filter.func"
#undef _TYPE_
}
} else if (filter->format == GST_PLAYONDEMAND_FORMAT_FLOAT) {
gfloat min = -1.0;
gfloat max = 1.0;
gfloat zero = 0.0;
#define _TYPE_ gfloat
#include "filter.func"
#undef _TYPE_
}
}
static gboolean
play_on_demand_set_clock (GstElement * elem, GstClock * clock)
{
GstPlayOnDemand *filter;
g_return_if_fail (elem != NULL);
g_return_if_fail (GST_IS_PLAYONDEMAND (elem));
filter = GST_PLAYONDEMAND (elem);
filter->clock = clock;
return GST_ELEMENT_CLASS (parent_class)->set_clock (elem, clock);
}
static void
play_on_demand_play_handler (GstElement * elem)
{
GstPlayOnDemand *filter;
g_return_if_fail (elem != NULL);
g_return_if_fail (GST_IS_PLAYONDEMAND (elem));
filter = GST_PLAYONDEMAND (elem);
play_on_demand_add_play_pointer (filter, 0);
}
static void
play_on_demand_clear_handler (GstElement * elem)
{
GstPlayOnDemand *filter;
register guint i;
g_return_if_fail (elem != NULL);
g_return_if_fail (GST_IS_PLAYONDEMAND (elem));
filter = GST_PLAYONDEMAND (elem);
filter->write = 0;
filter->eos = FALSE;
for (i = 0; i < filter->max_plays; i++)
filter->plays[i] = G_MAXUINT;
for (i = 0; i < filter->buffer_bytes; i++)
filter->buffer[i] = (gchar) 0;
}
static void
play_on_demand_reset_handler (GstElement * elem)
{
GstPlayOnDemand *filter;
register guint i;
play_on_demand_clear_handler (elem);
g_return_if_fail (elem != NULL);
g_return_if_fail (GST_IS_PLAYONDEMAND (elem));
filter = GST_PLAYONDEMAND (elem);
for (i = 0; i <= filter->total_ticks / 32; i++)
filter->ticks[i] = 0;
}
static void
play_on_demand_resize_buffer (GstPlayOnDemand * filter)
{
register guint i;
guint new_size, min_size;
gchar *new_buffer;
/* use a default sample rate of 44100, 1 channel, 1 byte per sample if caps
haven't been set yet */
new_size = (guint) filter->buffer_time;
new_size *= (filter->rate) ? filter->rate : 44100;
new_size *= (filter->channels) ? filter->channels : 1;
if (filter->format && filter->format == GST_PLAYONDEMAND_FORMAT_FLOAT)
new_size *= sizeof (gfloat);
else
new_size *= (filter->width) ? filter->width / 8 : 1;
min_size =
(new_size < filter->buffer_bytes) ? new_size : filter->buffer_bytes;
new_buffer = g_new (gchar, new_size);
for (i = 0; i < min_size; i++)
new_buffer[i] = filter->buffer[i];
for (i = min_size; i < new_size; i++)
new_buffer[i] = (gchar) 0;
g_free (filter->buffer);
filter->buffer = new_buffer;
filter->buffer_bytes = new_size;
}
static gboolean
plugin_init (GstPlugin * plugin)
{
return gst_element_register (plugin, "playondemand",
GST_RANK_NONE, GST_TYPE_PLAYONDEMAND);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"playondemand",
"Plays a stream at specific times, or when it receives a signal",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,97 +0,0 @@
/* -*- c-basic-offset: 2 -*-
* GStreamer
* 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_PLAYONDEMAND_H__
#define __GST_PLAYONDEMAND_H__
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <gst/gst.h>
G_BEGIN_DECLS
#define GST_TYPE_PLAYONDEMAND \
(gst_play_on_demand_get_type())
#define GST_PLAYONDEMAND(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_PLAYONDEMAND,GstPlayOnDemand))
#define GST_PLAYONDEMAND_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_PLAYONDEMAND,GstPlayOnDemandClass))
#define GST_IS_PLAYONDEMAND(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_PLAYONDEMAND))
#define GST_IS_PLAYONDEMAND_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_PLAYONDEMAND))
typedef struct _GstPlayOnDemand GstPlayOnDemand;
typedef struct _GstPlayOnDemandClass GstPlayOnDemandClass;
typedef enum _GstPlayOnDemandFormat GstPlayOnDemandFormat;
enum _GstPlayOnDemandFormat {
GST_PLAYONDEMAND_FORMAT_INT,
GST_PLAYONDEMAND_FORMAT_FLOAT
};
struct _GstPlayOnDemand {
GstElement element;
GstPad *sinkpad, *srcpad;
GstClock *clock;
/* filter properties */
gboolean mute;
gfloat buffer_time;
guint max_plays;
gfloat tick_rate;
guint total_ticks;
guint32 *ticks;
/* internal buffer info */
gchar *buffer;
guint buffer_bytes;
gboolean eos;
/* play pointers == internal buffer offsets for producing output sound */
guint *plays;
guint write;
/* audio format info (used to calculate buffer_samples) */
GstPlayOnDemandFormat format;
guint rate;
guint channels;
guint width;
};
struct _GstPlayOnDemandClass {
GstElementClass parent_class;
void (*play) (GstElement *elem);
void (*clear) (GstElement *elem);
void (*reset) (GstElement *elem);
void (*played) (GstElement *elem);
void (*stopped) (GstElement *elem);
};
GType gst_play_on_demand_get_type(void);
G_END_DECLS
#endif /* __GST_PLAYONDEMAND_H__ */

View file

@ -2,9 +2,29 @@
plugin_LTLIBRARIES = libgstsmooth.la
libgstsmooth_la_SOURCES = gstsmooth.c
libgstsmooth_la_CFLAGS = $(GST_CFLAGS)
libgstsmooth_la_LIBADD =
libgstsmooth_la_CFLAGS = \
$(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
$(GST_CFLAGS)
libgstsmooth_la_LIBADD = \
$(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_MAJORMINOR@ \
$(GST_BASE_LIBS) \
$(GST_LIBS)
libgstsmooth_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstsmooth_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstsmooth.h
Android.mk: Makefile.am $(BUILT_SOURCES)
androgenizer \
-:PROJECT libgstsmooth -:SHARED libgstsmooth \
-:TAGS eng debug \
-:REL_TOP $(top_srcdir) -:ABS_TOP $(abs_top_srcdir) \
-:SOURCES $(libgstsmooth_la_SOURCES) \
-:CFLAGS $(DEFS) $(DEFAULT_INCLUDES) $(libgstsmooth_la_CFLAGS) \
-:LDFLAGS $(libgstsmooth_la_LDFLAGS) \
$(libgstsmooth_la_LIBADD) \
-ldl \
-:PASSTHROUGH LOCAL_ARM_MODE:=arm \
LOCAL_MODULE_PATH:='$$(TARGET_OUT)/lib/gstreamer-0.10' \
> $@

View file

@ -1,5 +1,7 @@
/* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
* <2001> Wim Taymans <wim.taymans@chello.be>
* <2011> Stefan Sauer <ensonic@user.sf.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -24,20 +26,15 @@
#include "gstsmooth.h"
#include <gst/video/video.h>
/* Smooth signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
/* Smooth args */
enum
{
ARG_0,
ARG_ACTIVE,
ARG_TOLERANCE,
ARG_FILTERSIZE,
ARG_LUM_ONLY
PROP_0,
PROP_ACTIVE,
PROP_TOLERANCE,
PROP_FILTER_SIZE,
PROP_LUMA_ONLY
};
static GstStaticPadTemplate gst_smooth_src_template =
@ -56,11 +53,12 @@ GST_STATIC_PAD_TEMPLATE ("sink",
)
);
static void gst_smooth_class_init (GstSmoothClass * klass);
static void gst_smooth_base_init (GstSmoothClass * klass);
static void gst_smooth_init (GstSmooth * smooth);
static void gst_smooth_chain (GstPad * pad, GstData * _data);
static gboolean gst_smooth_set_caps (GstBaseTransform * btrans,
GstCaps * incaps, GstCaps * outcaps);
static GstFlowReturn gst_smooth_transform (GstBaseTransform * btrans,
GstBuffer * inbuf, GstBuffer * outbuf);
static void smooth_filter (unsigned char *dest, unsigned char *src,
int width, int height, int tolerance, int filtersize);
@ -69,38 +67,12 @@ static void gst_smooth_set_property (GObject * object, guint prop_id,
static void gst_smooth_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static GstElementClass *parent_class = NULL;
/*static guint gst_smooth_signals[LAST_SIGNAL] = { 0 }; */
GType
gst_smooth_get_type (void)
{
static GType smooth_type = 0;
if (!smooth_type) {
static const GTypeInfo smooth_info = {
sizeof (GstSmoothClass),
(GBaseInitFunc) gst_smooth_base_init,
NULL,
(GClassInitFunc) gst_smooth_class_init,
NULL,
NULL,
sizeof (GstSmooth),
0,
(GInstanceInitFunc) gst_smooth_init,
};
smooth_type =
g_type_register_static (GST_TYPE_ELEMENT, "GstSmooth", &smooth_info, 0);
}
return smooth_type;
}
GST_BOILERPLATE (GstSmooth, gst_smooth, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
static void
gst_smooth_base_init (GstSmoothClass * klass)
gst_smooth_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_smooth_sink_template));
@ -115,76 +87,63 @@ gst_smooth_base_init (GstSmoothClass * klass)
static void
gst_smooth_class_init (GstSmoothClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
parent_class = g_type_class_peek_parent (klass);
/* FIXME: add long property descriptions */
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_ACTIVE,
g_param_spec_boolean ("active", "active", "active", TRUE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOLERANCE,
g_param_spec_int ("tolerance", "tolerance", "tolerance", G_MININT,
G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FILTERSIZE,
g_param_spec_int ("filtersize", "filtersize", "filtersize", G_MININT,
G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
GObjectClass *gobject_class = (GObjectClass *) klass;
GstBaseTransformClass *btrans_class = (GstBaseTransformClass *) klass;
gobject_class->set_property = gst_smooth_set_property;
gobject_class->get_property = gst_smooth_get_property;
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ACTIVE,
g_param_spec_boolean ("active", "active", "process video", TRUE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TOLERANCE,
g_param_spec_int ("tolerance",
"tolerance", "contrast tolerance for smoothing", G_MININT,
G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILTER_SIZE,
g_param_spec_int ("filter-size", "filter-size", "size of media filter",
G_MININT, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LUMA_ONLY,
g_param_spec_boolean ("luma-only", "luma-only", "only filter luma part",
TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
btrans_class->transform = GST_DEBUG_FUNCPTR (gst_smooth_transform);
btrans_class->set_caps = GST_DEBUG_FUNCPTR (gst_smooth_set_caps);
}
static GstPadLinkReturn
gst_smooth_link (GstPad * pad, const GstCaps * caps)
static gboolean
gst_smooth_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
GstCaps * outcaps)
{
GstSmooth *filter;
GstStructure *structure;
gboolean ret;
filter = GST_SMOOTH (gst_pad_get_parent (pad));
filter = GST_SMOOTH (btrans);
structure = gst_caps_get_structure (caps, 0);
structure = gst_caps_get_structure (incaps, 0);
ret = gst_structure_get_int (structure, "width", &filter->width);
ret &= gst_structure_get_int (structure, "height", &filter->height);
if (!ret)
return GST_PAD_LINK_REFUSED;
return gst_pad_try_set_caps (filter->srcpad, caps);
return ret;
}
static void
gst_smooth_init (GstSmooth * smooth)
gst_smooth_init (GstSmooth * smooth, GstSmoothClass * klass)
{
smooth->sinkpad =
gst_pad_new_from_static_template (&gst_smooth_sink_template, "sink");
gst_pad_set_link_function (smooth->sinkpad, gst_smooth_link);
gst_pad_set_chain_function (smooth->sinkpad, gst_smooth_chain);
gst_element_add_pad (GST_ELEMENT (smooth), smooth->sinkpad);
smooth->srcpad =
gst_pad_new_from_static_template (&gst_smooth_sink_template, "src");
gst_pad_set_link_function (smooth->srcpad, gst_smooth_link);
gst_element_add_pad (GST_ELEMENT (smooth), smooth->srcpad);
smooth->active = TRUE;
smooth->tolerance = 8;
smooth->filtersize = 3;
smooth->lum_only = TRUE;
smooth->luma_only = TRUE;
}
static void
smooth_filter (unsigned char *dest, unsigned char *src, int width, int height,
int tolerance, int filtersize)
smooth_filter (guchar * dest, guchar * src, gint width, gint height,
gint tolerance, gint filtersize)
{
int refval, aktval, upperval, lowerval, numvalues, sum;
int x, y, fx, fy, fy1, fy2, fx1, fx2;
unsigned char *srcp = src;
gint refval, aktval, upperval, lowerval, numvalues, sum;
gint x, y, fx, fy, fy1, fy2, fx1, fx2;
guchar *srcp = src;
fy1 = 0;
fy2 = MIN (filtersize + 1, height) * width;
@ -224,57 +183,44 @@ smooth_filter (unsigned char *dest, unsigned char *src, int width, int height,
}
}
static void
gst_smooth_chain (GstPad * pad, GstData * _data)
static GstFlowReturn
gst_smooth_transform (GstBaseTransform * btrans, GstBuffer * inbuf,
GstBuffer * outbuf)
{
GstBuffer *buf = GST_BUFFER (_data);
GstSmooth *smooth;
guchar *data;
guchar *idata, *odata;
gulong size;
GstBuffer *outbuf;
gint lumsize, chromsize;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
smooth = GST_SMOOTH (GST_OBJECT_PARENT (pad));
smooth = GST_SMOOTH (btrans);
idata = GST_BUFFER_DATA (inbuf);
odata = GST_BUFFER_DATA (outbuf);
size = GST_BUFFER_SIZE (inbuf);
if (!smooth->active) {
gst_pad_push (smooth->srcpad, GST_DATA (buf));
return;
memcpy (odata, idata, size);
return GST_FLOW_OK;
}
data = GST_BUFFER_DATA (buf);
size = GST_BUFFER_SIZE (buf);
GST_DEBUG ("smooth: have buffer of %d", GST_BUFFER_SIZE (buf));
outbuf = gst_buffer_new ();
GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (buf));
GST_BUFFER_SIZE (outbuf) = GST_BUFFER_SIZE (buf);
GST_DEBUG_OBJECT (smooth, "smooth: have buffer of %d", size);
lumsize = smooth->width * smooth->height;
chromsize = lumsize / 4;
smooth_filter (GST_BUFFER_DATA (outbuf), data, smooth->width, smooth->height,
smooth_filter (odata, idata, smooth->width, smooth->height,
smooth->tolerance, smooth->filtersize);
if (!smooth->lum_only) {
smooth_filter (GST_BUFFER_DATA (outbuf) + lumsize, data + lumsize,
if (!smooth->luma_only) {
smooth_filter (odata + lumsize, idata + lumsize,
smooth->width / 2, smooth->height / 2, smooth->tolerance,
smooth->filtersize / 2);
smooth_filter (GST_BUFFER_DATA (outbuf) + lumsize + chromsize,
data + lumsize + chromsize, smooth->width / 2, smooth->height / 2,
smooth_filter (odata + lumsize + chromsize,
idata + lumsize + chromsize, smooth->width / 2, smooth->height / 2,
smooth->tolerance, smooth->filtersize / 2);
} else {
memcpy (GST_BUFFER_DATA (outbuf) + lumsize, data + lumsize, chromsize * 2);
memcpy (odata + lumsize, idata + lumsize, chromsize * 2);
}
GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
gst_buffer_unref (buf);
gst_pad_push (smooth->srcpad, GST_DATA (outbuf));
return GST_FLOW_OK;
}
static void
@ -287,19 +233,20 @@ gst_smooth_set_property (GObject * object, guint prop_id, const GValue * value,
smooth = GST_SMOOTH (object);
switch (prop_id) {
case ARG_ACTIVE:
case PROP_ACTIVE:
smooth->active = g_value_get_boolean (value);
break;
case ARG_TOLERANCE:
case PROP_TOLERANCE:
smooth->tolerance = g_value_get_int (value);
break;
case ARG_FILTERSIZE:
case PROP_FILTER_SIZE:
smooth->filtersize = g_value_get_int (value);
break;
case ARG_LUM_ONLY:
smooth->lum_only = g_value_get_boolean (value);
case PROP_LUMA_ONLY:
smooth->luma_only = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
@ -314,17 +261,17 @@ gst_smooth_get_property (GObject * object, guint prop_id, GValue * value,
smooth = GST_SMOOTH (object);
switch (prop_id) {
case ARG_ACTIVE:
case PROP_ACTIVE:
g_value_set_boolean (value, smooth->active);
break;
case ARG_TOLERANCE:
case PROP_TOLERANCE:
g_value_set_int (value, smooth->tolerance);
break;
case ARG_FILTERSIZE:
case PROP_FILTER_SIZE:
g_value_set_int (value, smooth->filtersize);
break;
case ARG_LUM_ONLY:
g_value_set_boolean (value, smooth->lum_only);
case PROP_LUMA_ONLY:
g_value_set_boolean (value, smooth->luma_only);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);

View file

@ -23,6 +23,8 @@
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/video/gstvideofilter.h>
#ifdef __cplusplus
extern "C" {
@ -44,7 +46,7 @@ typedef struct _GstSmooth GstSmooth;
typedef struct _GstSmoothClass GstSmoothClass;
struct _GstSmooth {
GstElement element;
GstVideoFilter element;
int format;
int width;
@ -53,13 +55,13 @@ struct _GstSmooth {
gboolean active;
int tolerance;
int filtersize;
gboolean lum_only;
gboolean luma_only;
GstPad *sinkpad,*srcpad;
};
struct _GstSmoothClass {
GstElementClass parent_class;
GstVideoFilterClass parent_class;
};
GType gst_smooth_get_type(void);

View file

@ -1,19 +0,0 @@
plugin_LTLIBRARIES = libgstsmoothwave.la
libgstsmoothwave_la_SOURCES = gstsmoothwave.c
libgstsmoothwave_la_CFLAGS = $(GST_CFLAGS)
libgstsmoothwave_la_LIBADD =
libgstsmoothwave_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstsmoothwave_la_LIBTOOLFLAGS = --tag=disable-static
noinst_HEADERS = gstsmoothwave.h
if HAVE_GTK
noinst_PROGRAMS = demo-osssrc
demo_osssrc_SOURCES = demo-osssrc.c
demo_osssrc_CFLAGS = $(GST_CFLAGS) $(GTK_CFLAGS)
demo_osssrc_LDFLAGS = $(GST_LIBS) $(GTK_LIBS)
endif
EXTRA_DIST = README

View file

@ -1,6 +0,0 @@
This is a home-grown visualization, with a couple lines of code copied
from synaesthesia. It draws the waveform in the bitmap, then fades out
the entire bitmap so older waveforms disappear. It looks OK, but it's
grayscale so far (haven't solved the cmap problems, note all the commented
out code). I'm going to try to make a much better version as time goes
on.

View file

@ -1,440 +0,0 @@
/* GStreamer
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gst/audio/audio.h>
#include "gstsmoothwave.h"
/* SmoothWave signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
static void gst_smoothwave_base_init (gpointer g_class);
static void gst_smoothwave_class_init (GstSmoothWaveClass * klass);
static void gst_smoothwave_init (GstSmoothWave * smoothwave);
static void gst_smoothwave_dispose (GObject * object);
static GstStateChangeReturn gst_sw_change_state (GstElement * element,
GstStateChange transition);
static void gst_smoothwave_chain (GstPad * pad, GstData * _data);
static GstPadLinkReturn gst_sw_sinklink (GstPad * pad, const GstCaps * caps);
static GstPadLinkReturn gst_sw_srclink (GstPad * pad, const GstCaps * caps);
static GstElementClass *parent_class = NULL;
/*static guint gst_smoothwave_signals[LAST_SIGNAL] = { 0 }; */
#if G_BYTE_ORDER == G_BIG_ENDIAN
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-rgb, "
"bpp = (int) 32, "
"depth = (int) 24, "
"endianness = (int) BIG_ENDIAN, "
"red_mask = (int) " GST_VIDEO_BYTE2_MASK_32 ", "
"green_mask = (int) " GST_VIDEO_BYTE3_MASK_32 ", "
"blue_mask = (int) " GST_VIDEO_BYTE4_MASK_32 ", "
"width = (int)512, "
"height = (int)256, " "framerate = " GST_VIDEO_FPS_RANGE)
);
#else
static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("video/x-raw-rgb, "
"bpp = (int) 32, "
"depth = (int) 24, "
"endianness = (int) BIG_ENDIAN, "
"red_mask = (int) " GST_VIDEO_BYTE3_MASK_32 ", "
"green_mask = (int) " GST_VIDEO_BYTE2_MASK_32 ", "
"blue_mask = (int) " GST_VIDEO_BYTE1_MASK_32 ", "
"width = (int)512, "
"height = (int)256, " "framerate = " GST_VIDEO_FPS_RANGE)
);
#endif
static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS ("audio/x-raw-int, "
"rate = (int) [ 1, MAX ], "
"channels = (int) [ 1, 2 ], "
"endianness = (int) BYTE_ORDER, "
"width = (int) 16, " "depth = (int) 16, " "signed = (boolean) true")
);
GType
gst_smoothwave_get_type (void)
{
static GType smoothwave_type = 0;
if (!smoothwave_type) {
static const GTypeInfo smoothwave_info = {
sizeof (GstSmoothWaveClass),
gst_smoothwave_base_init,
NULL,
(GClassInitFunc) gst_smoothwave_class_init,
NULL,
NULL,
sizeof (GstSmoothWave),
0,
(GInstanceInitFunc) gst_smoothwave_init,
};
smoothwave_type =
g_type_register_static (GST_TYPE_ELEMENT, "GstSmoothWave",
&smoothwave_info, 0);
}
return smoothwave_type;
}
static void
gst_smoothwave_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details_simple (element_class, "Smooth waveform",
"Visualization",
"Fading grayscale waveform display",
"Erik Walthinsen <omega@cse.ogi.edu>");
}
static void
gst_smoothwave_class_init (GstSmoothWaveClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
element_class = (GstElementClass *) klass;
parent_class = g_type_class_peek_parent (klass);
gobject_class->dispose = gst_smoothwave_dispose;
element_class->change_state = gst_sw_change_state;
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&src_template));
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&sink_template));
}
static void
gst_smoothwave_init (GstSmoothWave * smoothwave)
{
int i;
smoothwave->sinkpad =
gst_pad_new_from_static_template (&sink_template, "sink");
smoothwave->srcpad = gst_pad_new_from_static_template (&src_template, "src");
gst_element_add_pad (GST_ELEMENT (smoothwave), smoothwave->sinkpad);
gst_pad_set_chain_function (smoothwave->sinkpad, gst_smoothwave_chain);
gst_pad_set_link_function (smoothwave->sinkpad, gst_sw_sinklink);
gst_element_add_pad (GST_ELEMENT (smoothwave), smoothwave->srcpad);
gst_pad_set_link_function (smoothwave->srcpad, gst_sw_srclink);
GST_OBJECT_FLAG_SET (smoothwave, GST_ELEMENT_EVENT_AWARE);
smoothwave->adapter = gst_adapter_new ();
smoothwave->width = 512;
smoothwave->height = 256;
#define SPLIT_PT 96
/* Fade in blue up to the split point */
for (i = 0; i < SPLIT_PT; i++)
smoothwave->palette[i] = (255 * i / SPLIT_PT);
/* After the split point, fade out blue and fade in red */
for (; i < 256; i++) {
gint val = (i - SPLIT_PT) * 255 / (255 - SPLIT_PT);
smoothwave->palette[i] = (255 - val) | (val << 16);
}
smoothwave->imagebuffer = g_malloc (smoothwave->width * smoothwave->height);
memset (smoothwave->imagebuffer, 0, smoothwave->width * smoothwave->height);
smoothwave->fps = 0;
smoothwave->sample_rate = 0;
smoothwave->audio_basetime = GST_CLOCK_TIME_NONE;
smoothwave->samples_consumed = 0;
}
inline guchar *
draw_line (guchar * cur_pos, gint diff_y, gint stride)
{
gint j;
if (diff_y > 0) {
for (j = diff_y; j > 0; j--) {
cur_pos += stride;
*cur_pos = 0xff;
}
} else if (diff_y < 0) {
for (j = diff_y; j < 0; j++) {
cur_pos -= stride;
*cur_pos = 0xff;
}
} else {
*cur_pos = 0xff;
}
return cur_pos;
}
static void
gst_smoothwave_dispose (GObject * object)
{
GstSmoothWave *sw = GST_SMOOTHWAVE (object);
if (sw->adapter != NULL) {
g_object_unref (sw->adapter);
sw->adapter = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static GstPadLinkReturn
gst_sw_sinklink (GstPad * pad, const GstCaps * caps)
{
GstSmoothWave *sw = GST_SMOOTHWAVE (GST_OBJECT_PARENT (pad));
GstStructure *structure;
g_return_val_if_fail (sw != NULL, GST_PAD_LINK_REFUSED);
structure = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_int (structure, "channels", &sw->channels) ||
!gst_structure_get_int (structure, "rate", &sw->sample_rate))
return GST_PAD_LINK_REFUSED;
return GST_PAD_LINK_OK;
}
static GstPadLinkReturn
gst_sw_srclink (GstPad * pad, const GstCaps * caps)
{
GstSmoothWave *sw = GST_SMOOTHWAVE (GST_OBJECT_PARENT (pad));
GstStructure *structure;
g_return_val_if_fail (sw != NULL, GST_PAD_LINK_REFUSED);
structure = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_int (structure, "width", &sw->width) ||
!gst_structure_get_int (structure, "height", &sw->height) ||
!gst_structure_get_double (structure, "framerate", &sw->fps))
return GST_PAD_LINK_REFUSED;
return GST_PAD_LINK_OK;
}
static void
gst_smoothwave_chain (GstPad * pad, GstData * _data)
{
GstBuffer *buf = GST_BUFFER (_data);
GstSmoothWave *smoothwave;
guint32 bytesperread;
gint samples_per_frame;
g_return_if_fail (pad != NULL);
g_return_if_fail (GST_IS_PAD (pad));
g_return_if_fail (buf != NULL);
smoothwave = GST_SMOOTHWAVE (GST_OBJECT_PARENT (pad));
if (GST_IS_EVENT (_data)) {
GstEvent *event = GST_EVENT (_data);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_DISCONTINUOUS:
{
gint64 value = 0;
gst_event_discont_get_value (event, GST_FORMAT_TIME, &value);
gst_adapter_clear (smoothwave->adapter);
smoothwave->audio_basetime = value;
smoothwave->samples_consumed = 0;
}
default:
gst_pad_event_default (pad, event);
break;
}
return;
}
if (!GST_PAD_IS_USABLE (smoothwave->srcpad)) {
gst_buffer_unref (buf);
return;
}
if (smoothwave->audio_basetime == GST_CLOCK_TIME_NONE)
smoothwave->audio_basetime = GST_BUFFER_TIMESTAMP (buf);
if (smoothwave->audio_basetime == GST_CLOCK_TIME_NONE)
smoothwave->audio_basetime = 0;
bytesperread = smoothwave->width * smoothwave->channels * sizeof (gint16);
samples_per_frame = smoothwave->sample_rate / smoothwave->fps;
gst_adapter_push (smoothwave->adapter, buf);
while (gst_adapter_available (smoothwave->adapter) > MAX (bytesperread,
samples_per_frame * smoothwave->channels * sizeof (gint16))) {
guint32 *ptr;
gint i;
gint qheight;
const gint16 *samples =
(const guint16 *) gst_adapter_peek (smoothwave->adapter, bytesperread);
gint stride = smoothwave->width;
/* First draw the new waveform */
if (smoothwave->channels == 2) {
guchar *cur_pos[2];
gint prev_y[2];
qheight = smoothwave->height / 4;
prev_y[0] = (gint32) (*samples) * qheight / 32768;
samples++;
prev_y[1] = (gint32) (*samples) * qheight / 32768;
samples++;
cur_pos[0] = smoothwave->imagebuffer + ((prev_y[0] + qheight) * stride);
cur_pos[1] =
smoothwave->imagebuffer + ((prev_y[1] +
(3 * smoothwave->height / 4)) * stride);
*(cur_pos[0]) = 0xff;
*(cur_pos[1]) = 0xff;
for (i = 1; i < smoothwave->width; i++) {
gint diff_y = (gint) (*samples) * qheight / 32768 - prev_y[0];
samples++;
cur_pos[0] = draw_line (cur_pos[0], diff_y, stride);
cur_pos[0]++;
prev_y[0] += diff_y;
diff_y = (gint) (*samples) * qheight / 32768 - prev_y[1];
samples++;
cur_pos[1] = draw_line (cur_pos[1], diff_y, stride);
cur_pos[1]++;
prev_y[1] += diff_y;
}
} else {
qheight = smoothwave->height / 2;
guchar *cur_pos;
gint prev_y;
prev_y = (gint32) (*samples) * qheight / 32768;
samples++;
cur_pos = smoothwave->imagebuffer + ((prev_y + qheight) * stride);
*cur_pos = 0xff;
for (i = 1; i < smoothwave->width; i++) {
gint diff_y = (gint) (*samples) * qheight / 32768 - prev_y;
samples++;
cur_pos = draw_line (cur_pos, diff_y, stride);
cur_pos++;
prev_y += diff_y;
}
}
/* Now fade stuff out */
ptr = (guint32 *) smoothwave->imagebuffer;
for (i = 0; i < (smoothwave->width * smoothwave->height) / 4; i++) {
if (*ptr)
*ptr -= ((*ptr & 0xf0f0f0f0ul) >> 4) + ((*ptr & 0xe0e0e0e0ul) >> 5);
ptr++;
}
{
guint32 *out;
guchar *in;
GstBuffer *bufout;
bufout =
gst_buffer_new_and_alloc (smoothwave->width * smoothwave->height * 4);
GST_BUFFER_TIMESTAMP (bufout) =
smoothwave->audio_basetime +
(GST_SECOND * smoothwave->samples_consumed / smoothwave->sample_rate);
GST_BUFFER_DURATION (bufout) = GST_SECOND / smoothwave->fps;
out = (guint32 *) GST_BUFFER_DATA (bufout);
in = smoothwave->imagebuffer;
for (i = 0; i < (smoothwave->width * smoothwave->height); i++) {
*out++ = smoothwave->palette[*in++]; // t | (t << 8) | (t << 16) | (t << 24);
}
gst_pad_push (smoothwave->srcpad, GST_DATA (bufout));
}
smoothwave->samples_consumed += samples_per_frame;
gst_adapter_flush (smoothwave->adapter,
samples_per_frame * smoothwave->channels * sizeof (gint16));
}
}
static GstStateChangeReturn
gst_sw_change_state (GstElement * element, GstStateChange transition)
{
GstSmoothWave *sw = GST_SMOOTHWAVE (element);
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
break;
case GST_STATE_CHANGE_READY_TO_NULL:
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
sw->audio_basetime = GST_CLOCK_TIME_NONE;
gst_adapter_clear (sw->adapter);
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
sw->channels = 0;
break;
default:
break;
}
return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
}
static gboolean
plugin_init (GstPlugin * plugin)
{
if (!gst_library_load ("gstbytestream"))
return FALSE;
if (!gst_element_register (plugin, "smoothwave", GST_RANK_NONE,
GST_TYPE_SMOOTHWAVE))
return FALSE;
return TRUE;
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"smoothwave",
"Fading greyscale waveform display",
plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)

View file

@ -1,78 +0,0 @@
/* GStreamer
* 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_SMOOTHWAVE_H__
#define __GST_SMOOTHWAVE_H__
#include <gst/gst.h>
#include <gst/bytestream/adapter.h>
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#define GST_TYPE_SMOOTHWAVE \
(gst_smoothwave_get_type())
#define GST_SMOOTHWAVE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SMOOTHWAVE,GstSmoothWave))
#define GST_SMOOTHWAVE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SMOOTHWAVE,GstSmoothWaveClass))
#define GST_IS_SMOOTHWAVE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SMOOTHWAVE))
#define GST_IS_SMOOTHWAVE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SMOOTHWAVE))
typedef struct _GstSmoothWave GstSmoothWave;
typedef struct _GstSmoothWaveClass GstSmoothWaveClass;
struct _GstSmoothWave
{
GstElement element;
GstPad *sinkpad, *srcpad;
GstAdapter *adapter;
guchar *imagebuffer;
GstClockTime audio_basetime;
guint64 samples_consumed;
gint sample_rate;
gint width, height;
gdouble fps;
gint channels;
guint32 palette[256];
};
struct _GstSmoothWaveClass
{
GstElementClass parent_class;
};
GType gst_smoothwave_get_type (void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GST_SMOOTHWAVE_H__ */

View file

@ -21,7 +21,7 @@
/**
* SECTION:element-speed
*
* Plays an audio stream at a different speed.
* Plays an audio stream at a different speed (by resampling the audio).
*
* Do not use this element. Either use the 'pitch' element, or do a seek with
* a non-1.0 rate parameter, this will have the same effect as using the speed

View file

@ -539,6 +539,10 @@ gst_h264_parse_collect_nal (GstH264Parse * h264parse, const guint8 * data,
GstH264NalUnitType nal_type = nalu->type;
GstH264NalUnit nnalu;
if (h264parse->align == GST_H264_PARSE_ALIGN_NAL) {
return TRUE;
}
GST_DEBUG_OBJECT (h264parse, "parsing collected nal");
parse_res = gst_h264_parser_identify_nalu (h264parse->nalparser, data,
nalu->offset + nalu->size, size, &nnalu);
@ -546,10 +550,6 @@ gst_h264_parse_collect_nal (GstH264Parse * h264parse, const guint8 * data,
if (parse_res == GST_H264_PARSER_ERROR)
return FALSE;
if (h264parse->align == GST_H264_PARSE_ALIGN_NAL) {
return TRUE;
}
/* determine if AU complete */
GST_LOG_OBJECT (h264parse, "nal type: %d", nal_type);
/* coded slice NAL starts a picture,
@ -633,6 +633,16 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse,
nalu.offset + nalu.size);
if (!h264parse->nalu.size && !h264parse->nalu.valid)
h264parse->nalu = nalu;
/* need 2 bytes of next nal */
if (nalu.offset + nalu.size + 4 + 2 > size) {
if (GST_BASE_PARSE_DRAINING (parse)) {
drain = TRUE;
} else {
GST_DEBUG_OBJECT (h264parse, "need more bytes of next nal");
current_off = nalu.sc_offset;
goto more;
}
}
break;
case GST_H264_PARSER_BROKEN_LINK:
return FALSE;
@ -653,7 +663,7 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse,
*skipsize = nalu.offset;
GST_DEBUG_OBJECT (h264parse, "skipping broken nal");
return FALSE;
goto invalid;
} else {
nalu.size = 0;
goto end;
@ -675,7 +685,7 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse,
/* Can't parse the nalu */
if (size - h264parse->nalu.offset < 2) {
*skipsize = nalu.offset;
return FALSE;
goto invalid;
}
/* We parse it anyway */
@ -691,17 +701,14 @@ gst_h264_parse_check_valid_frame (GstBaseParse * parse,
data, nalu.offset, nalu.size);
gst_h264_parse_process_nal (h264parse, &nalu);
if (gst_h264_parse_collect_nal (h264parse, data, size, &nalu) || drain)
/* if no next nal, we know it's complete here */
if (drain || gst_h264_parse_collect_nal (h264parse, data, size, &nalu))
break;
}
end:
/* FIXME this shouldnt be needed */
if (h264parse->nalu.sc_offset > 0 && data[h264parse->nalu.sc_offset - 1] == 0)
h264parse->nalu.sc_offset--;
*skipsize = h264parse->nalu.sc_offset;
*framesize = nalu.offset + nalu.size - h264parse->nalu.sc_offset; /* CHECKME */
*framesize = nalu.offset + nalu.size - h264parse->nalu.sc_offset;
h264parse->current_off = current_off;
return TRUE;
@ -715,6 +722,10 @@ more:
if (!h264parse->nalu.size) {
/* skip up to initial startcode */
*skipsize = h264parse->nalu.sc_offset;
/* but mind some stuff will have been skipped */
g_assert (current_off >= *skipsize);
current_off -= *skipsize;
h264parse->nalu.sc_offset = 0;
} else {
*skipsize = 0;
}
@ -723,6 +734,10 @@ more:
h264parse->current_off = current_off;
return FALSE;
invalid:
gst_h264_parse_reset_frame (h264parse);
return FALSE;
}
/* byte together avc codec data based on collected pps and sps so far */
@ -1354,16 +1369,17 @@ gst_h264_parse_get_caps (GstBaseParse * parse)
GstStructure *s = gst_caps_get_structure (peercaps, i);
gst_structure_remove_field (s, "alignment");
gst_structure_remove_field (s, "stream-format");
gst_structure_remove_field (s, "parsed");
}
res =
gst_caps_intersect_full (peercaps,
gst_pad_get_pad_template_caps (GST_BASE_PARSE_SRC_PAD (parse)),
gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD (parse)),
GST_CAPS_INTERSECT_FIRST);
gst_caps_unref (peercaps);
} else {
res =
gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SRC_PAD
gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_PARSE_SINK_PAD
(parse)));
}

View file

@ -135,6 +135,12 @@ else
check_zbar =
endif
if USE_OPUS
check_opus = elements/opus
else
check_opus =
endif
VALGRIND_TO_FIX = \
elements/mpeg2enc \
elements/mplex \
@ -161,6 +167,7 @@ check_PROGRAMS = \
$(check_ofa) \
$(check_timidity) \
$(check_kate) \
$(check_opus) \
elements/autoconvert \
elements/autovideoconvert \
elements/asfmux \

383
tests/check/elements/opus.c Normal file
View file

@ -0,0 +1,383 @@
/* GStreamer
*
* unit test for opus
*
* Copyright (C) <2011> Vincent Penquerc'h <vincent.penquerch@collbaora.co.uk>
*
* 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 <unistd.h>
#include <gst/check/gstcheck.h>
static const guint8 opus_ogg_id_header[19] = {
0x4f, 0x70, 0x75, 0x73, 0x48, 0x65, 0x61, 0x64, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static const guint8 opus_ogg_comments_header[] = {
0x4f, 0x70, 0x75, 0x73, 0x54, 0x61, 0x67, 0x73, 0x1e, 0x00, 0x00, 0x00, 0x45,
0x6e, 0x63, 0x6f, 0x64, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x47,
0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x72, 0x20, 0x4f, 0x70, 0x75, 0x73,
0x65, 0x6e, 0x63, 0x00, 0x00, 0x00, 0x00
};
/* A lot of these taken from the vorbisdec test */
/* For ease of programming we use globals to keep refs for our floating
* src and sink pads we create; otherwise we always have to do get_pad,
* get_peer, and then remove references in every test function */
static GstPad *mydecsrcpad, *mydecsinkpad;
static GstPad *myencsrcpad, *myencsinkpad;
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS_ANY);
static GstElement *
setup_opusdec (void)
{
GstElement *opusdec;
GST_DEBUG ("setup_opusdec");
opusdec = gst_check_setup_element ("opusdec");
mydecsrcpad = gst_check_setup_src_pad (opusdec, &srctemplate, NULL);
mydecsinkpad = gst_check_setup_sink_pad (opusdec, &sinktemplate, NULL);
gst_pad_set_active (mydecsrcpad, TRUE);
gst_pad_set_active (mydecsinkpad, TRUE);
return opusdec;
}
static void
cleanup_opusdec (GstElement * opusdec)
{
GST_DEBUG ("cleanup_opusdec");
gst_element_set_state (opusdec, GST_STATE_NULL);
gst_pad_set_active (mydecsrcpad, FALSE);
gst_pad_set_active (mydecsinkpad, FALSE);
gst_check_teardown_src_pad (opusdec);
gst_check_teardown_sink_pad (opusdec);
gst_check_teardown_element (opusdec);
}
static GstElement *
setup_opusenc (void)
{
GstElement *opusenc;
GST_DEBUG ("setup_opusenc");
opusenc = gst_check_setup_element ("opusenc");
myencsrcpad = gst_check_setup_src_pad (opusenc, &srctemplate, NULL);
myencsinkpad = gst_check_setup_sink_pad (opusenc, &sinktemplate, NULL);
gst_pad_set_active (myencsrcpad, TRUE);
gst_pad_set_active (myencsinkpad, TRUE);
return opusenc;
}
static void
cleanup_opusenc (GstElement * opusenc)
{
GST_DEBUG ("cleanup_opusenc");
gst_element_set_state (opusenc, GST_STATE_NULL);
gst_pad_set_active (myencsrcpad, FALSE);
gst_pad_set_active (myencsinkpad, FALSE);
gst_check_teardown_src_pad (opusenc);
gst_check_teardown_sink_pad (opusenc);
gst_check_teardown_element (opusenc);
}
static void
check_buffers (guint expected, gboolean headers_in_caps)
{
GstBuffer *outbuffer;
guint i, num_buffers;
/* check buffers are the type we expect */
num_buffers = g_list_length (buffers);
fail_unless (num_buffers >= expected);
for (i = 0; i < num_buffers; ++i) {
outbuffer = GST_BUFFER (buffers->data);
fail_if (outbuffer == NULL);
fail_if (GST_BUFFER_SIZE (outbuffer) == 0);
buffers = g_list_remove (buffers, outbuffer);
ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
gst_buffer_unref (outbuffer);
outbuffer = NULL;
}
}
GST_START_TEST (test_opus_id_header)
{
GstElement *opusdec;
GstBuffer *inbuffer;
opusdec = setup_opusdec ();
fail_unless (gst_element_set_state (opusdec,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (sizeof (opus_ogg_id_header));
memcpy (GST_BUFFER_DATA (inbuffer), opus_ogg_id_header,
sizeof (opus_ogg_id_header));
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
gst_buffer_ref (inbuffer);
/* pushing gives away my reference ... */
fail_unless (gst_pad_push (mydecsrcpad, inbuffer) == GST_FLOW_OK);
/* ... and nothing ends up on the global buffer list */
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
gst_buffer_unref (inbuffer);
fail_unless (g_list_length (buffers) == 0);
/* cleanup */
cleanup_opusdec (opusdec);
}
GST_END_TEST;
GST_START_TEST (test_opus_encode_nothing)
{
GstElement *opusenc;
opusenc = setup_opusenc ();
fail_unless (gst_element_set_state (opusenc,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
fail_unless (gst_pad_push_event (myencsrcpad, gst_event_new_eos ()) == TRUE);
fail_unless (gst_element_set_state (opusenc,
GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS,
"could not set to ready");
/* cleanup */
cleanup_opusenc (opusenc);
}
GST_END_TEST;
GST_START_TEST (test_opus_decode_nothing)
{
GstElement *opusdec;
opusdec = setup_opusdec ();
fail_unless (gst_element_set_state (opusdec,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
fail_unless (gst_pad_push_event (mydecsrcpad, gst_event_new_eos ()) == TRUE);
fail_unless (gst_element_set_state (opusdec,
GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS,
"could not set to ready");
/* cleanup */
cleanup_opusdec (opusdec);
}
GST_END_TEST;
GST_START_TEST (test_opus_encode_samples)
{
const unsigned int nsamples = 4096;
GstElement *opusenc;
GstBuffer *inbuffer;
GstCaps *caps;
guint16 *samples;
unsigned int n;
opusenc = setup_opusenc ();
fail_unless (gst_element_set_state (opusenc,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
inbuffer = gst_buffer_new_and_alloc (nsamples * 2);
samples = (guint16 *) GST_BUFFER_DATA (inbuffer);
for (n = 0; n < nsamples; ++n) {
samples[n] = 0;
}
GST_BUFFER_TIMESTAMP (inbuffer) = GST_BUFFER_OFFSET (inbuffer) = 0;
GST_BUFFER_DURATION (inbuffer) = GST_CLOCK_TIME_NONE;
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
caps =
gst_caps_from_string
("audio/x-raw-int,rate=48000,channels=1,signed=true,width=16,depth=16,endianness=1234");
fail_unless (caps != NULL);
gst_buffer_set_caps (inbuffer, caps);
gst_caps_unref (caps);
gst_buffer_ref (inbuffer);
/* pushing gives away my reference ... */
fail_unless (gst_pad_push (myencsrcpad, inbuffer) == GST_FLOW_OK);
/* ... and nothing ends up on the global buffer list */
fail_unless (gst_pad_push_event (myencsrcpad, gst_event_new_eos ()) == TRUE);
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
gst_buffer_unref (inbuffer);
fail_unless (gst_element_set_state (opusenc,
GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS,
"could not set to ready");
/* default frame size is 20 ms, at 48000 Hz that's 960 samples */
check_buffers ((nsamples + 959) / 960, FALSE);
/* cleanup */
cleanup_opusenc (opusenc);
g_list_free (buffers);
}
GST_END_TEST;
GST_START_TEST (test_opus_encode_properties)
{
const unsigned int nsamples = 4096;
enum
{ steps = 20 };
GstElement *opusenc;
GstBuffer *inbuffer;
GstCaps *caps;
guint16 *samples;
unsigned int n, step;
static const struct
{
const char *param;
int value;
} param_changes[steps] = {
{
"frame-size", 40}, {
"inband-fec", 1}, {
"complexity", 5}, {
"bandwidth", 1104}, {
"frame-size", 2}, {
"max-payload-size", 80}, {
"frame-size", 60}, {
"max-payload-size", 900}, {
"complexity", 1}, {
"bitrate", 30000}, {
"frame-size", 10}, {
"bitrate", 300000}, {
"inband-fec", 0}, {
"frame-size", 5}, {
"bandwidth", 1101}, {
"frame-size", 10}, {
"bitrate", 500000}, {
"frame-size", 5}, {
"bitrate", 80000}, {
"complexity", 8},};
opusenc = setup_opusenc ();
fail_unless (gst_element_set_state (opusenc,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
caps =
gst_caps_from_string
("audio/x-raw-int,rate=48000,channels=1,signed=true,width=16,depth=16,endianness=1234");
fail_unless (caps != NULL);
for (step = 0; step < steps; ++step) {
inbuffer = gst_buffer_new_and_alloc (nsamples * 2);
samples = (guint16 *) GST_BUFFER_DATA (inbuffer);
for (n = 0; n < nsamples; ++n) {
samples[n] = 0;
}
GST_BUFFER_TIMESTAMP (inbuffer) = GST_BUFFER_OFFSET (inbuffer) = 0;
GST_BUFFER_DURATION (inbuffer) = GST_CLOCK_TIME_NONE;
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
gst_buffer_set_caps (inbuffer, caps);
gst_buffer_ref (inbuffer);
/* pushing gives away my reference ... */
fail_unless (gst_pad_push (myencsrcpad, inbuffer) == GST_FLOW_OK);
/* ... and nothing ends up on the global buffer list */
fail_unless (gst_pad_push_event (myencsrcpad,
gst_event_new_eos ()) == TRUE);
ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
gst_buffer_unref (inbuffer);
/* change random parameters */
g_object_set (opusenc, param_changes[step].param, param_changes[step].value,
NULL);
}
gst_caps_unref (caps);
fail_unless (gst_element_set_state (opusenc,
GST_STATE_READY) == GST_STATE_CHANGE_SUCCESS,
"could not set to ready");
/* cleanup */
cleanup_opusenc (opusenc);
g_list_free (buffers);
}
GST_END_TEST;
static Suite *
opus_suite (void)
{
Suite *s = suite_create ("opus");
TCase *tc_chain = tcase_create ("general");
suite_add_tcase (s, tc_chain);
#define X if (0)
tcase_add_test (tc_chain, test_opus_id_header);
tcase_add_test (tc_chain, test_opus_encode_nothing);
tcase_add_test (tc_chain, test_opus_decode_nothing);
tcase_add_test (tc_chain, test_opus_encode_samples);
tcase_add_test (tc_chain, test_opus_encode_properties);
#undef X
return s;
}
int
main (int argc, char **argv)
{
int nf;
Suite *s = opus_suite ();
SRunner *sr = srunner_create (s);
gst_check_init (&argc, &argv);
srunner_run_all (sr, CK_NORMAL);
nf = srunner_ntests_failed (sr);
srunner_free (sr);
return nf;
}