由iis的采样率反推cpu的主频大概是65.536M,约等于66Mhz。uboot和uclinux都应该设定一样的cpu主频!由于之前我板子上面的uboot是66M的主频,我在编译uclinux的时候选择的主频是60M,导致启动uclinux的时候start kernel后控制台全是乱码。 uboot的主频设定比较简单,在/cpu/s3c44b0/start.S可以设定pllcon寄存器,另外在/driver/serial/找到 44b0串口的代码,修改相应主频下的波特率分频因子,最后在/include/configs配置文件配置主频==66M。 uclinux在make menuconfig的时候并没有主频可以填写,而早uclinux的其他文件提到配置cpu主频的很多,到底那个才是有效的?不得而知。 1是在/vendors/samsung/44b0/config.linux-2.4.x # CONFIG_CPU_WITH_MCR_INSTRUCTION is not set CONFIG_ARM_CLK=66000000 CONFIG_SERIAL_S3C44B0X=y 2是在/linux2.4.x/arch/armnommu/config.in,这个应该是配置默认值 if [ "$CONFIG_BOARD_MBA44" = "y" ]; then define_string CONFIG_SPU_NAME "S3C44B0X" define_bool CONFIG_CPU_S3C44B0X y define_bool CONFIG_CPU_ARM710 y define_bool CONFIG_CPU_32v4 y define_bool CONFIG_CPU_32 y define_bool CONFIG_CPU_26 n define_bool CONFIG_NO_PGT_CACHE y define_bool CONFIG_CPU_WITH_CACHE y define_bool CONFIG_CPU_WITH_MCR_INSTRUCTION n define_int CONFIG_ARM_CLK 66000000 define_bool CONFIG_SERIAL_S3C44B0X y 不过怎么样,最后的配置config后都生成/linux2.4.x/include/linux/autoconf.h头文件,它被编译到系统(很多文件都包含这个头文件),所以以这个为准。 #define CONFIG_CPU_WITH_CACHE 1 #undef CONFIG_CPU_WITH_MCR_INSTRUCTION #define CONFIG_ARM_CLK (66000000) #define CONFIG_SERIAL_S3C44B0X 1
好,环境都准备好了,最后最好弄个nfs的开发环境,修改文件比较方便。另外根文件系统的busybox应该有常用的程序如cat,insmod,lsmod,rmmod,echo,mount,和shell。最后用mknod在根文件系统的/dev目录下建立一个设备文件iis,主 编号iis_major=14,次编号0,名字是iis,不管怎么样,目标一个:跟下面的函数保持一致。 result = register_chrdev(iis_major,DEV_IIS,&sound_dev_ops);
驱动正常工作,开始mp3解码成pcm的工作。用libmad的有两种方法,一种是简单的利用高层的api写,另外一种是用底层的api,下面两种方法都会介绍到。 下载libmad和madlld。 第一步是编译libmad库:libmad.a和mad.h,后续的mp3应用程序需要链接到这个库。 ./configure --help获得可用的配置选项。 panasonic@linux-p5tw:~/soundcard/libmad-0.15.1b> ./configure --help `configure' configures MPEG Audio Decoder 0.15.1b to adapt to many kinds of systems.
Usage: ./configure [OPTION]... [VAR=VALUE]...
To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables.
Defaults for the options are specified in brackets.
Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print `checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for `--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or `..']
panasonic@linux-p5tw:~/soundcard/libmad-0.15.1b> ./configure --enable-fpm=arm --host=arm-elf --disable-debugging --prefix=/home/panasonic/soundcard/libmad-0.15.1b/install --disable-shared --enable-static --enable-speed configure: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used. checking for a BSD-compatible install... /usr/bin/install -c checking whether build environment is sane... yes checking for gawk... gawk checking whether make sets $(MAKE)... yes checking for arm-elf-strip... arm-elf-strip
make TARGET_ARCH=arm CROSS=arm-elf- make install 最后生成mad.h和libmad.a静态库。
有了libmad.a库,下面写个简单的应用软件,这是用libmad高层的api写,比较简单,其实就是来自libmad自带的minimad.c ,test_music.c的基础就是前面介绍的wav播放器,所以 这个程序也可以播放wav音乐文件,判断命令行传递的argv参数就知道是mp3文件还是wav文件。 #include <sys/ioctl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/soundcard.h> #include <string.h> //add for mp3 play # include <sys/stat.h> # include <sys/mman.h> # include <sys/types.h> # include "./mad.h"
printf("This is a wav&mp3 play program.\n"); printf("Please add a file name and the audio rate!\nsuch as \"./test_music test.mp3\" \n\n\n"); delay(100000);
解码mp3基本上就是这样了^_^为了解决上面的问题,我想更进一步,弄个更实用的。 想了解libmad多一点,最好使用libmad的底层api,这个竟然没有文档!用linux世界的话说就是:一切都在代码里面。 madlld就是libmad的文档工程,使用libmad底层的api写的解码mp3的程序,由stdin输入,解码后写入到stdout。 madlld只有三个c文件,核心是madlld的MpegAudioDecoder(FILE *InputFp)函数。 本来这三个c文件我是翻译好的了,但是。。。。。。哎呀,硬盘没了,大家将就点吧,啃点E文对大家都有好处。 长篇大论我就说了,我只附上我对madlld.c的修改patch补丁。 https://static.assets-stash.eet-china.com/album/old-resources/2010/4/24/c7b73f03-e863-4502-9cf6-9071fe329c82.zip 为了我的附件不丢失,我还是把代码贴上来吧,免得到时候附件没了,还可以从博文里面复制麻。 /* HTAB = 4 */ /**************************************************************************** * madlld.c -- A simple program decoding an mpeg audio stream to 16-bit * * PCM from stdin to stdout. This program is just a simple sample * * demonstrating how the low-level libmad API can be used. * *--------------------------------------------------------------------------* * (c) 2001--2004 Bertrand Petit * * * * Redistribution and use in source and binary forms, with or without * * modification, are permitted provided that the following conditions * * are met: * * * * 1. Redistributions of source code must retain the above copyright * * notice, this list of conditions and the following disclaimer. * * * * 2. Redistributions in binary form must reproduce the above * * copyright notice, this list of conditions and the following * * disclaimer in the documentation and/or other materials provided * * with the distribution. * * * * 3. Neither the name of the author nor the names of its contributors * * may be used to endorse or promote products derived from this * * software without specific prior written permission. * * * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' * * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR * * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * * SUCH DAMAGE. * * * ****************************************************************************/
/**************************************************************************** * Global variables. * ****************************************************************************/
/* Keeps a pointer to the program invocation name for the error * messages. */ const char *ProgName;
/**************************************************************************** * Return an error string associated with a mad error code. * ****************************************************************************/ /* Mad version 0.14.2b introduced the mad_stream_errorstr() function. * For previous library versions a replacement is provided below. */ #if (MAD_VERSION_MAJOR>=1) || \ ((MAD_VERSION_MAJOR==0) && \ (((MAD_VERSION_MINOR==14) && \ (MAD_VERSION_PATCH>=2)) || \ (MAD_VERSION_MINOR>14))) #define MadErrorString(x) mad_stream_errorstr(x) #else static const char *MadErrorString(const struct mad_stream *Stream) { switch(Stream->error) { /* Generic unrecoverable errors. */ case MAD_ERROR_BUFLEN: return("input buffer too small (or EOF)"); case MAD_ERROR_BUFPTR: return("invalid (null) buffer pointer"); case MAD_ERROR_NOMEM: return("not enough memory");
/* Frame header related unrecoverable errors. */ case MAD_ERROR_LOSTSYNC: return("lost synchronization"); case MAD_ERROR_BADLAYER: return("reserved header layer value"); case MAD_ERROR_BADBITRATE: return("forbidden bitrate value"); case MAD_ERROR_BADSAMPLERATE: return("reserved sample frequency value"); case MAD_ERROR_BADEMPHASIS: return("reserved emphasis value");
/* Recoverable errors */ case MAD_ERROR_BADCRC: return("CRC check failed"); case MAD_ERROR_BADBITALLOC: return("forbidden bit allocation value"); case MAD_ERROR_BADSCALEFACTOR: return("bad scalefactor index"); case MAD_ERROR_BADFRAMELEN: return("bad frame length"); case MAD_ERROR_BADBIGVALUES: return("bad big_values count"); case MAD_ERROR_BADBLOCKTYPE: return("reserved block_type"); case MAD_ERROR_BADSCFSI: return("bad scalefactor selection info"); case MAD_ERROR_BADDATAPTR: return("bad main_data_begin pointer"); case MAD_ERROR_BADPART3LEN: return("bad audio data length"); case MAD_ERROR_BADHUFFTABLE: return("bad Huffman table select"); case MAD_ERROR_BADHUFFDATA: return("Huffman data overrun"); case MAD_ERROR_BADSTEREO: return("incompatible block_type for JS");
/* Unknown error. This swich may be out of sync with libmad's * defined error codes. */ default: return("Unknown error code"); } } #endif
/**************************************************************************** * Converts a sample from mad's fixed point number format to a signed * * short (16 bits). * ****************************************************************************/ static signed short MadFixedToSshort(mad_fixed_t Fixed) { /* A fixed point number is formed of the following bit pattern: * * SWWWFFFFFFFFFFFFFFFFFFFFFFFFFFFF * MSB LSB * S ==> Sign (0 is positive, 1 is negative) * W ==> Whole part bits * F ==> Fractional part bits * * This pattern contains MAD_F_FRACBITS fractional bits, one * should alway use this macro when working on the bits of a fixed * point number. It is not guaranteed to be constant over the * different platforms supported by libmad. * * The signed short value is formed, after clipping, by the least * significant whole part bit, followed by the 15 most significant * fractional part bits. Warning: this is a quick and dirty way to * compute the 16-bit number, madplay includes much better * algorithms. */
/**************************************************************************** * Print human readable informations about an audio MPEG frame. * ****************************************************************************/ static int PrintFrameInfo(FILE *fp, struct mad_header *Header) { const char *Layer, *Mode, *Emphasis;
/* Convert the layer number to it's printed representation. */ switch(Header->layer) { case MAD_LAYER_I: Layer="I"; break; case MAD_LAYER_II: Layer="II"; break; case MAD_LAYER_III: Layer="III"; break; default: Layer="(unexpected layer value)"; break; }
/* Convert the audio mode to it's printed representation. */ switch(Header->mode) { case MAD_MODE_SINGLE_CHANNEL: Mode="single channel"; break; case MAD_MODE_DUAL_CHANNEL: Mode="dual channel"; break; case MAD_MODE_JOINT_STEREO: Mode="joint (MS/intensity) stereo"; break; case MAD_MODE_STEREO: Mode="normal LR stereo"; break; default: Mode="(unexpected mode value)"; break; }
/* Convert the emphasis to it's printed representation. Note that * the MAD_EMPHASIS_RESERVED enumeration value appread in libmad * version 0.15.0b. */ switch(Header->emphasis) { case MAD_EMPHASIS_NONE: Emphasis="no"; break; case MAD_EMPHASIS_50_15_US: Emphasis="50/15 us"; break; case MAD_EMPHASIS_CCITT_J_17: Emphasis="CCITT J.17"; break; #if (MAD_VERSION_MAJOR>=1) || \ ((MAD_VERSION_MAJOR==0) && (MAD_VERSION_MINOR>=15)) case MAD_EMPHASIS_RESERVED: Emphasis="reserved(!)"; break; #endif default: Emphasis="(unexpected emphasis value)"; break; }
/**************************************************************************** * Main decoding loop. This is where mad is used. * ****************************************************************************/ #define INPUT_BUFFER_SIZE (5*8192) #define OUTPUT_BUFFER_SIZE 8192 /* Must be an integer multiple of 4. */ static int MpegAudioDecoder(FILE *InputFp) { struct mad_stream Stream; struct mad_frame Frame; struct mad_synth Synth; mad_timer_t Timer; unsigned char InputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD], OutputBuffer[OUTPUT_BUFFER_SIZE], *OutputPtr=OutputBuffer; const unsigned char *OutputBufferEnd=OutputBuffer+OUTPUT_BUFFER_SIZE; int Status=0, i; unsigned long FrameCount=0; bstdfile_t *BstdFile;
/* First the structures used by libmad must be initialized. */ mad_stream_init(&Stream); mad_frame_init(&Frame); mad_synth_init(&Synth); mad_timer_reset(&Timer);
/* Decoding options can here be set in the options field of the * Stream structure. */
/* {1} When decoding from a file we need to know when the end of * the file is reached at the same time as the last bytes are read * (see also the comment marked {3} bellow). Neither the standard * C fread() function nor the posix read() system call provides * this feature. We thus need to perform our reads through an * interface having this feature, this is implemented here by the * bstdfile.c module. */ BstdFile=NewBstdFile(InputFp); if(BstdFile==NULL) { fprintf(stderr,"%s: can't create a new bstdfile_t (%s).\n", ProgName,strerror(errno)); return(1); }
/* This is the decoding loop. */ do { /* The input bucket must be filled if it becomes empty or if * it's the first execution of the loop. */ if(Stream.buffer==NULL || Stream.error==MAD_ERROR_BUFLEN) { size_t ReadSize, Remaining; unsigned char *ReadStart;
/* {2} libmad may not consume all bytes of the input * buffer. If the last frame in the buffer is not wholly * contained by it, then that frame's start is pointed by * the next_frame member of the Stream structure. This * common situation occurs when mad_frame_decode() fails, * sets the stream error code to MAD_ERROR_BUFLEN, and * sets the next_frame pointer to a non NULL value. (See * also the comment marked {4} bellow.) * * When this occurs, the remaining unused bytes must be * put back at the beginning of the buffer and taken in * account before refilling the buffer. This means that * the input buffer must be large enough to hold a whole * frame at the highest observable bit-rate (currently 448 * kb/s). XXX=XXX Is 2016 bytes the size of the largest * frame? (448000*(1152/32000))/8 */ if(Stream.next_frame!=NULL) { Remaining=Stream.bufend-Stream.next_frame; memmove(InputBuffer,Stream.next_frame,Remaining); ReadStart=InputBuffer+Remaining; ReadSize=INPUT_BUFFER_SIZE-Remaining; } else ReadSize=INPUT_BUFFER_SIZE, ReadStart=InputBuffer, Remaining=0;
/* Fill-in the buffer. If an error occurs print a message * and leave the decoding loop. If the end of stream is * reached we also leave the loop but the return status is * left untouched. */ ReadSize=BstdRead(ReadStart,1,ReadSize,BstdFile); if(ReadSize<=0) { if(ferror(InputFp)) { fprintf(stderr,"%s: read error on bitstream (%s)\n", ProgName,strerror(errno)); Status=1; } if(feof(InputFp)) fprintf(stderr,"%s: end of input stream\n",ProgName); break; }
/* {3} When decoding the last frame of a file, it must be * followed by MAD_BUFFER_GUARD zero bytes if one wants to * decode that last frame. When the end of file is * detected we append that quantity of bytes at the end of * the available data. Note that the buffer can't overflow * as the guard size was allocated but not used the the * buffer managment code. (See also the comment marked * {1}.) * * In a message to the mad-dev mailing list on May 29th, * 2001, Rob leslie explains the guard zone as follows: * * "The reason for MAD_BUFFER_GUARD has to do with the * way decoding is performed. In Layer III, Huffman * decoding may inadvertently read a few bytes beyond * the end of the buffer in the case of certain invalid * input. This is not detected until after the fact. To * prevent this from causing problems, and also to * ensure the next frame's main_data_begin pointer is * always accessible, MAD requires MAD_BUFFER_GUARD * (currently 8) bytes to be present in the buffer past * the end of the current frame in order to decode the * frame." */ if(BstdFileEofP(BstdFile)) { memset(ReadStart+ReadSize,0,MAD_BUFFER_GUARD); ReadSize+=MAD_BUFFER_GUARD; }
/* Pipe the new buffer content to libmad's stream decoder * facility. */ mad_stream_buffer(&Stream,InputBuffer,ReadSize+Remaining); Stream.error=0; }
/* Decode the next mpeg frame. The streams is read from the * buffer, its constituents are break down and stored the the * Frame structure, ready for examination/alteration or PCM * synthesis. Decoding options are carried in the Frame * structure from the Stream structure. * * Error handling: mad_frame_decode() returns a non zero value * when an error occurs. The error condition can be checked in * the error member of the Stream structure. A mad error is * recoverable or fatal, the error status is checked with the * MAD_RECOVERABLE macro. * * {4} When a fatal error is encountered all decoding * activities shall be stopped, except when a MAD_ERROR_BUFLEN * is signaled. This condition means that the * mad_frame_decode() function needs more input to achieve * it's work. One shall refill the buffer and repeat the * mad_frame_decode() call. Some bytes may be left unused at * the end of the buffer if those bytes forms an incomplete * frame. Before refilling, the remainign bytes must be moved * to the begining of the buffer and used for input for the * next mad_frame_decode() invocation. (See the comments marked * {2} earlier for more details.) * * Recoverable errors are caused by malformed bit-streams, in * this case one can call again mad_frame_decode() in order to * skip the faulty part and re-sync to the next frame. */ if(mad_frame_decode(&Frame,&Stream)) { if(MAD_RECOVERABLE(Stream.error)) { fprintf(stderr,"%s: recoverable frame level error (%s)\n", ProgName,MadErrorString(&Stream)); fflush(stderr); continue; } else if(Stream.error==MAD_ERROR_BUFLEN) continue; else { fprintf(stderr,"%s: unrecoverable frame level error (%s).\n", ProgName,MadErrorString(&Stream)); Status=1; break; } }
/* The characteristics of the stream's first frame is printed * on stderr. The first frame is representative of the entire * stream. */ if(FrameCount==0) if(PrintFrameInfo(stderr,&Frame.header)) { Status=1; break; }
/* Accounting. The computed frame duration is in the frame * header structure. It is expressed as a fixed point number * whole data type is mad_timer_t. It is different from the * samples fixed point format and unlike it, it can't directly * be added or substracted. The timer module provides several * functions to operate on such numbers. Be careful there, as * some functions of mad's timer module receive some of their * mad_timer_t arguments by value! */ FrameCount++; mad_timer_add(&Timer,Frame.header.duration);
/* Between the frame decoding and samples synthesis we can * perform some operations on the audio data. We do this only * if some processing was required. Detailed explanations are * given in the ApplyFilter() function. */ //if(DoFilter) // ApplyFilter(&Frame);
/* Once decoded the frame is synthesized to PCM samples. No errors * are reported by mad_synth_frame(); */ mad_synth_frame(&Synth,&Frame);
/* Synthesized samples must be converted from mad's fixed * point number to the consumer format. Here we use unsigned * 16 bit big endian integers on two channels. Integer samples * are temporarily stored in a buffer that is flushed when * full. */ for(i=0;i<Synth.pcm.length;i++) { signed short Sample;
/* Left channel */ Sample=MadFixedToSshort(Synth.pcm.samples[0]); *(OutputPtr++)=Sample>>0; *(OutputPtr++)=Sample>>8;
/* Right channel. If the decoded stream is monophonic then * the right output channel is the same as the left one. */ if(MAD_NCHANNELS(&Frame.header)==2) Sample=MadFixedToSshort(Synth.pcm.samples[1]); *(OutputPtr++)=Sample>>0; *(OutputPtr++)=Sample>>8;
/* Flush the output buffer if it is full. */ if(OutputPtr==OutputBufferEnd) { //if(fwrite(OutputBuffer,1,OUTPUT_BUFFER_SIZE,OutputFp)!=OUTPUT_BUFFER_SIZE) if(write(sfd, OutputBuffer, OUTPUT_BUFFER_SIZE)!=OUTPUT_BUFFER_SIZE) { fprintf(stderr,"%s: PCM write error (%s).\n", ProgName,strerror(errno)); Status=2; break; } OutputPtr=OutputBuffer; } } }while(1);
/* The input file was completely read; the memory allocated by our * reading module must be reclaimed. */ BstdFileDestroy(BstdFile);
/* Mad is no longer used, the structures that were initialized must * now be cleared. */ mad_synth_finish(&Synth); mad_frame_finish(&Frame); mad_stream_finish(&Stream);
/* If the output buffer is not empty and no error occured during * the last write, then flush it. */ if(OutputPtr!=OutputBuffer && Status!=2) { size_t BufferSize=OutputPtr-OutputBuffer;
/* Accounting report if no error occured. */ if(!Status) { char Buffer[80];
/* The duration timer is converted to a human readable string * with the versatile, but still constrained mad_timer_string() * function, in a fashion not unlike strftime(). The main * difference is that the timer is broken into several * values according some of it's arguments. The units and * fracunits arguments specify the intended conversion to be * executed. * * The conversion unit (MAD_UNIT_MINUTES in our example) also * specify the order and kind of conversion specifications * that can be used in the format string. * * It is best to examine mad's timer.c source-code for details * of the available units, fraction of units, their meanings, * the format arguments, etc. */ mad_timer_string(Timer,Buffer,"%lu:%02lu.%03u", MAD_UNITS_MINUTES,MAD_UNITS_MILLISECONDS,0); fprintf(stderr,"%s: %lu frames decoded (%s).\n", ProgName,FrameCount,Buffer); }
/* That's the end of the world (in the H. G. Wells way). */ return(Status); }
/**************************************************************************** * Program entry point. * ****************************************************************************/ int main(int argc, char *argv[]) {
int Status; int i=0;
FILE *file_fd; //文件 long file_len; //文件长度 long loops;
printf("This is a wav&mp3 play program.\n"); printf("Please add a file name and the audio rate!\nsuch as \"./test_music test.mp3\" \n\n\n"); //delay(100000);
文章评论(0条评论)
登录后参与讨论