summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--codec-cfg.c1
-rw-r--r--codec-cfg.h1
-rw-r--r--dec_audio.c149
-rw-r--r--etc/codecs.conf11
5 files changed, 163 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 7c02bb380c..fa7dc02d03 100644
--- a/Makefile
+++ b/Makefile
@@ -18,8 +18,8 @@ BINDIR = ${prefix}/bin
# BINDIR = /usr/local/bin
SRCS = xacodec.c cpudetect.c postproc/swscale.c postproc/postprocess.c mp_msg.c ac3-iec958.c find_sub.c dec_audio.c dec_video.c codec-cfg.c subreader.c linux/getch2.c linux/timer-lx.c linux/shmem.c xa/xa_gsm.c xa/rle8.c lirc_mp.c cfgparser.c mixer.c spudec.c
OBJS = $(SRCS:.c=.o)
-CFLAGS = $(OPTFLAGS) -Ilibmpdemux -Iloader -Ilibvo $(CSS_INC) $(EXTRA_INC) # -Wall
-A_LIBS = -Lmp3lib -lMP3 -Llibac3 -lac3 $(ALSA_LIB) $(ESD_LIB)
+CFLAGS = $(OPTFLAGS) -Ilibmpdemux -Iloader -Ilibvo $(CSS_INC) $(EXTRA_INC) $(MADLIB_INC) # -Wall
+A_LIBS = -Lmp3lib -lMP3 -Llibac3 -lac3 $(ALSA_LIB) $(ESD_LIB) $(MADLIB_LIB)
VO_LIBS = -Llibvo -lvo $(MLIB_LIB) $(X_LIBS)
PARTS = libmpdemux mp3lib libac3 libmpeg2 opendivx libavcodec encore libvo libao2 drivers drivers/syncfb
diff --git a/codec-cfg.c b/codec-cfg.c
index 3f756a416d..64a3c94f5c 100644
--- a/codec-cfg.c
+++ b/codec-cfg.c
@@ -209,6 +209,7 @@ static short get_driver(char *s,int audioflag)
"hwac3",
"libvorbis",
"ffmpeg",
+ "libmad",
NULL
};
static char *videodrv[] = {
diff --git a/codec-cfg.h b/codec-cfg.h
index e96196acc3..9b1f7858bc 100644
--- a/codec-cfg.h
+++ b/codec-cfg.h
@@ -29,6 +29,7 @@
#define AFM_HWAC3 9
#define AFM_VORBIS 10
#define AFM_FFMPEG 11
+#define AFM_MAD 12
#define VFM_MPEG 1
#define VFM_VFW 2
diff --git a/dec_audio.c b/dec_audio.c
index c6605886bc..439e93c6e7 100644
--- a/dec_audio.c
+++ b/dec_audio.c
@@ -63,6 +63,55 @@ typedef struct ov_struct_st {
extern int avcodec_inited;
#endif
+
+
+#ifdef USE_LIBMAD
+#include <mad.h>
+static struct mad_stream mad_stream;
+static struct mad_frame mad_frame;
+static struct mad_synth mad_synth;
+
+
+// ensure buffer is filled with some data
+static void mad_prepare_buffer(sh_audio_t* sh_audio, struct mad_stream* ms, int length)
+{
+ if(sh_audio->a_in_buffer_len < length) {
+ int len = demux_read_data(sh_audio->ds, sh_audio->a_in_buffer+sh_audio->a_in_buffer_len, length-sh_audio->a_in_buffer_len);
+ sh_audio->a_in_buffer_len += len;
+ }
+}
+
+static void mad_postprocess_buffer(sh_audio_t* sh_audio, struct mad_stream* ms)
+{
+ int delta = (unsigned char*)ms->next_frame - (unsigned char *)sh_audio->a_in_buffer;
+ if(delta != 0) {
+ sh_audio->a_in_buffer_len -= delta;
+ memcpy(sh_audio->a_in_buffer, ms->next_frame, sh_audio->a_in_buffer_len);
+ }
+}
+
+
+static inline
+signed short mad_scale(mad_fixed_t sample)
+{
+ /* round */
+ sample += (1L << (MAD_F_FRACBITS - 16));
+
+ /* clip */
+ if (sample >= MAD_F_ONE)
+ sample = MAD_F_ONE - 1;
+ else if (sample < -MAD_F_ONE)
+ sample = -MAD_F_ONE;
+
+ /* quantize */
+ return sample >> (MAD_F_FRACBITS + 1 - 16);
+}
+#endif
+
+
+
+
+
int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen);
@@ -191,6 +240,17 @@ case AFM_FFMPEG:
sh_audio->audio_out_minsize=AVCODEC_MAX_AUDIO_FRAME_SIZE;
break;
#endif
+
+#ifdef USE_LIBMAD
+ case AFM_MAD:
+ printf(__FILE__ ":%d:mad: setting minimum outputsize\n", __LINE__);
+ sh_audio->audio_out_minsize=4608;
+ if(sh_audio->audio_in_minsize<8192) sh_audio->audio_in_minsize=8192;
+ sh_audio->a_in_buffer_size=sh_audio->audio_in_minsize;
+ sh_audio->a_in_buffer=malloc(sh_audio->a_in_buffer_size);
+ sh_audio->a_in_buffer_len=0;
+ break;
+#endif
}
if(!driver) return 0;
@@ -488,6 +548,37 @@ case AFM_VORBIS: {
break;
}
#endif
+
+#ifdef USE_LIBMAD
+ case AFM_MAD:
+ {
+ printf(__FILE__ ":%d:mad: initialising\n", __LINE__);
+ mad_frame_init(&mad_frame);
+ mad_stream_init(&mad_stream);
+
+ printf(__FILE__ ":%d:mad: preparing buffer\n", __LINE__);
+ mad_prepare_buffer(sh_audio, &mad_stream, sh_audio->a_in_buffer_size);
+ mad_stream_buffer(&mad_stream, (unsigned char*)(sh_audio->a_in_buffer), sh_audio->a_in_buffer_len);
+ mad_stream_sync(&mad_stream);
+ mad_synth_init(&mad_synth);
+
+ if(mad_frame_decode(&mad_frame, &mad_stream) == 0)
+ {
+ printf(__FILE__ ":%d:mad: post processing buffer\n", __LINE__);
+ mad_postprocess_buffer(sh_audio, &mad_stream);
+ }
+ else
+ {
+ printf(__FILE__ ":%d:mad: frame decoding failed\n", __LINE__);
+ }
+
+ sh_audio->channels=2; // hack
+ sh_audio->samplerate=mad_frame.header.sfreq;
+ sh_audio->i_bps=mad_frame.header.bitrate;
+ printf(__FILE__ ":%d:mad: continuing\n", __LINE__);
+ break;
+ }
+#endif
}
if(!sh_audio->channels || !sh_audio->samplerate){
@@ -741,6 +832,42 @@ int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen){
break;
}
#endif
+
+#ifdef USE_LIBMAD
+ case AFM_MAD:
+ {
+ mad_prepare_buffer(sh_audio, &mad_stream, sh_audio->a_in_buffer_size);
+ mad_stream_buffer(&mad_stream, sh_audio->a_in_buffer, sh_audio->a_in_buffer_len);
+ if(mad_frame_decode(&mad_frame, &mad_stream) == 0)
+ {
+ mad_synth_frame(&mad_synth, &mad_frame);
+ mad_postprocess_buffer(sh_audio, &mad_stream);
+
+ /* and fill buffer */
+
+ {
+ int i;
+ int end_size = mad_synth.pcm.length;
+ signed short* samples = (signed short*)buf;
+ if(end_size > maxlen/4)
+ end_size=maxlen/4;
+
+ for(i=0; i<mad_synth.pcm.length; ++i) {
+ *samples++ = mad_scale(mad_synth.pcm.samples[0][i]);
+ *samples++ = mad_scale(mad_synth.pcm.samples[0][i]);
+ // *buf++ = mad_scale(mad_synth.pcm.sampAles[1][i]);
+ }
+ len = end_size*4;
+ }
+ }
+ else
+ {
+ printf(__FILE__ ":%d:mad: frame decoding failed\n", __LINE__);
+ }
+
+ break;
+ }
+#endif
}
return len;
}
@@ -770,8 +897,16 @@ void resync_audio_stream(sh_audio_t *sh_audio){
case AFM_HWAC3:
sh_audio->a_in_buffer_len=0; // reset ACM/DShow audio buffer
break;
+
+#ifdef USE_LIBMAD
+ case AFM_MAD:
+ mad_prepare_buffer(sh_audio, &mad_stream, sh_audio->a_in_buffer_size);
+ mad_stream_buffer(&mad_stream, sh_audio->a_in_buffer, sh_audio->a_in_buffer_len);
+ mad_stream_sync(&mad_stream);
+ mad_postprocess_buffer(sh_audio, &mad_stream);
+ break;
}
-
+#endif
}
void skip_audio_frame(sh_audio_t *sh_audio){
@@ -796,6 +931,18 @@ void skip_audio_frame(sh_audio_t *sh_audio){
demux_read_data(sh_audio->ds,NULL,skip);
break;
}
+#ifdef USE_LIBMAD
+ case AFM_MAD:
+ {
+ mad_prepare_buffer(sh_audio, &mad_stream, sh_audio->a_in_buffer_size);
+ mad_stream_buffer(&mad_stream, sh_audio->a_in_buffer, sh_audio->a_in_buffer_len);
+ mad_stream_skip(&mad_stream, 2);
+ mad_stream_sync(&mad_stream);
+ mad_postprocess_buffer(sh_audio, &mad_stream);
+ break;
+ }
+#endif
+
default: ds_fill_buffer(sh_audio->ds); // skip PCM frame
}
}
diff --git a/etc/codecs.conf b/etc/codecs.conf
index 34540e56c8..15213eae57 100644
--- a/etc/codecs.conf
+++ b/etc/codecs.conf
@@ -590,6 +590,17 @@ audiocodec mp3
dll "mp3lib (mpglib)"
flags seekable
+;MAD library
+audiocodec mad
+ info "MAD MPEG layer-2, layer-3"
+ status working
+ comment "Optimized for ARM"
+ format 0x50
+ format 0x55
+ driver libmad
+ dll "libmad"
+ flags seekable
+
audiocodec ffmp3
info "FFmpeg layer-123 audio decoder - integer only"
status working