gstreamer/gst/volume/gstvolume.c

973 lines
28 KiB
C
Raw Normal View History

/* -*- c-basic-offset: 2 -*-
* vi:si:et:sw=2:sts=8:ts=8:expandtab
*
* GStreamer
* Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
* Copyright (C) 2005 Andy Wingo <wingo@pobox.com>
* Copyright (C) 2010 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
* 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.
*/
/**
* SECTION:element-volume
*
* The volume element changes the volume of the audio data.
Cleanup Plugin docs. Link to signals and properties. Fix sub-section titles. Drop mentining that all our example pipe... Original commit message from CVS: * docs/plugins/gst-plugins-base-plugins-docs.sgml: * docs/plugins/gst-plugins-base-plugins-overrides.txt: * docs/plugins/gst-plugins-base-plugins-sections.txt: * docs/plugins/gst-plugins-base-plugins.args: * docs/plugins/gst-plugins-base-plugins.hierarchy: * docs/plugins/gst-plugins-base-plugins.interfaces: * docs/plugins/gst-plugins-base-plugins.prerequisites: * docs/plugins/gst-plugins-base-plugins.signals: * docs/plugins/inspect/plugin-adder.xml: * docs/plugins/inspect/plugin-alsa.xml: * docs/plugins/inspect/plugin-audioconvert.xml: * docs/plugins/inspect/plugin-audiorate.xml: * docs/plugins/inspect/plugin-audioresample.xml: * docs/plugins/inspect/plugin-audiotestsrc.xml: * docs/plugins/inspect/plugin-cdparanoia.xml: * docs/plugins/inspect/plugin-decodebin.xml: * docs/plugins/inspect/plugin-ffmpegcolorspace.xml: * docs/plugins/inspect/plugin-gdp.xml: * docs/plugins/inspect/plugin-gnomevfs.xml: * docs/plugins/inspect/plugin-libvisual.xml: * docs/plugins/inspect/plugin-ogg.xml: * docs/plugins/inspect/plugin-pango.xml: * docs/plugins/inspect/plugin-playback.xml: * docs/plugins/inspect/plugin-queue2.xml: * docs/plugins/inspect/plugin-subparse.xml: * docs/plugins/inspect/plugin-tcp.xml: * docs/plugins/inspect/plugin-theora.xml: * docs/plugins/inspect/plugin-typefindfunctions.xml: * docs/plugins/inspect/plugin-uridecodebin.xml: * docs/plugins/inspect/plugin-video4linux.xml: * docs/plugins/inspect/plugin-videorate.xml: * docs/plugins/inspect/plugin-videoscale.xml: * docs/plugins/inspect/plugin-videotestsrc.xml: * docs/plugins/inspect/plugin-volume.xml: * docs/plugins/inspect/plugin-vorbis.xml: * docs/plugins/inspect/plugin-ximagesink.xml: * docs/plugins/inspect/plugin-xvimagesink.xml: * ext/alsa/gstalsamixer.c: * ext/alsa/gstalsasink.c: * ext/alsa/gstalsasrc.c: * ext/gio/gstgiosink.c: * ext/gio/gstgiosrc.c: * ext/gio/gstgiostreamsink.c: * ext/gio/gstgiostreamsrc.c: * ext/gnomevfs/gstgnomevfssink.c: * ext/gnomevfs/gstgnomevfssrc.c: * ext/ogg/gstoggdemux.c: * ext/ogg/gstoggmux.c: * ext/pango/gstclockoverlay.c: * ext/pango/gsttextoverlay.c: * ext/pango/gsttextrender.c: * ext/pango/gsttimeoverlay.c: * ext/theora/theoradec.c: * ext/theora/theoraenc.c: * ext/theora/theoraparse.c: * ext/vorbis/vorbisdec.c: * ext/vorbis/vorbisenc.c: * ext/vorbis/vorbisparse.c: * ext/vorbis/vorbistag.c: * gst/adder/gstadder.c: * gst/audioconvert/gstaudioconvert.c: * gst/audioresample/gstaudioresample.c: * gst/audiotestsrc/gstaudiotestsrc.c: * gst/ffmpegcolorspace/gstffmpegcolorspace.c: * gst/gdp/gstgdpdepay.c: * gst/gdp/gstgdppay.c: * gst/playback/gstdecodebin2.c: * gst/playback/gstplaybin.c: * gst/playback/gstplaybin2.c: * gst/playback/gstqueue2.c: * gst/playback/gsturidecodebin.c: * gst/tcp/gstmultifdsink.c: * gst/tcp/gsttcpserversink.c: * gst/videorate/gstvideorate.c: * gst/videoscale/gstvideoscale.c: * gst/videotestsrc/gstvideotestsrc.c: * gst/volume/gstvolume.c: * sys/ximage/ximagesink.c: * sys/xvimage/xvimagesink.c: Cleanup Plugin docs. Link to signals and properties. Fix sub-section titles. Drop mentining that all our example pipelines are "simple" pipelines.
2008-07-11 06:10:24 +00:00
*
* <refsect2>
* <title>Example launch line</title>
Cleanup Plugin docs. Link to signals and properties. Fix sub-section titles. Drop mentining that all our example pipe... Original commit message from CVS: * docs/plugins/gst-plugins-base-plugins-docs.sgml: * docs/plugins/gst-plugins-base-plugins-overrides.txt: * docs/plugins/gst-plugins-base-plugins-sections.txt: * docs/plugins/gst-plugins-base-plugins.args: * docs/plugins/gst-plugins-base-plugins.hierarchy: * docs/plugins/gst-plugins-base-plugins.interfaces: * docs/plugins/gst-plugins-base-plugins.prerequisites: * docs/plugins/gst-plugins-base-plugins.signals: * docs/plugins/inspect/plugin-adder.xml: * docs/plugins/inspect/plugin-alsa.xml: * docs/plugins/inspect/plugin-audioconvert.xml: * docs/plugins/inspect/plugin-audiorate.xml: * docs/plugins/inspect/plugin-audioresample.xml: * docs/plugins/inspect/plugin-audiotestsrc.xml: * docs/plugins/inspect/plugin-cdparanoia.xml: * docs/plugins/inspect/plugin-decodebin.xml: * docs/plugins/inspect/plugin-ffmpegcolorspace.xml: * docs/plugins/inspect/plugin-gdp.xml: * docs/plugins/inspect/plugin-gnomevfs.xml: * docs/plugins/inspect/plugin-libvisual.xml: * docs/plugins/inspect/plugin-ogg.xml: * docs/plugins/inspect/plugin-pango.xml: * docs/plugins/inspect/plugin-playback.xml: * docs/plugins/inspect/plugin-queue2.xml: * docs/plugins/inspect/plugin-subparse.xml: * docs/plugins/inspect/plugin-tcp.xml: * docs/plugins/inspect/plugin-theora.xml: * docs/plugins/inspect/plugin-typefindfunctions.xml: * docs/plugins/inspect/plugin-uridecodebin.xml: * docs/plugins/inspect/plugin-video4linux.xml: * docs/plugins/inspect/plugin-videorate.xml: * docs/plugins/inspect/plugin-videoscale.xml: * docs/plugins/inspect/plugin-videotestsrc.xml: * docs/plugins/inspect/plugin-volume.xml: * docs/plugins/inspect/plugin-vorbis.xml: * docs/plugins/inspect/plugin-ximagesink.xml: * docs/plugins/inspect/plugin-xvimagesink.xml: * ext/alsa/gstalsamixer.c: * ext/alsa/gstalsasink.c: * ext/alsa/gstalsasrc.c: * ext/gio/gstgiosink.c: * ext/gio/gstgiosrc.c: * ext/gio/gstgiostreamsink.c: * ext/gio/gstgiostreamsrc.c: * ext/gnomevfs/gstgnomevfssink.c: * ext/gnomevfs/gstgnomevfssrc.c: * ext/ogg/gstoggdemux.c: * ext/ogg/gstoggmux.c: * ext/pango/gstclockoverlay.c: * ext/pango/gsttextoverlay.c: * ext/pango/gsttextrender.c: * ext/pango/gsttimeoverlay.c: * ext/theora/theoradec.c: * ext/theora/theoraenc.c: * ext/theora/theoraparse.c: * ext/vorbis/vorbisdec.c: * ext/vorbis/vorbisenc.c: * ext/vorbis/vorbisparse.c: * ext/vorbis/vorbistag.c: * gst/adder/gstadder.c: * gst/audioconvert/gstaudioconvert.c: * gst/audioresample/gstaudioresample.c: * gst/audiotestsrc/gstaudiotestsrc.c: * gst/ffmpegcolorspace/gstffmpegcolorspace.c: * gst/gdp/gstgdpdepay.c: * gst/gdp/gstgdppay.c: * gst/playback/gstdecodebin2.c: * gst/playback/gstplaybin.c: * gst/playback/gstplaybin2.c: * gst/playback/gstqueue2.c: * gst/playback/gsturidecodebin.c: * gst/tcp/gstmultifdsink.c: * gst/tcp/gsttcpserversink.c: * gst/videorate/gstvideorate.c: * gst/videoscale/gstvideoscale.c: * gst/videotestsrc/gstvideotestsrc.c: * gst/volume/gstvolume.c: * sys/ximage/ximagesink.c: * sys/xvimage/xvimagesink.c: Cleanup Plugin docs. Link to signals and properties. Fix sub-section titles. Drop mentining that all our example pipelines are "simple" pipelines.
2008-07-11 06:10:24 +00:00
* |[
* gst-launch -v -m audiotestsrc ! volume volume=0.5 ! level ! fakesink silent=TRUE
Cleanup Plugin docs. Link to signals and properties. Fix sub-section titles. Drop mentining that all our example pipe... Original commit message from CVS: * docs/plugins/gst-plugins-base-plugins-docs.sgml: * docs/plugins/gst-plugins-base-plugins-overrides.txt: * docs/plugins/gst-plugins-base-plugins-sections.txt: * docs/plugins/gst-plugins-base-plugins.args: * docs/plugins/gst-plugins-base-plugins.hierarchy: * docs/plugins/gst-plugins-base-plugins.interfaces: * docs/plugins/gst-plugins-base-plugins.prerequisites: * docs/plugins/gst-plugins-base-plugins.signals: * docs/plugins/inspect/plugin-adder.xml: * docs/plugins/inspect/plugin-alsa.xml: * docs/plugins/inspect/plugin-audioconvert.xml: * docs/plugins/inspect/plugin-audiorate.xml: * docs/plugins/inspect/plugin-audioresample.xml: * docs/plugins/inspect/plugin-audiotestsrc.xml: * docs/plugins/inspect/plugin-cdparanoia.xml: * docs/plugins/inspect/plugin-decodebin.xml: * docs/plugins/inspect/plugin-ffmpegcolorspace.xml: * docs/plugins/inspect/plugin-gdp.xml: * docs/plugins/inspect/plugin-gnomevfs.xml: * docs/plugins/inspect/plugin-libvisual.xml: * docs/plugins/inspect/plugin-ogg.xml: * docs/plugins/inspect/plugin-pango.xml: * docs/plugins/inspect/plugin-playback.xml: * docs/plugins/inspect/plugin-queue2.xml: * docs/plugins/inspect/plugin-subparse.xml: * docs/plugins/inspect/plugin-tcp.xml: * docs/plugins/inspect/plugin-theora.xml: * docs/plugins/inspect/plugin-typefindfunctions.xml: * docs/plugins/inspect/plugin-uridecodebin.xml: * docs/plugins/inspect/plugin-video4linux.xml: * docs/plugins/inspect/plugin-videorate.xml: * docs/plugins/inspect/plugin-videoscale.xml: * docs/plugins/inspect/plugin-videotestsrc.xml: * docs/plugins/inspect/plugin-volume.xml: * docs/plugins/inspect/plugin-vorbis.xml: * docs/plugins/inspect/plugin-ximagesink.xml: * docs/plugins/inspect/plugin-xvimagesink.xml: * ext/alsa/gstalsamixer.c: * ext/alsa/gstalsasink.c: * ext/alsa/gstalsasrc.c: * ext/gio/gstgiosink.c: * ext/gio/gstgiosrc.c: * ext/gio/gstgiostreamsink.c: * ext/gio/gstgiostreamsrc.c: * ext/gnomevfs/gstgnomevfssink.c: * ext/gnomevfs/gstgnomevfssrc.c: * ext/ogg/gstoggdemux.c: * ext/ogg/gstoggmux.c: * ext/pango/gstclockoverlay.c: * ext/pango/gsttextoverlay.c: * ext/pango/gsttextrender.c: * ext/pango/gsttimeoverlay.c: * ext/theora/theoradec.c: * ext/theora/theoraenc.c: * ext/theora/theoraparse.c: * ext/vorbis/vorbisdec.c: * ext/vorbis/vorbisenc.c: * ext/vorbis/vorbisparse.c: * ext/vorbis/vorbistag.c: * gst/adder/gstadder.c: * gst/audioconvert/gstaudioconvert.c: * gst/audioresample/gstaudioresample.c: * gst/audiotestsrc/gstaudiotestsrc.c: * gst/ffmpegcolorspace/gstffmpegcolorspace.c: * gst/gdp/gstgdpdepay.c: * gst/gdp/gstgdppay.c: * gst/playback/gstdecodebin2.c: * gst/playback/gstplaybin.c: * gst/playback/gstplaybin2.c: * gst/playback/gstqueue2.c: * gst/playback/gsturidecodebin.c: * gst/tcp/gstmultifdsink.c: * gst/tcp/gsttcpserversink.c: * gst/videorate/gstvideorate.c: * gst/videoscale/gstvideoscale.c: * gst/videotestsrc/gstvideotestsrc.c: * gst/volume/gstvolume.c: * sys/ximage/ximagesink.c: * sys/xvimage/xvimagesink.c: Cleanup Plugin docs. Link to signals and properties. Fix sub-section titles. Drop mentining that all our example pipelines are "simple" pipelines.
2008-07-11 06:10:24 +00:00
* ]| This pipeline shows that the level of audiotestsrc has been halved
* (peak values are around -6 dB and RMS around -9 dB) compared to
* the same pipeline without the volume element.
* </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <gst/gst.h>
#include <gst/base/gstbasetransform.h>
#include <gst/audio/audio.h>
#include <gst/audio/mixer.h>
#include <gst/audio/gstaudiofilter.h>
#ifdef HAVE_ORC
#include <orc/orcfunctions.h>
#else
#define orc_memset memset
#endif
#include "gstvolumeorc.h"
#include "gstvolume.h"
/* some defines for audio processing */
/* the volume factor is a range from 0.0 to (arbitrary) VOLUME_MAX_DOUBLE = 10.0
* we map 1.0 to VOLUME_UNITY_INT*
*/
#define VOLUME_UNITY_INT8 8 /* internal int for unity 2^(8-5) */
#define VOLUME_UNITY_INT8_BIT_SHIFT 3 /* number of bits to shift for unity */
#define VOLUME_UNITY_INT16 2048 /* internal int for unity 2^(16-5) */
#define VOLUME_UNITY_INT16_BIT_SHIFT 11 /* number of bits to shift for unity */
#define VOLUME_UNITY_INT24 524288 /* internal int for unity 2^(24-5) */
#define VOLUME_UNITY_INT24_BIT_SHIFT 19 /* number of bits to shift for unity */
#define VOLUME_UNITY_INT32 134217728 /* internal int for unity 2^(32-5) */
#define VOLUME_UNITY_INT32_BIT_SHIFT 27
#define VOLUME_MAX_DOUBLE 10.0
#define VOLUME_MAX_INT8 G_MAXINT8
#define VOLUME_MIN_INT8 G_MININT8
#define VOLUME_MAX_INT16 G_MAXINT16
#define VOLUME_MIN_INT16 G_MININT16
#define VOLUME_MAX_INT24 8388607
#define VOLUME_MIN_INT24 -8388608
#define VOLUME_MAX_INT32 G_MAXINT32
#define VOLUME_MIN_INT32 G_MININT32
/* number of steps we use for the mixer interface to go from 0.0 to 1.0 */
# define VOLUME_STEPS 100
#define GST_CAT_DEFAULT gst_volume_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
/* Filter signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
#define DEFAULT_PROP_MUTE FALSE
#define DEFAULT_PROP_VOLUME 1.0
enum
{
PROP_0,
PROP_MUTE,
PROP_VOLUME
};
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
#define ALLOWED_CAPS \
GST_AUDIO_CAPS_MAKE ("{ F32LE, F64LE, S8, S16LE, S24LE, S32LE }") \
", layout = (string) interleaved"
#else
#define ALLOWED_CAPS \
GST_AUDIO_CAPS_MAKE ("{ F32BE, F64BE, S8, S16BE, S24BE, S32BE }") \
", layout = (string) { interleaved, non-interleaved }"
#endif
static void gst_volume_mixer_init (GstMixerInterface * iface);
#define gst_volume_parent_class parent_class
G_DEFINE_TYPE_WITH_CODE (GstVolume, gst_volume,
GST_TYPE_AUDIO_FILTER,
G_IMPLEMENT_INTERFACE (GST_TYPE_MIXER, gst_volume_mixer_init);
G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL));
static void volume_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void volume_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void volume_before_transform (GstBaseTransform * base,
GstBuffer * buffer);
static GstFlowReturn volume_transform_ip (GstBaseTransform * base,
GstBuffer * outbuf);
static gboolean volume_stop (GstBaseTransform * base);
static gboolean volume_setup (GstAudioFilter * filter,
const GstAudioInfo * info);
2010-02-13 00:08:05 +00:00
static void volume_process_double (GstVolume * self, gpointer bytes,
guint n_bytes);
static void volume_process_controlled_double (GstVolume * self, gpointer bytes,
gdouble * volume, guint channels, guint n_bytes);
2010-02-13 00:08:05 +00:00
static void volume_process_float (GstVolume * self, gpointer bytes,
guint n_bytes);
static void volume_process_controlled_float (GstVolume * self, gpointer bytes,
gdouble * volume, guint channels, guint n_bytes);
2010-02-13 00:08:05 +00:00
static void volume_process_int32 (GstVolume * self, gpointer bytes,
guint n_bytes);
2010-02-13 00:08:05 +00:00
static void volume_process_int32_clamp (GstVolume * self, gpointer bytes,
guint n_bytes);
static void volume_process_controlled_int32_clamp (GstVolume * self,
gpointer bytes, gdouble * volume, guint channels, guint n_bytes);
2010-02-13 00:08:05 +00:00
static void volume_process_int24 (GstVolume * self, gpointer bytes,
guint n_bytes);
2010-02-13 00:08:05 +00:00
static void volume_process_int24_clamp (GstVolume * self, gpointer bytes,
guint n_bytes);
static void volume_process_controlled_int24_clamp (GstVolume * self,
gpointer bytes, gdouble * volume, guint channels, guint n_bytes);
2010-02-13 00:08:05 +00:00
static void volume_process_int16 (GstVolume * self, gpointer bytes,
guint n_bytes);
2010-02-13 00:08:05 +00:00
static void volume_process_int16_clamp (GstVolume * self, gpointer bytes,
guint n_bytes);
static void volume_process_controlled_int16_clamp (GstVolume * self,
gpointer bytes, gdouble * volume, guint channels, guint n_bytes);
2010-02-13 00:08:05 +00:00
static void volume_process_int8 (GstVolume * self, gpointer bytes,
guint n_bytes);
2010-02-13 00:08:05 +00:00
static void volume_process_int8_clamp (GstVolume * self, gpointer bytes,
guint n_bytes);
static void volume_process_controlled_int8_clamp (GstVolume * self,
gpointer bytes, gdouble * volume, guint channels, guint n_bytes);
/* helper functions */
static gboolean
volume_choose_func (GstVolume * self, const GstAudioInfo * info)
{
GstAudioFormat format;
2010-02-13 00:08:05 +00:00
self->process = NULL;
self->process_controlled = NULL;
format = GST_AUDIO_INFO_FORMAT (info);
if (format == GST_AUDIO_FORMAT_UNKNOWN)
return FALSE;
switch (format) {
case GST_AUDIO_FORMAT_S32:
/* only clamp if the gain is greater than 1.0 */
if (self->current_vol_i32 > VOLUME_UNITY_INT32) {
self->process = volume_process_int32_clamp;
} else {
self->process = volume_process_int32;
}
self->process_controlled = volume_process_controlled_int32_clamp;
break;
case GST_AUDIO_FORMAT_S24:
/* only clamp if the gain is greater than 1.0 */
if (self->current_vol_i24 > VOLUME_UNITY_INT24) {
self->process = volume_process_int24_clamp;
} else {
self->process = volume_process_int24;
}
self->process_controlled = volume_process_controlled_int24_clamp;
break;
case GST_AUDIO_FORMAT_S16:
/* only clamp if the gain is greater than 1.0 */
if (self->current_vol_i16 > VOLUME_UNITY_INT16) {
self->process = volume_process_int16_clamp;
} else {
self->process = volume_process_int16;
}
self->process_controlled = volume_process_controlled_int16_clamp;
break;
case GST_AUDIO_FORMAT_S8:
/* only clamp if the gain is greater than 1.0 */
if (self->current_vol_i8 > VOLUME_UNITY_INT8) {
self->process = volume_process_int8_clamp;
} else {
self->process = volume_process_int8;
}
self->process_controlled = volume_process_controlled_int8_clamp;
break;
case GST_AUDIO_FORMAT_F32:
self->process = volume_process_float;
self->process_controlled = volume_process_controlled_float;
break;
case GST_AUDIO_FORMAT_F64:
self->process = volume_process_double;
self->process_controlled = volume_process_controlled_double;
break;
default:
break;
}
2010-02-13 00:08:05 +00:00
return (self->process != NULL);
}
static gboolean
volume_update_volume (GstVolume * self, const GstAudioInfo * info,
gfloat volume, gboolean mute)
{
gboolean passthrough;
gboolean res;
2010-02-13 00:08:05 +00:00
GST_DEBUG_OBJECT (self, "configure mute %d, volume %f", mute, volume);
if (mute) {
2010-02-13 00:08:05 +00:00
self->current_mute = TRUE;
self->current_volume = 0.0;
2010-02-13 00:08:05 +00:00
self->current_vol_i8 = 0;
self->current_vol_i16 = 0;
self->current_vol_i24 = 0;
self->current_vol_i32 = 0;
passthrough = FALSE;
} else {
2010-02-13 00:08:05 +00:00
self->current_mute = FALSE;
self->current_volume = volume;
2010-02-13 00:08:05 +00:00
self->current_vol_i8 = volume * VOLUME_UNITY_INT8;
self->current_vol_i16 = volume * VOLUME_UNITY_INT16;
self->current_vol_i24 = volume * VOLUME_UNITY_INT24;
self->current_vol_i32 = volume * VOLUME_UNITY_INT32;
2010-02-13 00:08:05 +00:00
passthrough = (self->current_vol_i16 == VOLUME_UNITY_INT16);
}
/* If a controller is used, never use passthrough mode
* because the property can change from 1.0 to something
* else in the middle of a buffer.
*/
passthrough &= !gst_object_has_active_control_bindings (GST_OBJECT (self));
2010-02-13 00:08:05 +00:00
GST_DEBUG_OBJECT (self, "set passthrough %d", passthrough);
2010-02-13 00:08:05 +00:00
gst_base_transform_set_passthrough (GST_BASE_TRANSFORM (self), passthrough);
res = self->negotiated = volume_choose_func (self, info);
return res;
}
/* Mixer interface */
static const GList *
gst_volume_list_tracks (GstMixer * mixer)
{
2010-02-13 00:08:05 +00:00
GstVolume *self = GST_VOLUME (mixer);
2010-02-13 00:08:05 +00:00
g_return_val_if_fail (self != NULL, NULL);
g_return_val_if_fail (GST_IS_VOLUME (self), NULL);
2010-02-13 00:08:05 +00:00
return self->tracklist;
}
static void
gst_volume_set_volume (GstMixer * mixer, GstMixerTrack * track, gint * volumes)
{
2010-02-13 00:08:05 +00:00
GstVolume *self = GST_VOLUME (mixer);
2010-02-13 00:08:05 +00:00
g_return_if_fail (self != NULL);
g_return_if_fail (GST_IS_VOLUME (self));
2010-02-13 00:08:05 +00:00
GST_OBJECT_LOCK (self);
self->volume = (gfloat) volumes[0] / VOLUME_STEPS;
GST_OBJECT_UNLOCK (self);
}
static void
gst_volume_get_volume (GstMixer * mixer, GstMixerTrack * track, gint * volumes)
{
2010-02-13 00:08:05 +00:00
GstVolume *self = GST_VOLUME (mixer);
2010-02-13 00:08:05 +00:00
g_return_if_fail (self != NULL);
g_return_if_fail (GST_IS_VOLUME (self));
2010-02-13 00:08:05 +00:00
GST_OBJECT_LOCK (self);
volumes[0] = (gint) self->volume * VOLUME_STEPS;
GST_OBJECT_UNLOCK (self);
}
static void
gst_volume_set_mute (GstMixer * mixer, GstMixerTrack * track, gboolean mute)
{
2010-02-13 00:08:05 +00:00
GstVolume *self = GST_VOLUME (mixer);
2010-02-13 00:08:05 +00:00
g_return_if_fail (self != NULL);
g_return_if_fail (GST_IS_VOLUME (self));
2010-02-13 00:08:05 +00:00
GST_OBJECT_LOCK (self);
self->mute = mute;
GST_OBJECT_UNLOCK (self);
}
static void
gst_volume_mixer_init (GstMixerInterface * iface)
{
GST_MIXER_TYPE (iface) = GST_MIXER_SOFTWARE;
/* default virtual functions */
iface->list_tracks = gst_volume_list_tracks;
iface->set_volume = gst_volume_set_volume;
iface->get_volume = gst_volume_get_volume;
iface->set_mute = gst_volume_set_mute;
}
/* Element class */
static void
gst_volume_dispose (GObject * object)
{
GstVolume *volume = GST_VOLUME (object);
if (volume->tracklist) {
if (volume->tracklist->data)
g_object_unref (volume->tracklist->data);
g_list_free (volume->tracklist);
volume->tracklist = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gst_volume_class_init (GstVolumeClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *element_class;
GstBaseTransformClass *trans_class;
GstAudioFilterClass *filter_class;
GstCaps *caps;
gobject_class = (GObjectClass *) klass;
element_class = (GstElementClass *) klass;
trans_class = (GstBaseTransformClass *) klass;
filter_class = (GstAudioFilterClass *) (klass);
gobject_class->set_property = volume_set_property;
gobject_class->get_property = volume_get_property;
gobject_class->dispose = gst_volume_dispose;
g_object_class_install_property (gobject_class, PROP_MUTE,
g_param_spec_boolean ("mute", "Mute", "mute channel",
DEFAULT_PROP_MUTE,
Use G_PARAM_STATIC_STRINGS everywhere for GParamSpecs that use static strings (i.e. all). This gives us less memory u... Original commit message from CVS: * configure.ac: * ext/alsa/gstalsamixerelement.c: (gst_alsa_mixer_element_class_init): * ext/alsa/gstalsasink.c: (gst_alsasink_class_init): * ext/alsa/gstalsasrc.c: (gst_alsasrc_class_init): * ext/cdparanoia/gstcdparanoiasrc.c: (gst_cd_paranoia_src_class_init): * ext/gio/gstgiosink.c: (gst_gio_sink_class_init): * ext/gio/gstgiosrc.c: (gst_gio_src_class_init): * ext/gio/gstgiostreamsink.c: (gst_gio_stream_sink_class_init): * ext/gio/gstgiostreamsrc.c: (gst_gio_stream_src_class_init): * ext/gnomevfs/gstgnomevfssink.c: (gst_gnome_vfs_sink_class_init): * ext/gnomevfs/gstgnomevfssrc.c: (gst_gnome_vfs_src_class_init): * ext/ogg/gstoggmux.c: (gst_ogg_mux_class_init): * ext/pango/gsttextoverlay.c: (gst_text_overlay_class_init): * ext/pango/gsttextrender.c: (gst_text_render_class_init): * ext/theora/theoradec.c: (gst_theora_dec_class_init): * ext/theora/theoraenc.c: (gst_theora_enc_class_init): * ext/theora/theoraparse.c: (gst_theora_parse_class_init): * ext/vorbis/vorbisenc.c: (gst_vorbis_enc_class_init): * gst-libs/gst/audio/gstaudiofiltertemplate.c: (gst_audio_filter_template_class_init): * gst-libs/gst/audio/gstbaseaudiosink.c: (gst_base_audio_sink_class_init): * gst-libs/gst/audio/gstbaseaudiosrc.c: (gst_base_audio_src_class_init): * gst-libs/gst/cdda/gstcddabasesrc.c: (gst_cdda_base_src_class_init): * gst-libs/gst/interfaces/mixertrack.c: (gst_mixer_track_class_init): * gst-libs/gst/rtp/gstbasertpdepayload.c: (gst_base_rtp_depayload_class_init): * gst-libs/gst/rtp/gstbasertppayload.c: (gst_basertppayload_class_init): * gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_class_init): * gst/audiorate/gstaudiorate.c: (gst_audio_rate_class_init): * gst/audioresample/gstaudioresample.c: (gst_audioresample_class_init): * gst/audiotestsrc/gstaudiotestsrc.c: (gst_audio_test_src_class_init): * gst/gdp/gstgdppay.c: (gst_gdp_pay_class_init): * gst/playback/gstdecodebin2.c: (gst_decode_bin_class_init): * gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init), (preroll_unlinked): * gst/playback/gstplaybin.c: (gst_play_bin_class_init): * gst/playback/gstplaybin2.c: (gst_play_bin_class_init): * gst/playback/gstplaysink.c: (gst_play_sink_class_init): * gst/playback/gstqueue2.c: (gst_queue_class_init): * gst/playback/gststreaminfo.c: (gst_stream_info_class_init): * gst/playback/gststreamselector.c: (gst_selector_pad_class_init), (gst_stream_selector_class_init): * gst/playback/gsturidecodebin.c: (gst_uri_decode_bin_class_init): * gst/subparse/gstsubparse.c: (gst_sub_parse_class_init): * gst/tcp/gstmultifdsink.c: (gst_multi_fd_sink_class_init): * gst/tcp/gsttcpclientsink.c: (gst_tcp_client_sink_class_init): * gst/tcp/gsttcpclientsrc.c: (gst_tcp_client_src_class_init): * gst/tcp/gsttcpserversink.c: (gst_tcp_server_sink_class_init): * gst/tcp/gsttcpserversrc.c: (gst_tcp_server_src_class_init): * gst/videorate/gstvideorate.c: (gst_video_rate_class_init): * gst/videoscale/gstvideoscale.c: (gst_video_scale_class_init): * gst/videotestsrc/gstvideotestsrc.c: (gst_video_test_src_class_init): * gst/volume/gstvolume.c: (gst_volume_class_init): * sys/v4l/gstv4lelement.c: (gst_v4lelement_class_init): * sys/v4l/gstv4lmjpegsink.c: (gst_v4lmjpegsink_class_init): * sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_class_init): * sys/v4l/gstv4lsrc.c: (gst_v4lsrc_class_init): * sys/ximage/ximagesink.c: (gst_ximagesink_class_init): * sys/xvimage/xvimagesink.c: (gst_xvimagesink_class_init): Use G_PARAM_STATIC_STRINGS everywhere for GParamSpecs that use static strings (i.e. all). This gives us less memory usage, fewer allocations and thus less memory defragmentation. Depend on core CVS for this. Fixes bug #523806.
2008-03-22 15:00:53 +00:00
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_VOLUME,
g_param_spec_double ("volume", "Volume", "volume factor, 1.0=100%",
0.0, VOLUME_MAX_DOUBLE, DEFAULT_PROP_VOLUME,
Use G_PARAM_STATIC_STRINGS everywhere for GParamSpecs that use static strings (i.e. all). This gives us less memory u... Original commit message from CVS: * configure.ac: * ext/alsa/gstalsamixerelement.c: (gst_alsa_mixer_element_class_init): * ext/alsa/gstalsasink.c: (gst_alsasink_class_init): * ext/alsa/gstalsasrc.c: (gst_alsasrc_class_init): * ext/cdparanoia/gstcdparanoiasrc.c: (gst_cd_paranoia_src_class_init): * ext/gio/gstgiosink.c: (gst_gio_sink_class_init): * ext/gio/gstgiosrc.c: (gst_gio_src_class_init): * ext/gio/gstgiostreamsink.c: (gst_gio_stream_sink_class_init): * ext/gio/gstgiostreamsrc.c: (gst_gio_stream_src_class_init): * ext/gnomevfs/gstgnomevfssink.c: (gst_gnome_vfs_sink_class_init): * ext/gnomevfs/gstgnomevfssrc.c: (gst_gnome_vfs_src_class_init): * ext/ogg/gstoggmux.c: (gst_ogg_mux_class_init): * ext/pango/gsttextoverlay.c: (gst_text_overlay_class_init): * ext/pango/gsttextrender.c: (gst_text_render_class_init): * ext/theora/theoradec.c: (gst_theora_dec_class_init): * ext/theora/theoraenc.c: (gst_theora_enc_class_init): * ext/theora/theoraparse.c: (gst_theora_parse_class_init): * ext/vorbis/vorbisenc.c: (gst_vorbis_enc_class_init): * gst-libs/gst/audio/gstaudiofiltertemplate.c: (gst_audio_filter_template_class_init): * gst-libs/gst/audio/gstbaseaudiosink.c: (gst_base_audio_sink_class_init): * gst-libs/gst/audio/gstbaseaudiosrc.c: (gst_base_audio_src_class_init): * gst-libs/gst/cdda/gstcddabasesrc.c: (gst_cdda_base_src_class_init): * gst-libs/gst/interfaces/mixertrack.c: (gst_mixer_track_class_init): * gst-libs/gst/rtp/gstbasertpdepayload.c: (gst_base_rtp_depayload_class_init): * gst-libs/gst/rtp/gstbasertppayload.c: (gst_basertppayload_class_init): * gst/audioconvert/gstaudioconvert.c: (gst_audio_convert_class_init): * gst/audiorate/gstaudiorate.c: (gst_audio_rate_class_init): * gst/audioresample/gstaudioresample.c: (gst_audioresample_class_init): * gst/audiotestsrc/gstaudiotestsrc.c: (gst_audio_test_src_class_init): * gst/gdp/gstgdppay.c: (gst_gdp_pay_class_init): * gst/playback/gstdecodebin2.c: (gst_decode_bin_class_init): * gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init), (preroll_unlinked): * gst/playback/gstplaybin.c: (gst_play_bin_class_init): * gst/playback/gstplaybin2.c: (gst_play_bin_class_init): * gst/playback/gstplaysink.c: (gst_play_sink_class_init): * gst/playback/gstqueue2.c: (gst_queue_class_init): * gst/playback/gststreaminfo.c: (gst_stream_info_class_init): * gst/playback/gststreamselector.c: (gst_selector_pad_class_init), (gst_stream_selector_class_init): * gst/playback/gsturidecodebin.c: (gst_uri_decode_bin_class_init): * gst/subparse/gstsubparse.c: (gst_sub_parse_class_init): * gst/tcp/gstmultifdsink.c: (gst_multi_fd_sink_class_init): * gst/tcp/gsttcpclientsink.c: (gst_tcp_client_sink_class_init): * gst/tcp/gsttcpclientsrc.c: (gst_tcp_client_src_class_init): * gst/tcp/gsttcpserversink.c: (gst_tcp_server_sink_class_init): * gst/tcp/gsttcpserversrc.c: (gst_tcp_server_src_class_init): * gst/videorate/gstvideorate.c: (gst_video_rate_class_init): * gst/videoscale/gstvideoscale.c: (gst_video_scale_class_init): * gst/videotestsrc/gstvideotestsrc.c: (gst_video_test_src_class_init): * gst/volume/gstvolume.c: (gst_volume_class_init): * sys/v4l/gstv4lelement.c: (gst_v4lelement_class_init): * sys/v4l/gstv4lmjpegsink.c: (gst_v4lmjpegsink_class_init): * sys/v4l/gstv4lmjpegsrc.c: (gst_v4lmjpegsrc_class_init): * sys/v4l/gstv4lsrc.c: (gst_v4lsrc_class_init): * sys/ximage/ximagesink.c: (gst_ximagesink_class_init): * sys/xvimage/xvimagesink.c: (gst_xvimagesink_class_init): Use G_PARAM_STATIC_STRINGS everywhere for GParamSpecs that use static strings (i.e. all). This gives us less memory usage, fewer allocations and thus less memory defragmentation. Depend on core CVS for this. Fixes bug #523806.
2008-03-22 15:00:53 +00:00
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
gst_element_class_set_details_simple (element_class, "Volume",
"Filter/Effect/Audio",
"Set volume on audio/raw streams", "Andy Wingo <wingo@pobox.com>");
caps = gst_caps_from_string (ALLOWED_CAPS);
gst_audio_filter_class_add_pad_templates (filter_class, caps);
gst_caps_unref (caps);
trans_class->before_transform = GST_DEBUG_FUNCPTR (volume_before_transform);
trans_class->transform_ip = GST_DEBUG_FUNCPTR (volume_transform_ip);
trans_class->stop = GST_DEBUG_FUNCPTR (volume_stop);
filter_class->setup = GST_DEBUG_FUNCPTR (volume_setup);
}
static void
gst_volume_init (GstVolume * self)
{
GstMixerTrack *track = NULL;
2010-02-13 00:08:05 +00:00
self->mute = DEFAULT_PROP_MUTE;;
self->volume = DEFAULT_PROP_VOLUME;
2010-02-13 00:08:05 +00:00
self->tracklist = NULL;
self->negotiated = FALSE;
track = g_object_new (GST_TYPE_MIXER_TRACK, NULL);
if (GST_IS_MIXER_TRACK (track)) {
track->label = g_strdup ("volume");
track->num_channels = 1;
track->min_volume = 0;
track->max_volume = VOLUME_STEPS;
track->flags = GST_MIXER_TRACK_SOFTWARE;
2010-02-13 00:08:05 +00:00
self->tracklist = g_list_append (self->tracklist, track);
}
2010-02-13 00:08:05 +00:00
gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (self), TRUE);
}
static void
2010-02-13 00:08:05 +00:00
volume_process_double (GstVolume * self, gpointer bytes, guint n_bytes)
{
gdouble *data = (gdouble *) bytes;
guint num_samples = n_bytes / sizeof (gdouble);
orc_scalarmultiply_f64_ns (data, self->current_volume, num_samples);
}
static void
volume_process_controlled_double (GstVolume * self, gpointer bytes,
gdouble * volume, guint channels, guint n_bytes)
{
gdouble *data = (gdouble *) bytes;
guint num_samples = n_bytes / (sizeof (gdouble) * channels);
guint i, j;
gdouble vol;
if (channels == 1) {
orc_process_controlled_f64_1ch (data, volume, num_samples);
} else {
for (i = 0; i < num_samples; i++) {
vol = *volume++;
for (j = 0; j < channels; j++) {
*data++ *= vol;
}
}
}
}
static void
2010-02-13 00:08:05 +00:00
volume_process_float (GstVolume * self, gpointer bytes, guint n_bytes)
{
gfloat *data = (gfloat *) bytes;
guint num_samples = n_bytes / sizeof (gfloat);
orc_scalarmultiply_f32_ns (data, self->current_volume, num_samples);
}
static void
volume_process_controlled_float (GstVolume * self, gpointer bytes,
gdouble * volume, guint channels, guint n_bytes)
{
gfloat *data = (gfloat *) bytes;
guint num_samples = n_bytes / (sizeof (gfloat) * channels);
guint i, j;
gdouble vol;
if (channels == 1) {
orc_process_controlled_f32_1ch (data, volume, num_samples);
} else if (channels == 2) {
orc_process_controlled_f32_2ch (data, volume, num_samples);
} else {
for (i = 0; i < num_samples; i++) {
vol = *volume++;
for (j = 0; j < channels; j++) {
*data++ *= vol;
}
}
}
}
static void
2010-02-13 00:08:05 +00:00
volume_process_int32 (GstVolume * self, gpointer bytes, guint n_bytes)
{
gint32 *data = (gint32 *) bytes;
guint num_samples = n_bytes / sizeof (gint);
/* hard coded in volume.orc */
g_assert (VOLUME_UNITY_INT32_BIT_SHIFT == 27);
orc_process_int32 (data, self->current_vol_i32, num_samples);
}
static void
2010-02-13 00:08:05 +00:00
volume_process_int32_clamp (GstVolume * self, gpointer bytes, guint n_bytes)
{
gint32 *data = (gint32 *) bytes;
guint num_samples = n_bytes / sizeof (gint);
/* hard coded in volume.orc */
g_assert (VOLUME_UNITY_INT32_BIT_SHIFT == 27);
orc_process_int32_clamp (data, self->current_vol_i32, num_samples);
}
static void
volume_process_controlled_int32_clamp (GstVolume * self, gpointer bytes,
gdouble * volume, guint channels, guint n_bytes)
{
gint32 *data = (gint32 *) bytes;
guint i, j;
guint num_samples = n_bytes / (sizeof (gint32) * channels);
gdouble vol, val;
if (channels == 1) {
orc_process_controlled_int32_1ch (data, volume, num_samples);
} else {
for (i = 0; i < num_samples; i++) {
vol = *volume++;
for (j = 0; j < channels; j++) {
val = *data * vol;
*data++ = (gint32) CLAMP (val, VOLUME_MIN_INT32, VOLUME_MAX_INT32);
}
}
}
}
#if (G_BYTE_ORDER == G_LITTLE_ENDIAN)
#define get_unaligned_i24(_x) ( (((guint8*)_x)[0]) | ((((guint8*)_x)[1]) << 8) | ((((gint8*)_x)[2]) << 16) )
#define write_unaligned_u24(_x,samp) \
G_STMT_START { \
*(_x)++ = samp & 0xFF; \
*(_x)++ = (samp >> 8) & 0xFF; \
*(_x)++ = (samp >> 16) & 0xFF; \
} G_STMT_END
#else /* BIG ENDIAN */
#define get_unaligned_i24(_x) ( (((guint8*)_x)[2]) | ((((guint8*)_x)[1]) << 8) | ((((gint8*)_x)[0]) << 16) )
#define write_unaligned_u24(_x,samp) \
G_STMT_START { \
*(_x)++ = (samp >> 16) & 0xFF; \
*(_x)++ = (samp >> 8) & 0xFF; \
*(_x)++ = samp & 0xFF; \
} G_STMT_END
#endif
static void
2010-02-13 00:08:05 +00:00
volume_process_int24 (GstVolume * self, gpointer bytes, guint n_bytes)
{
gint8 *data = (gint8 *) bytes; /* treat the data as a byte stream */
guint i, num_samples;
guint32 samp;
gint64 val;
num_samples = n_bytes / (sizeof (gint8) * 3);
for (i = 0; i < num_samples; i++) {
samp = get_unaligned_i24 (data);
val = (gint32) samp;
val =
2010-02-13 00:08:05 +00:00
(((gint64) self->current_vol_i24 *
val) >> VOLUME_UNITY_INT24_BIT_SHIFT);
samp = (guint32) val;
/* write the value back into the stream */
write_unaligned_u24 (data, samp);
}
}
static void
2010-02-13 00:08:05 +00:00
volume_process_int24_clamp (GstVolume * self, gpointer bytes, guint n_bytes)
{
gint8 *data = (gint8 *) bytes; /* treat the data as a byte stream */
guint i, num_samples;
guint32 samp;
gint64 val;
num_samples = n_bytes / (sizeof (gint8) * 3);
for (i = 0; i < num_samples; i++) {
samp = get_unaligned_i24 (data);
val = (gint32) samp;
val =
2010-02-13 00:08:05 +00:00
(((gint64) self->current_vol_i24 *
val) >> VOLUME_UNITY_INT24_BIT_SHIFT);
samp = (guint32) CLAMP (val, VOLUME_MIN_INT24, VOLUME_MAX_INT24);
/* write the value back into the stream */
write_unaligned_u24 (data, samp);
}
}
static void
volume_process_controlled_int24_clamp (GstVolume * self, gpointer bytes,
gdouble * volume, guint channels, guint n_bytes)
{
gint8 *data = (gint8 *) bytes; /* treat the data as a byte stream */
guint i, j;
guint num_samples = n_bytes / (sizeof (gint8) * 3 * channels);
gdouble vol, val;
for (i = 0; i < num_samples; i++) {
vol = *volume++;
for (j = 0; j < channels; j++) {
val = get_unaligned_i24 (data) * vol;
val = CLAMP (val, VOLUME_MIN_INT24, VOLUME_MAX_INT24);
write_unaligned_u24 (data, (gint32) val);
}
}
}
static void
2010-02-13 00:08:05 +00:00
volume_process_int16 (GstVolume * self, gpointer bytes, guint n_bytes)
{
gint16 *data = (gint16 *) bytes;
guint num_samples = n_bytes / sizeof (gint16);
/* hard coded in volume.orc */
g_assert (VOLUME_UNITY_INT16_BIT_SHIFT == 11);
orc_process_int16 (data, self->current_vol_i16, num_samples);
}
static void
2010-02-13 00:08:05 +00:00
volume_process_int16_clamp (GstVolume * self, gpointer bytes, guint n_bytes)
{
gint16 *data = (gint16 *) bytes;
2010-06-07 06:48:15 +00:00
guint num_samples = n_bytes / sizeof (gint16);
2010-06-07 06:48:15 +00:00
/* hard coded in volume.orc */
g_assert (VOLUME_UNITY_INT16_BIT_SHIFT == 11);
orc_process_int16_clamp (data, self->current_vol_i16, num_samples);
}
static void
volume_process_controlled_int16_clamp (GstVolume * self, gpointer bytes,
gdouble * volume, guint channels, guint n_bytes)
{
gint16 *data = (gint16 *) bytes;
guint i, j;
guint num_samples = n_bytes / (sizeof (gint16) * channels);
gdouble vol, val;
if (channels == 1) {
orc_process_controlled_int16_1ch (data, volume, num_samples);
} else if (channels == 2) {
orc_process_controlled_int16_2ch (data, volume, num_samples);
} else {
for (i = 0; i < num_samples; i++) {
vol = *volume++;
for (j = 0; j < channels; j++) {
val = *data * vol;
*data++ = (gint16) CLAMP (val, VOLUME_MIN_INT16, VOLUME_MAX_INT16);
}
}
}
}
static void
2010-02-13 00:08:05 +00:00
volume_process_int8 (GstVolume * self, gpointer bytes, guint n_bytes)
{
gint8 *data = (gint8 *) bytes;
guint num_samples = n_bytes / sizeof (gint8);
2010-06-07 06:48:15 +00:00
/* hard coded in volume.orc */
g_assert (VOLUME_UNITY_INT8_BIT_SHIFT == 3);
2010-06-07 06:48:15 +00:00
orc_process_int8 (data, self->current_vol_i8, num_samples);
}
static void
2010-02-13 00:08:05 +00:00
volume_process_int8_clamp (GstVolume * self, gpointer bytes, guint n_bytes)
{
gint8 *data = (gint8 *) bytes;
2010-06-07 06:48:15 +00:00
guint num_samples = n_bytes / sizeof (gint8);
2010-06-07 06:48:15 +00:00
/* hard coded in volume.orc */
g_assert (VOLUME_UNITY_INT8_BIT_SHIFT == 3);
orc_process_int8_clamp (data, self->current_vol_i8, num_samples);
}
static void
volume_process_controlled_int8_clamp (GstVolume * self, gpointer bytes,
gdouble * volume, guint channels, guint n_bytes)
{
gint8 *data = (gint8 *) bytes;
guint i, j;
guint num_samples = n_bytes / (sizeof (gint8) * channels);
gdouble val, vol;
if (channels == 1) {
orc_process_controlled_int8_1ch (data, volume, num_samples);
} else if (channels == 2) {
orc_process_controlled_int8_2ch (data, volume, num_samples);
} else {
for (i = 0; i < num_samples; i++) {
vol = *volume++;
for (j = 0; j < channels; j++) {
val = *data * vol;
*data++ = (gint8) CLAMP (val, VOLUME_MIN_INT8, VOLUME_MAX_INT8);
}
}
}
}
/* GstBaseTransform vmethod implementations */
/* get notified of caps and plug in the correct process function */
static gboolean
volume_setup (GstAudioFilter * filter, const GstAudioInfo * info)
{
gboolean res;
2010-02-13 00:08:05 +00:00
GstVolume *self = GST_VOLUME (filter);
gfloat volume;
gboolean mute;
2010-02-13 00:08:05 +00:00
GST_OBJECT_LOCK (self);
volume = self->volume;
mute = self->mute;
GST_OBJECT_UNLOCK (self);
res = volume_update_volume (self, info, volume, mute);
if (!res) {
2010-02-13 00:08:05 +00:00
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
("Invalid incoming format"), (NULL));
}
2010-02-13 00:08:05 +00:00
self->negotiated = res;
return res;
}
static gboolean
volume_stop (GstBaseTransform * base)
{
GstVolume *self = GST_VOLUME (base);
g_free (self->volumes);
self->volumes = NULL;
self->volumes_count = 0;
g_free (self->mutes);
self->mutes = NULL;
self->mutes_count = 0;
return GST_CALL_PARENT_WITH_DEFAULT (GST_BASE_TRANSFORM_CLASS, stop, (base),
TRUE);
}
static void
volume_before_transform (GstBaseTransform * base, GstBuffer * buffer)
{
GstClockTime timestamp;
2010-02-13 00:08:05 +00:00
GstVolume *self = GST_VOLUME (base);
gfloat volume;
gboolean mute;
timestamp = GST_BUFFER_TIMESTAMP (buffer);
timestamp =
gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, timestamp);
GST_DEBUG_OBJECT (base, "sync to %" GST_TIME_FORMAT,
GST_TIME_ARGS (timestamp));
if (GST_CLOCK_TIME_IS_VALID (timestamp))
gst_object_sync_values (GST_OBJECT (self), timestamp);
/* get latest values */
2010-02-13 00:08:05 +00:00
GST_OBJECT_LOCK (self);
volume = self->volume;
mute = self->mute;
GST_OBJECT_UNLOCK (self);
2010-02-13 00:08:05 +00:00
if ((volume != self->current_volume) || (mute != self->current_mute)) {
/* the volume or mute was updated, update our internal state before
* we continue processing. */
volume_update_volume (self, GST_AUDIO_FILTER_INFO (self), volume, mute);
}
}
/* call the plugged-in process function for this instance
* needs to be done with this indirection since volume_transform is
* a class-global method
*/
static GstFlowReturn
volume_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
{
GstAudioFilter *filter = GST_AUDIO_FILTER_CAST (base);
2010-02-13 00:08:05 +00:00
GstVolume *self = GST_VOLUME (base);
2012-01-20 15:11:54 +00:00
GstMapInfo map;
GstControlBinding *mute_cb, *volume_cb;
2010-02-13 00:08:05 +00:00
if (G_UNLIKELY (!self->negotiated))
goto not_negotiated;
/* don't process data in passthrough-mode */
if (gst_base_transform_is_passthrough (base) ||
GST_BUFFER_FLAG_IS_SET (outbuf, GST_BUFFER_FLAG_GAP))
return GST_FLOW_OK;
2012-01-20 15:11:54 +00:00
gst_buffer_map (outbuf, &map, GST_MAP_READWRITE);
mute_cb = gst_object_get_control_binding (GST_OBJECT (self), "mute");
volume_cb = gst_object_get_control_binding (GST_OBJECT (self), "volume");
if (mute_cb || (volume_cb && !self->current_mute)) {
gint rate = GST_AUDIO_INFO_RATE (&filter->info);
gint width = GST_AUDIO_FORMAT_INFO_WIDTH (filter->info.finfo) / 8;
gint channels = GST_AUDIO_INFO_CHANNELS (&filter->info);
2012-01-20 15:11:54 +00:00
guint nsamples = map.size / (width * channels);
GstClockTime interval = gst_util_uint64_scale_int (1, GST_SECOND, rate);
GstClockTime ts = GST_BUFFER_TIMESTAMP (outbuf);
gboolean use_mutes = FALSE;
ts = gst_segment_to_stream_time (&base->segment, GST_FORMAT_TIME, ts);
if (self->mutes_count < nsamples && mute_cb) {
self->mutes = g_realloc (self->mutes, sizeof (gboolean) * nsamples);
self->mutes_count = nsamples;
}
if (self->volumes_count < nsamples) {
self->volumes = g_realloc (self->volumes, sizeof (gdouble) * nsamples);
self->volumes_count = nsamples;
}
if (mute_cb) {
if (!gst_control_binding_get_value_array (mute_cb, ts, interval,
nsamples, (gpointer) self->mutes))
goto controller_failure;
gst_object_replace ((GstObject **) & mute_cb, NULL);
use_mutes = TRUE;
} else {
g_free (self->mutes);
self->mutes = NULL;
self->mutes_count = 0;
}
if (volume_cb) {
if (!gst_control_binding_get_value_array (volume_cb, ts, interval,
nsamples, (gpointer) self->volumes))
goto controller_failure;
gst_object_replace ((GstObject **) & volume_cb, NULL);
} else {
orc_memset_f64 (self->volumes, self->current_volume, nsamples);
}
if (use_mutes) {
orc_prepare_volumes (self->volumes, self->mutes, nsamples);
}
2012-01-20 15:11:54 +00:00
self->process_controlled (self, map.data, self->volumes, channels,
map.size);
2012-01-20 15:11:54 +00:00
goto done;
} else if (volume_cb) {
gst_object_unref (volume_cb);
}
if (self->current_volume == 0.0 || self->current_mute) {
2012-01-20 15:11:54 +00:00
orc_memset (map.data, 0, map.size);
GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_GAP);
2010-02-13 00:08:05 +00:00
} else if (self->current_volume != 1.0) {
2012-01-20 15:11:54 +00:00
self->process (self, map.data, map.size);
}
2012-01-20 15:11:54 +00:00
done:
gst_buffer_unmap (outbuf, &map);
return GST_FLOW_OK;
/* ERRORS */
not_negotiated:
{
2010-02-13 00:08:05 +00:00
GST_ELEMENT_ERROR (self, CORE, NEGOTIATION,
("No format was negotiated"), (NULL));
return GST_FLOW_NOT_NEGOTIATED;
}
controller_failure:
{
if (mute_cb)
gst_object_unref (mute_cb);
if (volume_cb)
gst_object_unref (volume_cb);
GST_ELEMENT_ERROR (self, CORE, FAILED,
("Failed to get values from controller"), (NULL));
2012-01-20 15:11:54 +00:00
gst_buffer_unmap (outbuf, &map);
return GST_FLOW_ERROR;
}
}
static void
volume_set_property (GObject * object, guint prop_id, const GValue * value,
GParamSpec * pspec)
{
2010-02-13 00:08:05 +00:00
GstVolume *self = GST_VOLUME (object);
switch (prop_id) {
case PROP_MUTE:
2010-02-13 00:08:05 +00:00
GST_OBJECT_LOCK (self);
self->mute = g_value_get_boolean (value);
GST_OBJECT_UNLOCK (self);
break;
case PROP_VOLUME:
2010-02-13 00:08:05 +00:00
GST_OBJECT_LOCK (self);
self->volume = g_value_get_double (value);
GST_OBJECT_UNLOCK (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
volume_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
2010-02-13 00:08:05 +00:00
GstVolume *self = GST_VOLUME (object);
switch (prop_id) {
case PROP_MUTE:
2010-02-13 00:08:05 +00:00
GST_OBJECT_LOCK (self);
g_value_set_boolean (value, self->mute);
GST_OBJECT_UNLOCK (self);
break;
case PROP_VOLUME:
2010-02-13 00:08:05 +00:00
GST_OBJECT_LOCK (self);
g_value_set_double (value, self->volume);
GST_OBJECT_UNLOCK (self);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gboolean
plugin_init (GstPlugin * plugin)
{
gst_volume_orc_init ();
GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "volume", 0, "Volume gain");
/* ref class from a thread-safe context to work around missing bit of
* thread-safety in GObject */
g_type_class_ref (GST_TYPE_MIXER_TRACK);
return gst_element_register (plugin, "volume", GST_RANK_NONE,
GST_TYPE_VOLUME);
}
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"volume",
"plugin for controlling audio volume",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);