44B0软解码MP3的一些努力
by panasonic.lin@163.com
自上篇我的44B0可以解码16k立体声MP3以来,我给驱动添加了oss接口,支持22k,32k
,44k等采样,最高44k的pcm wav码流可以直接写入驱动,但是在应用程序层,我用了
libmad,解码22k的mp3有点吃力,问题出在madlld的程序结构上:
if(OutputPtr==OutputBufferEnd)
{
if(write(sfd, OutputBuffer, OUTPUT_BUFFER_SIZE)!=OUTPUT_BUFFER_SIZE)
{
fprintf(stderr,"%s: PCM write error (%s).\n",
ProgName,strerror(errno));
Status=2;
break;
}
当libmad解码完一个OUTPUT_BUFFER_SIZE的数据后,写入声卡的驱动程序空间,这时候write可能
阻塞了,这时驱动在搬运这些数据到iis,但是主程序main却阻塞在这里等待,所以等write返回后
libmad才可以解码下一个OUTPUT_BUFFER_SIZE的数据,所以会出现一卡一卡的现象。
为了解决这个问题,我尝试用多线程的方法:
写入者是madlld的MpegAudioDecoder函数,解码完一个OUTPUT_BUFFER_SIZE后,写入fifo。
写入fifo前,如果fifo没有OUTPUT_BUFFER_SIZE以上的空间,挂起当前主线程,等待条件成熟。
写入fifo后,如果fifo的数据>RD_MIN_SPACE,唤醒读取着读取fifo的数据。
读取者是另外一个线程,如果fifo没有数据,则读取者进入睡眠,等待写入者写入足够多的数据后唤醒它。
如果fifo有数据,则读取fifo的数据到自己的缓冲区中,然后write到声卡驱动中,这时候可能会阻塞。
但是由于fifo的数据已经拷贝到读取者自己的缓存中,所以在write阻塞的时候,fifo可以继续被写入者写入。
读取者写入驱动程序空间后,如果fifo的空间>WR_MIN_SPACE,唤醒写入者写入fifo数据。
基本思想如上,程序全套代码附上:
https://static.assets-stash.eet-china.com/album/old-resources/2010/5/6/1d7fb01c-0de2-41a5-ab14-a7506d5ba676.zip
16k,22k,32k采样的mp3都很流畅的播放,但是44k的有点卡,还是老问题,解码数据的速度跟不上驱动的写入速度。
网上有人说44b0能软解码320kbps的MP3,我估计是裸奔吧,单从驱动程序写入速度来说,我这个完全没有问题,44k采样
的wav文件码率是1411kbps!
uclinux的多线程并不是真正意义上的多线程,父子线程是交替进行的,就是说如果子线程
没有让出cpu,父线程是没有机会运行的!从下面的多线程例程可以看到这样的现象:
附上uclinux测试用多线程源码
https://static.assets-stash.eet-china.com/album/old-resources/2010/5/6/4df984a8-91a6-4cc4-9c4a-6f0b5ee09651.zip
如果我说的没错,从这种意义上来说,uclinux跟ucos或者其他的os一样,是不是要主动让出cpu阿??
所以上面说到的基本思路,其实是有问题的,当读取着阻塞在write调用时候,写入者进程也得不到cpu
时间去写入fifo,结果还是跟以前的程序一样,一个大循环,卡在某个子程序,使得别的程序没有运行。
不过比以前好点,32k采样的可以流畅播放。
或许我应该放弃继续研究下去,或者弄个硬解码的code,如vs1003??
uclinux的多线程Makefile:
Makefile要指定libpthread,程序包含pthread.h
#/* $Id: Makefile,v 1.5 2009/10/26 03:32:21 $ */
CFLAGS = -Wall -Dlinux -D__linux__ -Dunix -D__uClinux__ -DEMBED
LDFLAGS =-Wl,-elf2flt
LOCAL_LIBS = /usr/local/arm-elf/lib/libpthread.a
LDLIBS = ./libmad.a
CC = arm-elf-gcc
LD = arm-elf-gcc
TARGT = madlld
OBJ = bstdfile.o kfifo.o madlld.o
SRC = bstdfile.c kfifo.c madlld.c
all: $(TARGT)
cp -v $(TARGT) /home/panasonic/nfsroot-44b0/bin
%.o:%.c
$(CC) $(CFLAGS) -c $< -o $@
$(TARGT) :$(OBJ) $(LOCAL_LIBS)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJ) $(LOCAL_LIBS) $(LDLIBS)
clean:
rm -f $(TARGT) *.elf *.gdb *.o
文章评论(0条评论)
登录后参与讨论