mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
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:
commit
0a9387c43c
79 changed files with 3063 additions and 4367 deletions
|
@ -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
|
||||
|
|
|
@ -52,8 +52,6 @@ struct _GstCeltDec {
|
|||
gint frame_size;
|
||||
guint64 packetno;
|
||||
|
||||
gboolean discont;
|
||||
|
||||
GstBuffer *streamheader;
|
||||
GstBuffer *vorbiscomment;
|
||||
GList *extra_headers;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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 <= 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 <= 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);
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -53,6 +53,7 @@ struct _GstOpusDec {
|
|||
|
||||
int sample_rate;
|
||||
int n_channels;
|
||||
guint32 pre_skip;
|
||||
};
|
||||
|
||||
struct _GstOpusDecClass {
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
@ -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
170
ext/opus/gstopusheader.c
Normal 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));
|
||||
}
|
|
@ -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__ */
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -42,6 +42,10 @@ typedef struct _GstOpusParseClass GstOpusParseClass;
|
|||
|
||||
struct _GstOpusParse {
|
||||
GstBaseParse element;
|
||||
|
||||
gboolean header_sent;
|
||||
GSList *headers;
|
||||
GstClockTime next_ts;
|
||||
};
|
||||
|
||||
struct _GstOpusParseClass {
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
|
37
gst/audiovisualizers/gstdrawhelpers.h
Normal file
37
gst/audiovisualizers/gstdrawhelpers.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;"../../gst-libs";../../../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;"../../gst-libs";../../../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>
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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__ */
|
348
gst/filter/iir.c
348
gst/filter/iir.c
|
@ -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
|
|
@ -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
28
gst/freeverb/Makefile.am
Normal 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
972
gst/freeverb/gstfreeverb.c
Normal 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)
|
71
gst/freeverb/gstfreeverb.h
Normal file
71
gst/freeverb/gstfreeverb.h
Normal 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__ */
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
7
gst/passthrough/.gitignore
vendored
7
gst/passthrough/.gitignore
vendored
|
@ -1,7 +0,0 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
.deps
|
||||
.libs
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
|
@ -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__ */
|
|
@ -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;"../../gst-libs";../../../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;"../../gst-libs";../../../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>
|
1
gst/playondemand/.gitignore
vendored
1
gst/playondemand/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
demo_mp3
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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)
|
|
@ -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__ */
|
|
@ -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' \
|
||||
> $@
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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.
|
|
@ -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)
|
|
@ -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__ */
|
|
@ -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
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
||||
|
|
|
@ -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
383
tests/check/elements/opus.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue