[MPlayer-dev-eng] [PATCH] af_scale* command-line only
Robert Juliano
juliano.1 at osu.edu
Wed Jun 13 06:50:47 CEST 2007
Thanks for the feedback Reimar and Diego. I incorporated
most of your suggestions.
Here are just the filters (no interactivity and not tied to
playback_speed). This patch only changes files in libaf and
then just enough to enable the filters. This should be easier
to test and allow those in PAL-land to have the audio play
at a different tempo than the video (why they would want that,
I dunno know).
Usage:
mplayer -af scaletempo=1.25 -speed 1.25 ...
mplayer -af scalerate=.8 -speed=.8 ...
mplayer -af scalepitch=1.5 ...
As for performance, chaining five instances of scaletempo on
my Athlon XP 3200, uses roughly 10% of the CPU. The WSOLA
technique does little more then selectively skip forward/backward
overlapping each skip. No DSP or FFT number crunching. And
it produces quite decent results.
Enjoy.
Files:
A libaf/af_scaletempo.c
A libaf/af_scalerate.c
A libaf/af_scalepitch.c
M libaf/Makefile
M libaf/control.h
M libaf/af.c
M libaf/af.h
Index: libaf/af_scalerate.c
===================================================================
--- libaf/af_scalerate.c (revision 0)
+++ libaf/af_scalerate.c (revision 0)
@@ -0,0 +1,131 @@
+/*
+ * scalerate audio filter
+ * (cc) GPL 2007 MPlayer / Robert Juliano
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer 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 MPlayer; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * scale rate (both time and tempo) (i.e. chipmunk effect)
+ *
+ * basic technique:
+ * pretend input rate is scaled rate and resample to input rate
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "af.h"
+
+#ifdef USE_LIBAVCODEC
+ #define RESAMPLER "lavcresample"
+#else
+ #define RESAMPLER "resample"
+#endif
+
+// Data for specific instances of this filter
+typedef struct af_scalerate_s
+{
+ af_instance_t* resampler;
+ float scale;
+} af_scalerate_t;
+
+// Initialization and runtime control
+static int control(struct af_instance_s* af, int cmd, void* arg)
+{
+ af_scalerate_t* s = af->setup;
+ af_instance_t* resampler = s->resampler;
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ af_data_t* c = (af_data_t*)arg;
+ int base_rate;
+ int rv;
+
+ base_rate = c->rate;
+ resampler->control(resampler, AF_CONTROL_RESAMPLE_RATE, &base_rate);
+ c->rate = base_rate * s->scale;
+ if (AF_OK != (rv = resampler->control(resampler, AF_CONTROL_REINIT, c)))
+ return rv;
+ c->rate = base_rate;
+ af->data = resampler->data;
+ af->mul.n = resampler->mul.n;
+ af->mul.d = resampler->mul.d;
+ af->delay = resampler->delay;
+
+ return af_test_output(af,(af_data_t*)arg);
+ }
+ case AF_CONTROL_SCALERATE_AMOUNT | AF_CONTROL_SET:
+ s->scale = *(float*)arg;
+ return AF_OK;
+ case AF_CONTROL_SCALERATE_AMOUNT | AF_CONTROL_GET:
+ *(float*)arg = s->scale;
+ return AF_OK;
+ case AF_CONTROL_COMMAND_LINE:{
+ float f;
+ sscanf((char*)arg,"%f", &f);
+ return control(af, AF_CONTROL_SCALERATE_AMOUNT | AF_CONTROL_SET, &f);
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance_s* af)
+{
+ af_scalerate_t* s = af->setup;
+ s->resampler->uninit(s->resampler);
+ free(s->resampler);
+ free(af->setup);
+}
+
+// Filter data through filter
+static af_data_t* play(struct af_instance_s* af, af_data_t* data)
+{
+ af_scalerate_t* s = af->setup;
+ return s->resampler->play(s->resampler, data);
+}
+
+// Allocate memory and set function pointers
+static int af_open(af_instance_t* af){
+ af_scalerate_t* s;
+
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul.d=1;
+ af->mul.n=1;
+ af->setup=calloc(1,sizeof(af_scalerate_t));
+ if(af->setup == NULL)
+ return AF_ERROR;
+
+ s = af->setup;
+ s->resampler = af_create(af->stream, RESAMPLER);
+ if (!s->resampler)
+ return AF_ERROR;
+
+ return AF_OK;
+}
+
+// Description of this filter
+af_info_t af_info_scalerate = {
+ "Scales audio rate (both pitch and tempo) (i.e. chipmunk effect)",
+ "scalerate",
+ "Robert Juliano",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
Index: libaf/control.h
===================================================================
--- libaf/control.h (revision 23550)
+++ libaf/control.h (working copy)
@@ -229,4 +229,9 @@
#define AF_CONTROL_SS_FREQ 0x00002300 | AF_CONTROL_FILTER_SPECIFIC
#define AF_CONTROL_SS_DECAY 0x00002400 | AF_CONTROL_FILTER_SPECIFIC
+// Percentage to scale tempo, rate, or pitch
+#define AF_CONTROL_SCALETEMPO_AMOUNT 0x00002500 | AF_CONTROL_FILTER_SPECIFIC
+#define AF_CONTROL_SCALERATE_AMOUNT 0x00002600 | AF_CONTROL_FILTER_SPECIFIC
+#define AF_CONTROL_SCALEPITCH_AMOUNT 0x00002700 | AF_CONTROL_FILTER_SPECIFIC
+
#endif /*__af_control_h */
Index: libaf/Makefile
===================================================================
--- libaf/Makefile (revision 23550)
+++ libaf/Makefile (working copy)
@@ -16,6 +16,9 @@
af_karaoke.c \
af_pan.c \
af_resample.c \
+ af_scalepitch.c \
+ af_scalerate.c \
+ af_scaletempo.c \
af_sinesuppress.c \
af_sub.c \
af_surround.c \
Index: libaf/af_scaletempo.c
===================================================================
--- libaf/af_scaletempo.c (revision 0)
+++ libaf/af_scaletempo.c (revision 0)
@@ -0,0 +1,303 @@
+/*
+ * scaletempo audio filter
+ * (cc) GPL 2007 MPlayer / Robert Juliano
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer 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 MPlayer; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * scale tempo while maintaining pitch
+ * (WSOLA technique with cross correlation)
+ * inspired by SoundTouch library by Olli Parviainen
+ *
+ * basic algorithm
+ * - produce 'stride' output samples per loop
+ * - consume stride*speed input samples per loop
+ *
+ * to produce smoother transitions between strides, blend next ns_overlap
+ * samples from last stride with correlated samples of current input
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "af.h"
+
+#define AOF(a, i) &(((float *)a)[i])
+
+// Data for specific instances of this filter
+typedef struct af_scaletempo_s
+{
+ float scale;
+ int np_window;
+ int np_overlap;
+ int np_seek;
+ int ns_stride;
+ float ns_stride_scaled;
+ float ns_stride_error;
+ int ns_standing;
+ int ns_min_win;
+ float* buf_win;
+ int ns_win; // number of samples in window buffer
+ int ns_towin; // number of samples until next window
+ float* buf_ovl;
+ float* buf_calc; // reusable memory for best_overlap_calculation
+} af_scaletempo_t;
+
+int fill_window(struct af_instance_s* af, af_data_t* c, int ic) {
+ af_scaletempo_t* s = af->setup;
+ int ns_in = c->len/c->bps - ic;
+ int ic0 = ic;
+ int bps = af->data->bps;
+ float* win = s->buf_win;
+
+ // skip
+ if (s->ns_towin > 0) {
+ if (s->ns_towin < s->ns_win) {
+ int ns_tomove = s->ns_win - s->ns_towin;
+ memmove(win, &win[s->ns_towin], ns_tomove * bps);
+ s->ns_win = ns_tomove;
+ s->ns_towin = 0;
+ } else {
+ int ns_toskip;
+ s->ns_towin -= s->ns_win;
+ ns_toskip = min(s->ns_towin, ns_in);
+ s->ns_towin -= ns_toskip;
+ ic += ns_toskip;
+ ns_in -= ns_toskip;
+ s->ns_win = 0;
+ }
+ }
+
+ // copy
+ if (ns_in > 0) {
+ int ns_tocopy = min(s->ns_min_win - s->ns_win, ns_in);
+ memcpy(win + s->ns_win, AOF(c->audio, ic), ns_tocopy*bps);
+ s->ns_win += ns_tocopy;
+ ic += ns_tocopy;
+ ns_in -= ns_tocopy;
+ }
+
+ return ic - ic0;
+}
+
+int best_overlap_off(struct af_instance_s* af) {
+ af_scaletempo_t* s = af->setup;
+
+ int np_off = 0;
+ float best_corr = INT_MIN;
+ register int i, j, io, iw;
+ int ib, is;
+
+ int nch = af->data->nch;
+ int np_overlap = s->np_overlap;
+ int ns_overlap = np_overlap * nch;
+ int np_seek = s->np_seek;
+
+ float* win = s->buf_win;
+ float* ovl = s->buf_ovl;
+ float* calc = s->buf_calc;
+
+ // precalc
+ for (i=0, io=0; i<np_overlap; i++) {
+ float t = i * (np_overlap - i);
+ for (j=0; j<nch; j++, io++) {
+ calc[io] = ovl[io] * t;
+ }
+ }
+
+ for (i=0, is=0; i<np_seek; i++, is += nch) {
+ float corr = 0;
+ iw = is;
+ for (ib=0; ib<ns_overlap; ib++, iw++) {
+ corr += calc[ib] * win[iw];
+ }
+
+ if (corr > best_corr) {
+ best_corr = corr;
+ np_off = i;
+ }
+ }
+
+ return np_off * nch;
+}
+
+// Filter data through filter
+static af_data_t* play(struct af_instance_s* af, af_data_t* data)
+{
+ af_scaletempo_t* s = af->setup;
+ af_data_t* c = data; // Current working data
+ af_data_t* l = af->data; // Local data
+ int ns_in = c->len/c->bps; // Length of input in samples
+ int nch = c->nch; // Number of channels
+ int bps = c->bps; // bytes per sample
+ int ic, il;
+ int nb_out;
+
+ // RESIZE_LOCAL_BUFFER - can't use macro
+ // number of strides in input * size of output stride
+ nb_out = (int) ((ns_in / s->ns_stride_scaled + 1) * s->ns_stride * bps + 1);
+ if (nb_out > l->len) {
+ af_msg(AF_MSG_VERBOSE,"[libaf] Reallocating memory in module %s, "
+ "old len = %i, new len = %i\n",af->info->name,l->len,nb_out);
+ l->audio = realloc(l->audio, nb_out);
+ if (!l->audio) {
+ af_msg(AF_MSG_FATAL, "[libaf] Could not allocate memory\n");
+ return NULL;
+ }
+ l->len = nb_out;
+ }
+
+ ic = 0;
+ il = 0;
+ ic = fill_window(af, c, 0);
+ while (s->ns_win >= s->ns_min_win) {
+ int io, iw;
+ float tf;
+ float ti;
+ register int i, j;
+
+ int ns_off = best_overlap_off(af);
+
+ // output overlap
+ for (i=0, io=0, iw=ns_off; i<s->np_overlap; i++) {
+ float t = i / (float)s->np_overlap;
+ for (j=0; j<nch; j++, il++, io++, iw++) {
+ ((float *)l->audio)[il] = (1 - t) * s->buf_ovl[io] + t * s->buf_win[iw];
+ }
+ }
+
+ // output standing
+ iw = ns_off + s->np_overlap * af->data->nch;
+ memcpy(AOF(l->audio, il), AOF(s->buf_win, iw), s->ns_standing*bps);
+ il += s->ns_standing;
+
+ // input stride
+ tf = s->ns_stride_scaled + s->ns_stride_error;
+ ti = (int)(tf + .5);
+ s->ns_stride_error = tf - ti;
+ s->ns_towin = ti;
+
+ // update overlap buffer
+ io = ns_off + s->ns_stride;
+ memcpy(s->buf_ovl, AOF(s->buf_win, io), s->np_overlap*nch*bps);
+
+ ic += fill_window(af, c, ic);
+ }
+
+ c->audio = l->audio;
+ c->len = il*bps;
+ return c;
+}
+
+// Initialization and runtime control
+static int control(struct af_instance_s* af, int cmd, void* arg)
+{
+ af_scaletempo_t* s = af->setup;
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ af_data_t* c = (af_data_t*)arg;
+ float srate = c->rate / 1000;
+ int nch = c->nch;
+
+ af->data->rate = c->rate;
+ af->data->nch = nch;
+ af->data->format = AF_FORMAT_FLOAT_NE;
+ af->data->bps = 4;
+
+ // set through experimentation - same as SoundTouch
+ s->np_seek = srate * 14;
+ s->np_window = srate * 82;
+ s->np_overlap = srate * 12;
+
+ s->ns_stride = (s->np_window - s->np_overlap) * nch;
+ s->ns_stride_scaled = s->ns_stride * s->scale;
+ s->ns_standing = s->ns_stride - s->np_overlap * nch;
+ s->ns_min_win = (s->np_seek + s->np_window) * nch;
+
+ af->mul.n = s->ns_stride;
+ af->mul.d = s->ns_stride_scaled;
+ af_frac_cancel(&af->mul);
+
+ s->buf_win = realloc(s->buf_win, s->ns_min_win * sizeof(float));
+ s->buf_ovl = realloc(s->buf_ovl, s->np_overlap * nch * sizeof(float));
+ s->buf_calc = realloc(s->buf_calc, s->np_overlap * nch * sizeof(float));
+ if(!s->buf_win || !s->buf_calc || !s->buf_ovl) {
+ af_msg(AF_MSG_FATAL, "[scaletempo] Out of memory\n");
+ return AF_ERROR;
+ }
+
+ return af_test_output(af,(af_data_t*)arg);
+ }
+ case AF_CONTROL_SCALETEMPO_AMOUNT | AF_CONTROL_SET:
+ s->scale = *(float*)arg;
+ return AF_OK;
+ case AF_CONTROL_SCALETEMPO_AMOUNT | AF_CONTROL_GET:
+ *(float*)arg = s->scale;
+ return AF_OK;
+ case AF_CONTROL_COMMAND_LINE:{
+ float f;
+ sscanf((char*)arg,"%f", &f);
+ return control(af, AF_CONTROL_SCALETEMPO_AMOUNT | AF_CONTROL_SET, &f);
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance_s* af)
+{
+ af_scaletempo_t* s = af->setup;
+ free(af->data->audio);
+ free(af->data);
+ free(s->buf_win);
+ free(s->buf_ovl);
+ free(s->buf_calc);
+ free(af->setup);
+}
+
+// Allocate memory and set function pointers
+static int af_open(af_instance_t* af){
+ af_scaletempo_t* s;
+
+ af->control = control;
+ af->uninit = uninit;
+ af->play = play;
+ af->mul.n = 1;
+ af->mul.d = 1;
+ af->data = calloc(1,sizeof(af_data_t));
+ af->setup = calloc(1,sizeof(af_scaletempo_t));
+ if(af->data == NULL || af->setup == NULL)
+ return AF_ERROR;
+
+ s = af->setup;
+ s->scale = 1.0;
+ s->ns_stride_error = 0;
+
+ return AF_OK;
+}
+
+// Description of this filter
+af_info_t af_info_scaletempo = {
+ "Scale audio tempo while maintaining pitch",
+ "scaletempo",
+ "Robert Juliano",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
Index: libaf/af_scalepitch.c
===================================================================
--- libaf/af_scalepitch.c (revision 0)
+++ libaf/af_scalepitch.c (revision 0)
@@ -0,0 +1,171 @@
+/*
+ * scalepitch audio filter
+ * (cc) GPL 2007 MPlayer / Robert Juliano
+ *
+ * This file is part of MPlayer.
+ *
+ * MPlayer 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.
+ *
+ * MPlayer 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 MPlayer; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * scale pitch without scaling tempo
+ *
+ * basic technique:
+ * scale pitch and tempo with scalerate + unscale tempo with scaletempo
+ *
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "af.h"
+
+// Data for specific instances of this filter
+typedef struct af_scalepitch_s
+{
+ af_instance_t* scaler_rate;
+ af_instance_t* scaler_tempo;
+ af_instance_t* converter;
+ float scale;
+} af_scalepitch_t;
+
+// Initialization and runtime control
+static int control(struct af_instance_s* af, int cmd, void* arg)
+{
+ af_scalepitch_t* s = af->setup;
+ af_instance_t* scaler_tempo = s->scaler_tempo;
+ af_instance_t* scaler_rate = s->scaler_rate;
+ af_instance_t* converter = s->converter;
+ switch(cmd){
+ case AF_CONTROL_REINIT:{
+ af_data_t* c = (af_data_t*)arg;
+ af_data_t fmt_rate, fmtc, fmt_tempo;
+ float tempo, rate;
+ int rv;
+
+ if (s->scale == 1.0)
+ return AF_DETACH;
+
+ // init sub filters
+ tempo = 1.0 / s->scale;
+ rate = s->scale;
+ if (AF_OK != (rv = scaler_tempo->control(scaler_tempo, AF_CONTROL_SCALETEMPO_AMOUNT | AF_CONTROL_SET, &tempo)))
+ return rv;
+ if (AF_OK != (rv = scaler_rate->control(scaler_rate, AF_CONTROL_SCALERATE_AMOUNT | AF_CONTROL_SET, &rate)))
+ return rv;
+
+ memcpy(&fmt_rate, c, sizeof(af_data_t));
+ if (AF_ERROR == (rv = scaler_rate->control(scaler_rate, AF_CONTROL_REINIT, &fmt_rate)))
+ return rv;
+ memcpy(&fmt_tempo, &fmt_rate, sizeof(af_data_t));
+ if (AF_ERROR == (rv = scaler_tempo->control(scaler_tempo, AF_CONTROL_REINIT, &fmt_tempo)))
+ return rv;
+
+ // convert
+ if (scaler_rate->data->format != fmt_tempo.format) {
+ memcpy(&fmtc, scaler_rate->data, sizeof(af_data_t));
+ if (AF_ERROR == (rv = converter->control(converter, AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET, &(fmt_tempo.format))) )
+ return rv;
+ if (AF_ERROR == (rv = converter->control(converter, AF_CONTROL_REINIT, &fmtc)) )
+ return rv;
+ } else {
+ free(s->converter);
+ }
+
+ af->data = scaler_tempo->data;
+ if (c->format != fmt_rate.format
+ || c->bps != fmt_rate.bps
+ || c->rate != fmt_rate.rate
+ || c->nch != fmt_rate.nch) {
+ memcpy(c, &fmt_rate, sizeof(af_data_t));
+ return AF_FALSE;
+ }
+
+ return AF_OK;
+ }
+ case AF_CONTROL_SCALEPITCH_AMOUNT | AF_CONTROL_SET:
+ s->scale = *(float*)arg;
+ return AF_OK;
+ case AF_CONTROL_SCALEPITCH_AMOUNT | AF_CONTROL_GET:
+ *(float*)arg = s->scale;
+ return AF_OK;
+ case AF_CONTROL_COMMAND_LINE:{
+ float f;
+ sscanf((char*)arg,"%f", &f);
+ return control(af, AF_CONTROL_SCALEPITCH_AMOUNT | AF_CONTROL_SET, &f);
+ }
+ }
+ return AF_UNKNOWN;
+}
+
+// Deallocate memory
+static void uninit(struct af_instance_s* af)
+{
+ af_scalepitch_t* s = af->setup;
+ s->scaler_tempo->uninit(s->scaler_tempo);
+ free(s->scaler_tempo);
+ s->scaler_rate->uninit(s->scaler_rate);
+ free(s->scaler_rate);
+ if(s->converter) {
+ s->converter->uninit(s->converter);
+ free(s->converter);
+ }
+ free(af->setup);
+}
+
+// Filter data through filter
+static af_data_t* play(struct af_instance_s* af, af_data_t* data)
+{
+ af_scalepitch_t* s = af->setup;
+ af_data_t* l;
+ l = s->scaler_rate->play(s->scaler_rate, data);
+ if (s->converter)
+ s->converter->play(s->converter, l);
+ s->scaler_tempo->play(s->scaler_tempo, l);
+ return l;
+}
+
+// Allocate memory and set function pointers
+static int af_open(af_instance_t* af){
+ af_scalepitch_t* s;
+
+ af->control=control;
+ af->uninit=uninit;
+ af->play=play;
+ af->mul.d=1;
+ af->mul.n=1;
+ af->setup=calloc(1,sizeof(af_scalepitch_t));
+ if(af->setup == NULL)
+ return AF_ERROR;
+
+ s = af->setup;
+ s->scale = 1.0;
+ s->scaler_tempo = af_create(af->stream, "scaletempo");
+ s->scaler_rate = af_create(af->stream, "scalerate");
+ s->converter = af_create(af->stream, "format");
+ if (!s->scaler_tempo || !s->scaler_rate || !s->converter)
+ return AF_ERROR;
+
+ return AF_OK;
+}
+
+// Description of this filter
+af_info_t af_info_scalepitch = {
+ "Scale pitch without scaling tempo",
+ "scalepitch",
+ "Robert Juliano",
+ "",
+ AF_FLAGS_REENTRANT,
+ af_open
+};
Index: libaf/af.c
===================================================================
--- libaf/af.c (revision 23550)
+++ libaf/af.c (working copy)
@@ -31,6 +31,9 @@
extern af_info_t af_info_center;
extern af_info_t af_info_sinesuppress;
extern af_info_t af_info_karaoke;
+extern af_info_t af_info_scaletempo;
+extern af_info_t af_info_scalerate;
+extern af_info_t af_info_scalepitch;
static af_info_t* filter_list[]={
&af_info_dummy,
@@ -61,6 +64,9 @@
&af_info_center,
&af_info_sinesuppress,
&af_info_karaoke,
+ &af_info_scaletempo,
+ &af_info_scalerate,
+ &af_info_scalepitch,
NULL
};
@@ -100,7 +106,7 @@
/*/ Function for creating a new filter of type name. The name may
contain the commandline parameters for the filter */
-static af_instance_t* af_create(af_stream_t* s, char* name)
+af_instance_t* af_create(af_stream_t* s, char* name)
{
char* cmdline = name;
@@ -131,6 +137,8 @@
af_msg(AF_MSG_VERBOSE,"[libaf] Adding filter %s \n",name);
+ new->stream = s;
+
// Initialize the new filter
if(AF_OK == new->info->open(new) &&
AF_ERROR < new->control(new,AF_CONTROL_POST_CREATE,&s->cfg)){
Index: libaf/af.h
===================================================================
--- libaf/af.h (revision 23550)
+++ libaf/af.h (working copy)
@@ -64,6 +64,7 @@
af_data_t* data; // configuration for outgoing data stream
struct af_instance_s* next;
struct af_instance_s* prev;
+ struct af_stream_s* stream; // allow filters to create, add, etc. other filters
double delay; // Delay caused by the filter [ms]
frac_t mul; /* length multiplier: how much does this instance change
the length of the buffer. */
@@ -173,6 +174,16 @@
void af_remove(af_stream_t* s, af_instance_t* af);
/**
+ * \brief create instance of filter
+ * \param name name of filter to create with command line paramters
+ * \return pointer to the new filter, NULL if failed
+ *
+ * Does not add filter to filter chain. Useful for swallowing other
+ * filters. Use af_add to add filter to filter chain.
+ */
+af_instance_t* af_create(af_stream_t* s, char* name);
+
+/**
* \brief find filter in chain by name
* \param name name of the filter to find
* \return first filter with right name or NULL if not found
More information about the MPlayer-dev-eng
mailing list