mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-24 10:41:04 +00:00
386 lines
11 KiB
C
386 lines
11 KiB
C
/* GStreamer LADSPA sink category
|
|
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
|
* 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
|
|
* 2003 Andy Wingo <wingo at pobox.com>
|
|
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com> (fakesink)
|
|
* Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.com>
|
|
*
|
|
* 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., 51 Franklin St, Fifth Floor,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "gstladspasink.h"
|
|
#include "gstladspa.h"
|
|
#include "gstladspautils.h"
|
|
#include <gst/base/gstbasetransform.h>
|
|
|
|
#include <string.h>
|
|
|
|
GST_DEBUG_CATEGORY_EXTERN (ladspa_debug);
|
|
#define GST_CAT_DEFAULT ladspa_debug
|
|
|
|
#define GST_LADSPA_SINK_CLASS_TAGS "Sink/Audio/LADSPA"
|
|
#define GST_LADSPA_SINK_DEFAULT_SYNC TRUE
|
|
#define GST_LADSPA_SINK_DEFAULT_CAN_ACTIVATE_PUSH TRUE
|
|
#define GST_LADSPA_SINK_DEFAULT_CAN_ACTIVATE_PULL FALSE
|
|
#define GST_LADSPA_SINK_DEFAULT_NUM_BUFFERS -1
|
|
|
|
enum
|
|
{
|
|
GST_LADSPA_SINK_PROP_0,
|
|
GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PUSH,
|
|
GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PULL,
|
|
GST_LADSPA_SINK_PROP_NUM_BUFFERS,
|
|
GST_LADSPA_SINK_PROP_LAST
|
|
};
|
|
|
|
static GstLADSPASinkClass *gst_ladspa_sink_type_parent_class = NULL;
|
|
|
|
/*
|
|
* Boilerplates BaseSink add pad.
|
|
*/
|
|
void
|
|
gst_my_base_sink_class_add_pad_template (GstBaseSinkClass * base_class,
|
|
GstCaps * sinkcaps)
|
|
{
|
|
GstElementClass *elem_class = GST_ELEMENT_CLASS (base_class);
|
|
GstPadTemplate *pad_template;
|
|
|
|
g_return_if_fail (GST_IS_CAPS (sinkcaps));
|
|
|
|
pad_template =
|
|
gst_pad_template_new (GST_BASE_TRANSFORM_SINK_NAME, GST_PAD_SINK,
|
|
GST_PAD_ALWAYS, sinkcaps);
|
|
gst_element_class_add_pad_template (elem_class, pad_template);
|
|
}
|
|
|
|
static gboolean
|
|
gst_ladspa_sink_type_set_caps (GstBaseSink * base, GstCaps * caps)
|
|
{
|
|
GstLADSPASink *ladspa = GST_LADSPA_SINK (base);
|
|
GstAudioInfo info;
|
|
|
|
if (!gst_audio_info_from_caps (&info, caps)) {
|
|
GST_ERROR_OBJECT (base, "received invalid caps");
|
|
return FALSE;
|
|
}
|
|
|
|
GST_DEBUG_OBJECT (ladspa, "negotiated to caps %" GST_PTR_FORMAT, caps);
|
|
|
|
ladspa->info = info;
|
|
|
|
return gst_ladspa_setup (&ladspa->ladspa, GST_AUDIO_INFO_RATE (&info));
|
|
}
|
|
|
|
static gboolean
|
|
gst_ladspa_sink_type_query (GstBaseSink * base, GstQuery * query)
|
|
{
|
|
gboolean ret;
|
|
|
|
switch (GST_QUERY_TYPE (query)) {
|
|
case GST_QUERY_SEEKING:{
|
|
GstFormat fmt;
|
|
|
|
/* we don't supporting seeking */
|
|
gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
|
|
gst_query_set_seeking (query, fmt, FALSE, 0, -1);
|
|
ret = TRUE;
|
|
break;
|
|
}
|
|
default:
|
|
ret =
|
|
GST_BASE_SINK_CLASS (gst_ladspa_sink_type_parent_class)->query
|
|
(base, query);
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_ladspa_sink_type_preroll (GstBaseSink * base, GstBuffer * buffer)
|
|
{
|
|
GstLADSPASink *ladspa = GST_LADSPA_SINK (base);
|
|
|
|
if (ladspa->num_buffers_left == 0) {
|
|
GST_DEBUG_OBJECT (ladspa, "we are EOS");
|
|
return GST_FLOW_EOS;
|
|
}
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_ladspa_sink_type_render (GstBaseSink * base, GstBuffer * buf)
|
|
{
|
|
GstLADSPASink *ladspa = GST_LADSPA_SINK (base);
|
|
GstMapInfo info;
|
|
|
|
if (ladspa->num_buffers_left == 0)
|
|
goto eos;
|
|
|
|
if (ladspa->num_buffers_left != -1)
|
|
ladspa->num_buffers_left--;
|
|
|
|
gst_object_sync_values (GST_OBJECT (ladspa), GST_BUFFER_TIMESTAMP (buf));
|
|
|
|
gst_buffer_map (buf, &info, GST_MAP_READ);
|
|
gst_ladspa_transform (&ladspa->ladspa, NULL,
|
|
info.size / sizeof (LADSPA_Data) / ladspa->ladspa.klass->count.audio.in,
|
|
info.data);
|
|
gst_buffer_unmap (buf, &info);
|
|
|
|
if (ladspa->num_buffers_left == 0)
|
|
goto eos;
|
|
|
|
return GST_FLOW_OK;
|
|
|
|
/* ERRORS */
|
|
eos:
|
|
{
|
|
GST_DEBUG_OBJECT (ladspa, "we are EOS");
|
|
return GST_FLOW_EOS;
|
|
}
|
|
}
|
|
|
|
static GstStateChangeReturn
|
|
gst_ladspa_sink_type_change_state (GstElement * element,
|
|
GstStateChange transition)
|
|
{
|
|
GstLADSPASink *ladspa = GST_LADSPA_SINK (element);
|
|
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
|
|
|
|
switch (transition) {
|
|
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
ladspa->num_buffers_left = ladspa->num_buffers;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ret =
|
|
GST_ELEMENT_CLASS (gst_ladspa_sink_type_parent_class)->change_state
|
|
(element, transition);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static void
|
|
gst_ladspa_sink_type_set_property (GObject * object, guint prop_id,
|
|
const GValue * value, GParamSpec * pspec)
|
|
{
|
|
GstLADSPASink *ladspa = GST_LADSPA_SINK (object);
|
|
|
|
switch (prop_id) {
|
|
case GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PUSH:
|
|
GST_BASE_SINK (ladspa)->can_activate_push = g_value_get_boolean (value);
|
|
break;
|
|
case GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PULL:
|
|
GST_BASE_SINK (ladspa)->can_activate_pull = g_value_get_boolean (value);
|
|
break;
|
|
case GST_LADSPA_SINK_PROP_NUM_BUFFERS:
|
|
ladspa->num_buffers = g_value_get_int (value);
|
|
break;
|
|
default:
|
|
gst_ladspa_object_set_property (&ladspa->ladspa, object, prop_id, value,
|
|
pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_ladspa_sink_type_get_property (GObject * object, guint prop_id,
|
|
GValue * value, GParamSpec * pspec)
|
|
{
|
|
GstLADSPASink *ladspa = GST_LADSPA_SINK (object);
|
|
|
|
switch (prop_id) {
|
|
case GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PUSH:
|
|
g_value_set_boolean (value, GST_BASE_SINK (ladspa)->can_activate_push);
|
|
break;
|
|
case GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PULL:
|
|
g_value_set_boolean (value, GST_BASE_SINK (ladspa)->can_activate_pull);
|
|
break;
|
|
case GST_LADSPA_SINK_PROP_NUM_BUFFERS:
|
|
g_value_set_int (value, ladspa->num_buffers);
|
|
break;
|
|
default:
|
|
gst_ladspa_object_get_property (&ladspa->ladspa, object, prop_id, value,
|
|
pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_ladspa_sink_type_init (GstLADSPASink * ladspa, LADSPA_Descriptor * desc)
|
|
{
|
|
GstLADSPASinkClass *ladspa_class = GST_LADSPA_SINK_GET_CLASS (ladspa);
|
|
GstBaseSink *base = GST_BASE_SINK (ladspa);
|
|
|
|
gst_ladspa_init (&ladspa->ladspa, &ladspa_class->ladspa);
|
|
|
|
ladspa->num_buffers = GST_LADSPA_SINK_DEFAULT_NUM_BUFFERS;
|
|
|
|
gst_base_sink_set_sync (base, GST_LADSPA_SINK_DEFAULT_SYNC);
|
|
}
|
|
|
|
static void
|
|
gst_ladspa_sink_type_dispose (GObject * object)
|
|
{
|
|
GstLADSPASink *ladspa = GST_LADSPA_SINK (object);
|
|
|
|
gst_ladspa_cleanup (&ladspa->ladspa);
|
|
|
|
G_OBJECT_CLASS (gst_ladspa_sink_type_parent_class)->dispose (object);
|
|
}
|
|
|
|
static void
|
|
gst_ladspa_sink_type_finalize (GObject * object)
|
|
{
|
|
GstLADSPASink *ladspa = GST_LADSPA_SINK (object);
|
|
|
|
gst_ladspa_finalize (&ladspa->ladspa);
|
|
|
|
G_OBJECT_CLASS (gst_ladspa_sink_type_parent_class)->finalize (object);
|
|
}
|
|
|
|
/*
|
|
* It is okay for plugins to 'leak' a one-time allocation. This will be freed when
|
|
* the application exits. When the plugins are scanned for the first time, this is
|
|
* done from a separate process to not impose the memory overhead on the calling
|
|
* application (among other reasons). Hence no need for class_finalize.
|
|
*/
|
|
static void
|
|
gst_ladspa_sink_type_base_init (GstLADSPASinkClass * ladspa_class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (ladspa_class);
|
|
GstElementClass *elem_class = GST_ELEMENT_CLASS (ladspa_class);
|
|
GstBaseSinkClass *base_class = GST_BASE_SINK_CLASS (ladspa_class);
|
|
LADSPA_Descriptor *desc;
|
|
|
|
desc =
|
|
g_type_get_qdata (G_OBJECT_CLASS_TYPE (object_class), descriptor_quark);
|
|
g_assert (desc);
|
|
|
|
gst_ladspa_class_init (&ladspa_class->ladspa, desc);
|
|
|
|
gst_ladspa_element_class_set_metadata (&ladspa_class->ladspa, elem_class,
|
|
GST_LADSPA_SINK_CLASS_TAGS);
|
|
|
|
gst_ladspa_sink_type_class_add_pad_template (&ladspa_class->ladspa,
|
|
base_class);
|
|
}
|
|
|
|
|
|
static void
|
|
gst_ladspa_sink_type_base_finalize (GstLADSPASinkClass * ladspa_class)
|
|
{
|
|
gst_ladspa_class_finalize (&ladspa_class->ladspa);
|
|
}
|
|
|
|
static void
|
|
gst_ladspa_sink_type_class_init (GstLADSPASinkClass * ladspa_class,
|
|
LADSPA_Descriptor * desc)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (ladspa_class);
|
|
GstElementClass *elem_class = GST_ELEMENT_CLASS (ladspa_class);
|
|
GstBaseSinkClass *base_class = base_class =
|
|
GST_BASE_SINK_CLASS (ladspa_class);
|
|
|
|
gst_ladspa_sink_type_parent_class = g_type_class_peek_parent (ladspa_class);
|
|
|
|
object_class->dispose = GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_dispose);
|
|
object_class->finalize = GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_finalize);
|
|
object_class->set_property =
|
|
GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_set_property);
|
|
object_class->get_property =
|
|
GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_get_property);
|
|
|
|
elem_class->change_state =
|
|
GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_change_state);
|
|
|
|
base_class->set_caps = GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_set_caps);
|
|
base_class->preroll = GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_preroll);
|
|
base_class->render = GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_render);
|
|
base_class->query = GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_query);
|
|
|
|
g_object_class_install_property (object_class,
|
|
GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PUSH,
|
|
g_param_spec_boolean ("can-activate-push", "Can activate push",
|
|
"Can activate in push mode",
|
|
GST_LADSPA_SINK_DEFAULT_CAN_ACTIVATE_PUSH,
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (object_class,
|
|
GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PULL,
|
|
g_param_spec_boolean ("can-activate-pull", "Can activate pull",
|
|
"Can activate in pull mode",
|
|
GST_LADSPA_SINK_DEFAULT_CAN_ACTIVATE_PULL,
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
g_object_class_install_property (object_class,
|
|
GST_LADSPA_SINK_PROP_NUM_BUFFERS, g_param_spec_int ("num-buffers",
|
|
"num-buffers", "Number of buffers to accept going EOS", -1, G_MAXINT,
|
|
GST_LADSPA_SINK_DEFAULT_NUM_BUFFERS,
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
|
|
gst_ladspa_object_class_install_properties (&ladspa_class->ladspa,
|
|
object_class, GST_LADSPA_SINK_PROP_LAST);
|
|
|
|
}
|
|
|
|
G_DEFINE_ABSTRACT_TYPE (GstLADSPASink, gst_ladspa_sink, GST_TYPE_BASE_SINK);
|
|
|
|
static void
|
|
gst_ladspa_sink_init (GstLADSPASink * ladspa)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gst_ladspa_sink_class_init (GstLADSPASinkClass * ladspa_class)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* Construct the type.
|
|
*/
|
|
void
|
|
ladspa_describe_sink_plugin (GstPlugin * plugin,
|
|
const gchar * filename, const LADSPA_Descriptor * desc)
|
|
{
|
|
GTypeInfo info = {
|
|
sizeof (GstLADSPASinkClass),
|
|
(GBaseInitFunc) gst_ladspa_sink_type_base_init,
|
|
(GBaseFinalizeFunc) gst_ladspa_sink_type_base_finalize,
|
|
(GClassInitFunc) gst_ladspa_sink_type_class_init,
|
|
NULL,
|
|
desc,
|
|
sizeof (GstLADSPASink),
|
|
0,
|
|
(GInstanceInitFunc) gst_ladspa_sink_type_init,
|
|
NULL
|
|
};
|
|
gchar *tmp;
|
|
|
|
tmp = g_strdup_printf ("ladspasink-%s-%s", filename, desc->Label);
|
|
ladspa_register_plugin (plugin, GST_TYPE_LADSPA_SINK, tmp, &info,
|
|
descriptor_quark, filename, desc);
|
|
g_free (tmp);
|
|
}
|