| /* 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) |
| { |
| GstElementClass *elem_class = GST_ELEMENT_CLASS (ladspa_class); |
| GstBaseSinkClass *base_class = GST_BASE_SINK_CLASS (ladspa_class); |
| |
| gst_ladspa_class_init (&ladspa_class->ladspa, |
| G_TYPE_FROM_CLASS (ladspa_class)); |
| |
| 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 = 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_register_sink_element (GstPlugin * plugin, GstStructure * ladspa_meta) |
| { |
| 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, |
| NULL, |
| sizeof (GstLADSPASink), |
| 0, |
| (GInstanceInitFunc) gst_ladspa_sink_type_init, |
| NULL |
| }; |
| ladspa_register_element (plugin, GST_TYPE_LADSPA_SINK, &info, ladspa_meta); |
| } |