af_sox with some fixes.
---
libavfilter/Makefile | 1 +
libavfilter/af_sox.c | 327 ++++++++++++++++++++++++++++++++++++++++++++++
libavfilter/allfilters.c | 1 +
3 files changed, 329 insertions(+), 0 deletions(-)
create mode 100644 libavfilter/af_sox.c
diff --git a/libavfilter/Makefile b/libavfilter/Makefile
index 920f428..4c4ec74 100644
--- a/libavfilter/Makefile
+++ b/libavfilter/Makefile
@@ -17,6 +17,7 @@ OBJS = allfilters.o \
OBJS-$(CONFIG_AFIFO_FILTER) += af_afifo.o
OBJS-$(CONFIG_NULLAUD_FILTER) += af_nullaud.o
OBJS-$(CONFIG_ASPLIT_FILTER) += af_asplit.o
+OBJS-$(CONFIG_SOX_FILTER) += af_sox.o
OBJS-$(CONFIG_ASPECT_FILTER) += vf_aspect.o
OBJS-$(CONFIG_CROP_FILTER) += vf_crop.o
diff --git a/libavfilter/af_sox.c b/libavfilter/af_sox.c
new file mode 100644
index 0000000..1cb9b94
--- /dev/null
+++ b/libavfilter/af_sox.c
@@ -0,0 +1,327 @@
+/*
+ * copyright (c) 2010 S.N. Hemanth Meenakshisundaram
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * Sox Filter
+ */
+
+#include "avfilter.h"
+#include "parseutils.h"
+#include "libavcodec/audioconvert.h"
+#include "libavutil/fifo.h"
+#include <assert.h>
+#include <sox.h>
+#include <string.h>
+
+typedef struct {
+ sox_effects_chain_t * chain; ///< handle to sox effects chain.
+ AVFifoBuffer *in_fifo; ///< fifo buffer of input audio frame pointers
+ AVFifoBuffer *out_fifo; ///< fifo buffer of output audio data from sox
+ int64_t ch_layout; ///< channel layout of data handled
+ int nb_channels; ///< number of channels in our channel layout
+ int out_size; ///< desired size of each output audio buffer
+} SoxContext;
+
+static int query_formats(AVFilterContext *ctx)
+{
+ // Sox effects only operate on signed 32-bit integer audio data.
+ enum SampleFormat sample_fmts[] = {
+ SAMPLE_FMT_S32, PIX_FMT_NONE
+ };
+
+ avfilter_set_common_formats(ctx, avfilter_make_format_list(sample_fmts));
+ return 0;
+}
+
+typedef struct {
+ SoxContext *lavfi_ctx;
+} sox_inout_ctx;
+
+// configures the sox effect for sample input.
+static int inout_config_opts(sox_effect_t * effp, int argc, char **argv)
+{
+ SoxContext *sox;
+ if (argc < 2) {
+ lsx_fail("lavfi context not supplied");
+ return (SOX_EOF);
+ }
+ sscanf(argv[1], "%ld", (long int *)&sox);
+ ((sox_inout_ctx *)effp->priv)->lavfi_ctx = sox;
+ return SOX_SUCCESS;
+}
+
+/**
+ * a sox effect handler to handle input of samples to the effects chain.
+ * The function that will be called to input samples into the effects chain.
+ */
+static int input_drain(sox_effect_t *effp,
+ sox_sample_t *obuf, size_t * osamp) {
+
+ SoxContext *sox = ((sox_inout_ctx *)effp->priv)->lavfi_ctx;
+ AVFilterBufferRef *samplesref;
+ int input_nb_samples = 0;
+
+ if (!av_fifo_size(sox->in_fifo)) {
+ av_log(sox, AV_LOG_DEBUG,
+ "sox chain requested audio data when none available, sending silence!\n");
+ memset(obuf, 0, *osamp);
+ return SOX_SUCCESS;
+ }
+
+ // read first audio frame from queued input buffers and give it to sox.
+ av_fifo_generic_read(sox->in_fifo, &samplesref, sizeof(samplesref), NULL);
+
+ /**
+ * inside lavfi, nb_samples is number of samples in each channel, while in sox
+ * number of samples refers to the total number over all channels
+ */
+ input_nb_samples = samplesref->audio->samples_nb * sox->nb_channels;
+
+ // ensure that *osamp is a multiple of the number of channels.
+ *osamp -= *osamp % sox->nb_channels;
+
+ /**
+ * FIXME: Right now, if sox chain accepts fewer samples than in one buffer, we drop
+ * remaining data. We should be taking the required data and preserving the rest.
+ * Luckily, this is highly unlikely.
+ */
+ if (*osamp < input_nb_samples)
+ input_nb_samples = *osamp;
+
+ memcpy(obuf, samplesref->data[0], input_nb_samples*sizeof(int));
+ *osamp = input_nb_samples;
+
+ avfilter_unref_buffer(samplesref);
+ return SOX_SUCCESS;
+}
+
+/**
+ * a sox effect handler to handle output of samples to the effects chain.
+ * The function that will be called to output samples from the effects chain.
+ */
+static int output_flow(sox_effect_t *effp UNUSED, sox_sample_t const * ibuf,
+ sox_sample_t * obuf UNUSED, size_t * isamp, size_t * osamp)
+{
+
+ SoxContext *sox = ((sox_inout_ctx *)effp->priv)->lavfi_ctx;
+
+ // If our fifo runs out of space, we just drop this frame and keep going.
+ if (av_fifo_space(sox->out_fifo) < *isamp * sizeof(int)) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Buffering limit reached. Sox output data being dropped.\n");
+ return SOX_SUCCESS;
+ }
+
+ av_fifo_generic_write(sox->out_fifo, (void *)ibuf, *isamp, NULL);
+
+ // Set *osamp to 0 since this is the last effect of the sox chain.
+ *osamp = 0;
+
+ return SOX_SUCCESS; // All samples output successfully.
+}
+
+static sox_effect_handler_t const * input_handler(void)
+{
+ static sox_effect_handler_t handler = {
+ "input", NULL, SOX_EFF_MCHAN, inout_config_opts, NULL, NULL,
+ input_drain, NULL, NULL, sizeof(SoxContext *)
+ };
+ return &handler;
+}
+
+// a sox effect handler to handle output of samples from the effects chain.
+static sox_effect_handler_t const * output_handler(void)
+{
+ static sox_effect_handler_t handler = {
+ "output", NULL, SOX_EFF_MCHAN, inout_config_opts, NULL,
+ output_flow, NULL, NULL, NULL, 0
+ };
+ return &handler;
+}
+
+#define MAX_EFFECT_ARGS 10
+#define INFIFO_SIZE 8
+#define OUTFIFO_SIZE 8192
+#define OUT_FRAME_SIZE 1024
+
+static inline int add_effect_and_setopts(AVFilterContext *ctx, char *effect_str, sox_signalinfo_t *signal)
+{
+ SoxContext *sox = ctx->priv;
+ int nargs = -1, err = 0;
+ char *effect = NULL, *args[MAX_EFFECT_ARGS];
+ sox_effect_t *e = NULL;
+
+ effect = strtok(effect_str, " ");
+ e = sox_create_effect(sox_find_effect(effect));
+ if (!e) {
+ av_log(ctx, AV_LOG_ERROR, "No such sox effect: '%s'.\n", effect);
+ return AVERROR(EINVAL);
+ }
+
+ while (args[nargs++] = strtok(NULL, " "))
+ ;
+ if ((err = sox_add_effect(sox->chain, e, signal, signal)) != SOX_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "Sox error: '%s'.\n", sox_strerror(err));
+ return AVERROR(EINVAL);
+ }
+ if ((err = sox_effect_options(e, nargs, args)) != SOX_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "Sox error: '%s'.\n", sox_strerror(err));
+ return AVERROR(EINVAL);
+ }
+
+ return 0;
+}
+
+static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
+{
+ SoxContext *sox = ctx->priv;
+ sox_effects_chain_t * chain;
+ sox_effect_t *e = NULL;
+ unsigned int bits_per_sample = 32;
+ sox_encodinginfo_t enc = {SOX_DEFAULT_ENCODING, bits_per_sample,
+ 0.0, 0, 0, 0, 0};
+ sox_signalinfo_t in_signal_info = {SOX_UNSPEC};
+ char *token = NULL, param[10], *ioargs[] = {param}, *cpargs = av_strdup(args);
+ int err = 0;
+
+ if ((err = sox_init()) != SOX_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "Sox error: '%s'.\n", sox_strerror(err));
+ return AVERROR(EINVAL);
+ }
+
+ chain = sox_create_effects_chain(&enc, &enc);
+ sox->chain = chain;
+
+ snprintf(param, sizeof(param), "%ld", (long int)sox);
+ // Set up the audio buffer source as first effect of the chain.
+ e = sox_create_effect(input_handler());
+ if ((err = sox_add_effect(chain, e, &in_signal_info, &in_signal_info)) != SOX_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "Sox error: '%s'.\n", sox_strerror(err));
+ return AVERROR(EINVAL);
+ }
+ if ((err = sox_effect_options(e, 1, ioargs)) != SOX_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "Sox error: '%s'.\n", sox_strerror(err));
+ return AVERROR(EINVAL);
+ }
+
+ token = strtok (cpargs, ":");
+ while (token) {
+ if ((err = add_effect_and_setopts(ctx, token, &in_signal_info))) {
+ av_log(ctx, AV_LOG_ERROR, "Invalid sox argument: '%s'.\n", token);
+ return err;
+ }
+ token = strtok (NULL, ":");
+ }
+
+ e = sox_create_effect(output_handler());
+ if ((err = sox_add_effect(chain, e, &in_signal_info, &in_signal_info)) != SOX_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "Sox error: '%s'.\n", sox_strerror(err));
+ return AVERROR(EINVAL);
+ }
+ if ((err = sox_effect_options(e, 1, ioargs)) != SOX_SUCCESS) {
+ av_log(ctx, AV_LOG_ERROR, "Sox error: '%s'.\n", sox_strerror(err));
+ return AVERROR(EINVAL);
+ }
+
+ sox->in_fifo = av_fifo_alloc(INFIFO_SIZE*sizeof(AVFilterBufferRef*));
+ // the output data fifo stores samples in sox's native s32 integer format.
+ sox->out_size = OUT_FRAME_SIZE; // FIXME: Make this configurable;
+ sox->out_fifo = av_fifo_alloc(OUTFIFO_SIZE*sizeof(int));
+ return 0;
+}
+
+static av_cold void uninit(AVFilterContext *ctx)
+{
+ SoxContext *sox = ctx->priv;
+ sox_quit();
+ av_fifo_free(sox->in_fifo);
+ av_fifo_free(sox->out_fifo);
+}
+
+static int config_input(AVFilterLink *link)
+{
+ SoxContext *sox = link->dst->priv;
+
+ if (link->format != SAMPLE_FMT_S32) {
+ av_log(link->dst, AV_LOG_ERROR, "Sox needs signed 32-bit input samples, insert resample filter.");
+ return AVERROR(EINVAL);
+ }
+ // store channel layout and number of channels, insert resample filter to keep this constant.
+ sox->ch_layout = link->channel_layout;
+ sox->nb_channels = avcodec_channel_layout_num_channels(link->channel_layout);
+
+ return 0;
+}
+
+static void filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
+{
+ SoxContext *sox = link->dst->priv;
+
+ if (av_fifo_space(sox->in_fifo) < sizeof(samplesref)) {
+ av_log(NULL, AV_LOG_ERROR,
+ "Buffering limit reached. Please allow sox to consume some available frames before adding new ones.\n");
+ return;
+ }
+
+ av_fifo_generic_write(sox->in_fifo, &samplesref, sizeof(samplesref), NULL);
+
+ return;
+}
+
+static int request_frame(AVFilterLink *link)
+{
+ SoxContext *sox = link->src->priv;
+ AVFilterBufferRef *samplesref;
+
+ if (!av_fifo_size(sox->out_fifo)) {
+ av_log(link->src, AV_LOG_ERROR,
+ "request_frame() called with no available data from sox!\n");
+ }
+
+ // libsox uses packed audio data internally.
+ samplesref = avfilter_get_audio_buffer(link, AV_PERM_WRITE, SAMPLE_FMT_S32,
+ sox->out_size, sox->ch_layout, 0);
+
+ av_fifo_generic_read(sox->out_fifo, samplesref->data[0], sox->out_size, NULL);
+ filter_samples(link, samplesref);
+ return 0;
+}
+
+AVFilter avfilter_af_sox = {
+ .name = "sox",
+ .description = NULL_IF_CONFIG_SMALL("Draw text on top of audio frames using libfreetype library."),
+ .priv_size = sizeof(SoxContext),
+ .init = init,
+ .uninit = uninit,
+
+ .query_formats = query_formats,
+ .inputs = (AVFilterPad[]) {{ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .get_audio_buffer = avfilter_null_get_audio_buffer,
+ .filter_samples = avfilter_null_start_frame,
+ .config_props = config_input,
+ .min_perms = AV_PERM_READ },
+ { .name = NULL}},
+ .outputs = (AVFilterPad[]) {{ .name = "default",
+ .type = AVMEDIA_TYPE_AUDIO,
+ .request_frame = request_frame, },
+ { .name = NULL}},
+};
diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c
index 3d86947..df7e7ca 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -37,6 +37,7 @@ void avfilter_register_all(void)
REGISTER_FILTER (AFIFO, afifo, af);
REGISTER_FILTER (NULLAUD, nullaud, af);
REGISTER_FILTER (ASPLIT, asplit, af);
+ REGISTER_FILTER (SOX, sox, af);
REGISTER_FILTER (ASPECT, aspect, vf);
REGISTER_FILTER (CROP, crop, vf);
_______________________________________________
FFmpeg-soc mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/ffmpeg-soc