[MPlayer-dev-eng] [PATCH] Simple 2:1 Audio Downsampling Plugin

Philip Chong pchong at ic.EECS.Berkeley.EDU
Thu Dec 20 07:32:01 CET 2001


Hi there:

Currently I've got one of those miserable sound cards which is limited
to a 44.1 kHz maximum rate.  Needless to say, this makes a lot of stuff
unplayable (at decent quality, anyways) under MPlayer.  Despite the
assurances of sound.html in the docs, I was unable to figure out where
the downsampling was happening in the SDL driver, or how even to turn
this on.  So, I wrote an audio plugin to do simple 2:1 downsampling,
and can now play 48 kHz audio (downsampled to 24 kHz, but still
"reasonable" quality).

The audio plugin is turned on with the label "halfrate".  There is also
a plugin flag "autohalfrate", which enables autodetection and disables
the plugin if the original sample rate is less than or equal to 44.1
kHz.  This means you can simply put "aop=list=halfrate:autohalfrate=1"
in the config file, and be assured that downsampling will only happen
when it is needed.

Hope this patch is of some use.  The diff is against CVS sources.

-- 
Philip Chong
pchong at eecs.berkeley.edu
-------------- next part --------------
diff -urN -X ignore main/cfg-mplayer.h devel/cfg-mplayer.h
--- main/cfg-mplayer.h	Sun Dec 16 15:59:28 2001
+++ devel/cfg-mplayer.h	Wed Dec 19 21:53:49 2001
@@ -83,6 +83,8 @@
 	{"list", &ao_plugin_cfg.plugin_list, CONF_TYPE_STRING, 0, 0, 0},
 	{"delay", &ao_plugin_cfg.pl_delay_len, CONF_TYPE_INT, CONF_MIN, 0, 0},
 	{"format", &ao_plugin_cfg.pl_format_type, CONF_TYPE_INT, CONF_MIN, 0, 0},
+	{"autohalfrate", &ao_plugin_cfg.pl_autohalfrate, CONF_TYPE_FLAG, 0, 0, 1},
+	{"noautohalfrate", &ao_plugin_cfg.pl_autohalfrate, CONF_TYPE_FLAG, 0, 1, 0},
 	{NULL, NULL, 0, 0, 0, 0}
 };
 
diff -urN -X ignore main/libao2/Makefile devel/libao2/Makefile
--- main/libao2/Makefile	Thu Dec 13 15:36:36 2001
+++ devel/libao2/Makefile	Wed Dec 19 21:03:28 2001
@@ -4,7 +4,7 @@
 LIBNAME = libao2.a
 
 # TODO: moveout ao_sdl.c so it's only used when SDL is detected
-SRCS=afmt.c audio_out.c ao_mpegpes.c ao_null.c ao_pcm.c ao_plugin.c pl_delay.c pl_format.c pl_surround.c remez.c $(OPTIONAL_SRCS)
+SRCS=afmt.c audio_out.c ao_mpegpes.c ao_null.c ao_pcm.c ao_plugin.c pl_delay.c pl_format.c pl_halfrate.c pl_surround.c remez.c $(OPTIONAL_SRCS)
 OBJS=$(SRCS:.c=.o)
 
 CFLAGS  = $(OPTFLAGS) -I. -I.. $(SDL_INC) $(X11_INC) $(EXTRA_INC)
diff -urN -X ignore main/libao2/audio_plugin.h devel/libao2/audio_plugin.h
--- main/libao2/audio_plugin.h	Wed Dec  5 02:31:10 2001
+++ devel/libao2/audio_plugin.h	Wed Dec 19 21:06:55 2001
@@ -34,6 +34,7 @@
   char* plugin_list; 	// List of used plugins read from cfg
   int pl_format_type;	// Output format
   int pl_delay_len;	// Number of samples to delay sound output
+  int pl_autohalfrate;  // Turns on rate autodetection
 } ao_plugin_cfg_t;
 
 extern volatile ao_plugin_cfg_t ao_plugin_cfg;
@@ -48,16 +49,18 @@
 // This block should not be available in the pl_xxxx files
 // due to compilation issues
 #ifndef PLUGIN
-#define NPL 3+1 // Number of PLugins ( +1 list ends with NULL )
+#define NPL 4+1 // Number of PLugins ( +1 list ends with NULL )
 // List of plugins 
 extern ao_plugin_functions_t audio_plugin_delay;
 extern ao_plugin_functions_t audio_plugin_format; 
+extern ao_plugin_functions_t audio_plugin_halfrate; 
 extern ao_plugin_functions_t audio_plugin_surround;
 
 
 #define AO_PLUGINS { \
    &audio_plugin_delay, \
    &audio_plugin_format, \
+   &audio_plugin_halfrate, \
    &audio_plugin_surround, \
    NULL \
 }
diff -urN -X ignore main/libao2/pl_halfrate.c devel/libao2/pl_halfrate.c
--- main/libao2/pl_halfrate.c	Wed Dec 31 16:00:00 1969
+++ devel/libao2/pl_halfrate.c	Wed Dec 19 21:17:56 2001
@@ -0,0 +1,118 @@
+/* Halfrate plugin:  Simple 2:1 downsampling
+   Useful for bringing 48kHz audio down to 24kHz for playing on soundcards
+   limited to 44.1kHz audio
+   Philip Chong <pchong at eecs.berkeley.edu>
+*/
+
+#define PLUGIN
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "audio_out.h"
+#include "audio_plugin.h"
+#include "audio_plugin_internal.h"
+#include "afmt.h"
+
+static ao_info_t info =
+{
+        "Halfrate audio plugin",
+        "halfrate",
+        "Philip Chong <pchong at eecs.berkeley.edu>",
+        ""
+};
+
+LIBAO_PLUGIN_EXTERN(halfrate)
+
+// local data
+typedef struct pl_halfrate_s
+{
+  void* data;       // local audio data block
+  int len;          // local buffer length
+  int disabled;     // indicates filter is disabled because of autodetect
+} pl_halfrate_t;
+
+static pl_halfrate_t pl_halfrate = {NULL, 0, 0};
+
+// to set/get/query special features/parameters
+static int control(int cmd,int arg) {
+  switch (cmd) {
+  case AOCONTROL_PLUGIN_SET_LEN:
+    if (!pl_halfrate.disabled) {
+      pl_halfrate.len = ao_plugin_data.len;
+      ao_plugin_data.len *= 2;
+      if (pl_halfrate.data) 
+	free (pl_halfrate.data);
+      pl_halfrate.data = (void*) malloc(ao_plugin_data.len);
+      if (!pl_halfrate.data)
+	return CONTROL_ERROR;
+    }
+    return CONTROL_OK;
+  }
+  return -1;
+}
+
+// open & setup audio device
+// return: 1=success 0=fail
+static int init() {
+  switch (ao_plugin_data.format) {
+    case AFMT_U8:
+    case AFMT_S8:
+    case AFMT_S32_LE:
+    case AFMT_S32_BE:
+      printf("[pl_halfrate] Error: 16-bit input required for now\n");
+      return 0;
+    default:
+      break;
+  }
+  printf("[pl_halfrate] 2:1 audio downsampler: ");
+  if (ao_plugin_cfg.pl_autohalfrate && ao_plugin_data.rate <= 44100) {
+    // rate is low enough that we need not enable this filter
+    pl_halfrate.disabled = 1;
+    printf("autodetect disabled\n");
+  }
+  else {
+    ao_plugin_data.rate /= 2;
+    ao_plugin_data.sz_mult *= 2;
+    printf("enabled\n");
+  }
+  return 1;
+}
+
+// close plugin
+static void uninit() {
+  if (pl_halfrate.data) {
+    free (pl_halfrate.data);
+  }
+  pl_halfrate.data = NULL;
+  pl_halfrate.len = 0;
+}
+
+// empty buffers
+static void reset() {
+  if (pl_halfrate.data) {
+    memset (pl_halfrate.data, 0, pl_halfrate.len);
+  }
+}
+
+// processes 'ao_plugin_data.len' bytes of 'data'
+// called for every block of data
+static int play() {
+  int i;
+  char *p1, *p2;
+
+  if (!pl_halfrate.disabled) {
+    p1 = pl_halfrate.data;
+    p2 = ao_plugin_data.data;
+    for (i=ao_plugin_data.len/4; i--; ) {
+      (*p1++) = (*p2++);
+      (*p1++) = (*p2++);
+      p2 += 2;
+    }
+
+    ao_plugin_data.data = pl_halfrate.data;
+    ao_plugin_data.len /= 2;
+  }
+
+  return 1;
+}


More information about the MPlayer-dev-eng mailing list