java编写mp3播放器.docx_第1页
java编写mp3播放器.docx_第2页
java编写mp3播放器.docx_第3页
java编写mp3播放器.docx_第4页
java编写mp3播放器.docx_第5页
已阅读5页,还剩151页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

(一)用JAVA编写MP3解码器前言发布: 2010-8-27 09:49 | 作者: wxhfree | 来源: 迈胜 IT人才培训机构MP3解码程序很多,杂志上、网络上关于这方面的讨论很多,C语言开源的著名的MP3解码程序有mpg123和libmad,JAVA语言(当然是开源的了)有JLayer(个这写得不敢恭维,乱),其它的还可以在网络上搜索到很多。拜读了这些资料及源码,发现有这样几个特点: 1、这些程序多是国外作者写的。国内有关系统介绍MP3解码技术方面的文章不多,我在网络上搜索到的至少有两篇全面讨论MP3解码的论文,一篇的是作者是台湾的,另一篇的作者是贵州大学的,只能看到他们论文的目录和摘要。 2、mpg123和libmad(定点数解码)等开源程序的MP3解码关键技术如哈夫曼解码、多相合成滤波等都可以进一步改进。特别是影响解码效率的“多相合成滤波”,解码一帧双声道的MP3,矩阵运算要被调用72次,每次矩阵运算要进行大量的浮点运算;哈夫曼解码都采用二叉树结构逐位解码。 3、这些解码程序没有作比较详细的说明,读懂程序需要花去很多时间。 我的源码写好已经有很长一段时间了,这段时间又回头过去看了一遍MP3解码的标准ISO/IEC 11172-3,打算在这儿把MP3解码过程作一个简要的分析,抛砖引玉,欢迎批评指正。谢谢你的臭鸡蛋,谢谢你的烂番茄。 音频压缩的格式很多,MP3以其固有的优势,一直是音频编码的主流格式。随着技术的发展,存储介质的容量及存取速度都会发生革命性的变化,加之以后网络带宽也极有可能大幅度提高,那时,有损压缩在很多时候都将被无损压缩取代。MP3还能走多远,谁又说得清呢? 用JAVA编写MP3解码器将对实现MP3解码的技术细节作介绍,本着开源的精神,文中给出完整的MP3解码的JAVA源代码。即使你之前对JAVA语言不太熟悉,由于JAVA的语法类似于C语言,也是很容易看懂的。【源码测试】MP3解码的JAVA源码和原理简介在本站论坛和本站我的博客上陆续写出来,这需要一个比较漫长的过程。Windows操作系统,JDK安装在F:jdk1.6.0_12,各源文件(*.java)的目录结构如下:F:WORKSPACEJMLSRCdecoder Decoder.java HuffmanBits.java BitStream.java Layer3.java Synthesis.java Header.java Layer2.java ILayer123.java Layer1.javatest Player.javainstream IRandomAccess.java BuffRandAcceFile.java HttpReader.java BuffRandAcceURL.java IWriterCallBack.java Writer.java TagThread.javatag ID3Tag.javaoutput Audio.javaWindows平台下,建立对各源文件编译、打包的批命令文件F:workspacejmlbuild-win32.cmd,内容如下:echo offecho 稍候.rem -rem JAVA mini MP3 Player WIN32 Build Scriptrem -set JAVA_HOME=F:jdk1.6.0_12set JML=.set LIB_PATH=%JML%binif not exist %LIB_PATH% md %LIB_PATH%rem set CLASSPATH=%JAVA_HOME%libtools.jarset PATH=%PATH%;%JAVA_HOME%binset SRC_DECODER=%JML%srcdecoderset SRC_INSTREAM=%JML%srcinstreamset SRC_OUTPUT=%JML%srcoutputset SRC_TAG=%JML%srctagset SRC_PLAYER=%JML%srctestrem -javac -classpath %LIB_PATH% -d %LIB_PATH% %SRC_TAG%*.javajavac -classpath %LIB_PATH% -d %LIB_PATH% %SRC_INSTREAM%*.javajavac -classpath %LIB_PATH% -d %LIB_PATH% %SRC_OUTPUT%*.javajavac -classpath %LIB_PATH% -d %LIB_PATH% %SRC_DECODER%*.javajavac -classpath %LIB_PATH% -d %LIB_PATH% %SRC_PLAYER%*.javarem -cd %LIB_PATH%jar cvfm .jplay123.jar .manifest.mf *cd %JML%rem -pauseecho on先在F:WORKSPACEJML文件夹下建立一个manifest.mf文件,第一行:Main-Class: test.Player第二行是空行。从本站论坛或本站我的博客中COPY相应的JAVA源码到上文所示的目录下,建立好manifest.mf文件之后,运行build-win32.cmd,在F:workspacejml目录生成jplay123.jar文件。播放单个MP3的命令行示例:java -jar jplay123.jarE:MP3a2.mp3java -jar jplay123.jar/mp3/汤潮-那滋味.mp3播放某目录下MP3文件批命令示例:echo offecho JAVA mini MP3 Player 0.0.1echo.rem #设置路径#set mp3path=E:MP3set df=%mp3path%afor /f delims=* %a in (dir %mp3path%*.mp3 /b) do echo 正在播放:%df% & java -jar jplay123.jar %df% & echo.pauseecho on【提示】MP3的技术文档,获得许可方能使用。如果本系列贴子侵犯了您相关权利,通知我,我第一时间更改或删除。【再费几句话】 无论用什么样的编程语言,编写出MPEG 1.0/2.0/2.5音频解码器是不难的;编写出兼顾速度和存储开销的高效的解码器是很难的。 我所知道的解码器,解码结果没有区别,不同的是效率问题。有人对不同的播放器作出这样的主观听感上不同评价:柔和、甜美、声音发干、偏冷等。这样的评价是值得商榷的,如果解码器是开源的,调试运行可以直接看到解码最后一步送入音频硬件的PCM数据,如果解码器不是开源的,可以编程抓取其PCM数据出来看,我测试几个解码器的结果是没的区别的。解码中间过程的计算误差是存在的,不同的解码器对同一输入解码出的中间结果(double类型)不同,经过最后一步乘上32767再取整得到16位整型的PCM,不同的解码器对同一输入结果就是相同的了,包括最古老的Xing MP3解码器和最新的MPG123、LIBMAD。所以不要担心你美妙的歌曲被解码器折腾得不动听了,如果追求好的音质,用专业的声卡配高品质的音箱才行。 JAVA版的MP3播放器的屏幕截图1.jpg(二)用JAVA编写MP3解码器帧头信息解码发布: 2010-8-27 14:58 | 作者: wxhfree | 来源: 迈胜 IT人才培训机构帧头 共4字节,从高位到低位这32比特的含义如下:2.jpgbitrate_index主数据的位率(单位KBits/s),例如对192Kbps的MP3,解码时每秒读取192*1024/8=24576字节的码流,如果你是从网络在线播放要确保下载速度不低于192Kbps/s才能流畅播放。3.jpgsampling_freq PCM样本的采样率,用它来初始化音频硬件以播放MP3。mpeg1.0时其值0,1,2分别对应的采样是44100Hz,48000Hz,32000Hzmpeg2.0时其值0,1,2分别对应的采样是22050Hz,24000Hz,16000Hzmpeg2.5时其值0,1,2分别对应的采样是11025Hz,12000Hz,8000Hzmode 声道模式,其值表示的含义:0立体声(stereo)1联合立体声(joint stereo)2双声道(dual channel)3单声道(single channel)联合立体声(joint stereo) 采用联合立体声编码方式的两个声道具有关联性。例如MS_stereo将两个声道相加、相差后处理,相减后去掉了左右声道相同的成份,后续的压缩可得到更高的压缩率。extension 其值表示采用哪种联合立体声方式4.jpg帧头信息解码除解码上述信息外,还要进行帧同步、计算帧长、计算帧边信息长度等供后续解码。考虑到MP3文件可能有的数据帧损坏,帧同步时还要解析下一帧的帧头来确定当前的4字节是否是有效的帧头;一帧的长度应该用槽(slot)来描述,MPEG 1.0/2.0/2.5 对声音共有三种压缩方式:Layer1、Layer2和Layer3,每种压缩方式一帧的槽数是固定的,Layer3一槽就是一个字节,据此可以计算出帧的字节数;帧边信息的长度根据MP3帧头解码出的表示立体声编码模式(mode)和MPEG的版本来计算。Header.java源程序: CODE:package decoder;import instream.IRandomAccess;public final class Header public static final int MPEG1 = 3; public static final int MPEG2 = 2; public static final int MPEG25 = 0; public static final int MAX_FRAMESIZE = 1732; /MPEG 1.0/2.0/2.5, Lay 1/2/3 /* * intBitrateTableintLSFintLayer-1intBitrateIndex */ private static final int intBitrateTable = /MPEG 1 /Layer I 0,32,64,96,128,160,192,224,256,288,320,352,384,416,448, /Layer II 0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384, /Layer III 0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320, , /MPEG 2.0/2.5 /Layer I 0,32,48,56,64,80,96,112,128,144,160,176,192,224,256, /Layer II 0,8,16,24,32,40,48,56,64,80,96,112,128,144,160, /Layer III 0,8,16,24,32,40,48,56,64,80,96,112,128,144,160, ; /* * intSamplingRateTableintVersionIDintSamplingFrequency */ private static final int intSamplingRateTable = 11025 , 12000 , 8000,0, /MPEG Version 2.5 0,0,0,0, /reserved 22050, 24000, 16000 ,0, /MPEG Version 2 (ISO/IEC 13818-3) 44100, 48000, 32000,0 /MPEG Version 1 (ISO/IEC 11172-3) ; /* * intVersionID: 2 bits * 00MPEG Version 2.5 (unofficial extension of MPEG 2); * 01reserved; * 10MPEG Version 2 (ISO/IEC 13818-3); * 11MPEG Version 1 (ISO/IEC 11172-3). */ private static int intVersionID; /* * intLayer: 2 bits * 11 Layer I * 10 Layer II * 01 Layer III * 00 reserved * 已换算intLayer=4-intLayer: 1-Layer I; 2-Layer II; 3-Layer III; 4-reserved */ private static int intLayer; /* * intProtectionBit: 1 bit * 1no CRC; * 0protected by 16 bit CRC following header. */ private static int intProtectionBit; /* * intBitrateIndex: 4 bits */ private static int intBitrateIndex; /* * intSamplingFrequency: 2 bits * 00 44.1kHz * 01 48kHz * 10 32kHz * 11reserved */ private static int intSamplingFrequency; private static int intPaddingBit; /* * intMode: 2 bits * 00Stereo; * 01Joint Stereo (Stereo); * 10Dual channel (Two mono channels); * 11Single channel (Mono). */ private static int intMode; /* * intModeExtension: 2 bits * intensity_stereo boolMS_Stereo * 00 off off * 01 on off * 10 off on * 11 on on */ private static int intModeExtension; private static boolean boolSync; private static int intFrameSize; private static int intMainDataSlots; /main_data length private static int intSideInfoSize; /side_information length private static int intLSF; private static int intStandardMask = 0xffe00000; private static boolean boolMS_Stereo, boolIntensityStereo; private static IRandomAccess iraInput; public Header(IRandomAccess in_rai) iraInput = in_rai; public boolean isMSStereo() return boolMS_Stereo; public boolean isIStereo() return boolIntensityStereo; public int getBitrate() return intBitrateTableintLSFintLayer-1intBitrateIndex; public int getBitrateIndex() return intBitrateIndex; public int getChannels() if(intMode = 3) return 1; return 2; public int getMode() return intMode; public int getModeExtension() return intModeExtension; public int getVersion() return intVersionID; public int getLayer() return intLayer; public int getSampleFrequency() return intSamplingFrequency; public int getFrequency() return intSamplingRateTableintVersionIDintSamplingFrequency; public int getMainDataSlots() return intMainDataSlots; public int getSideInfoSize() return intSideInfoSize; public int getFrameSize() return intFrameSize; private void parseHeader(int h) intVersionID = (h 19) & 3; intLayer = 4 - (h 17) & 3; intProtectionBit = (h 16) & 0x1; intBitrateIndex = (h 12) & 0xF; intSamplingFrequency = (h 10) & 3; intPaddingBit = (h 9) & 0x1; intMode = (h 6) & 3; intModeExtension = (h 4) & 3; boolMS_Stereo = intMode = 1 & (intModeExtension & 2) != 0; boolIntensityStereo = intMode = 1 & (intModeExtension & 0x1) != 0; intLSF = (intVersionID = MPEG1) ? 0 : 1; switch (intLayer) case 1: intFrameSize= intBitrateTableintLSF0intBitrateIndex * 12000; intFrameSize /= intSamplingRateTableintVersionIDintSamplingFrequency; intFrameSize= (intFrameSize+intPaddingBit)2); break; case 2: intFrameSize= intBitrateTableintLSF1intBitrateIndex * 144000; intFrameSize /= intSamplingRateTableintVersionIDintSamplingFrequency; intFrameSize += intPaddingBit; break; case 3: intFrameSize= intBitrateTableintLSF2intBitrateIndex * 144000; intFrameSize /= intSamplingRateTableintVersionIDintSamplingFrequency(intLSF); intFrameSize += intPaddingBit; /计算帧边信息长度 if(intVersionID = MPEG1) intSideInfoSize = (intMode = 3) ? 17 : 32; else intSideInfoSize = (intMode = 3) ? 9 : 17; break; default: break; /计算主数据长度 intMainDataSlots = intFrameSize - 4 - intSideInfoSize; if(intProtectionBit = 0) intMainDataSlots -= 2; / - / syncXXX: 帧同步 private static int intFrameCounter; /当前帧序号 public boolean syncFrame()throws Exception if(syncSearch() = false) return false; if (intProtectionBit = 0) headerCRC(); intFrameCounter+; return true; /* * 帧同步: 查找到帧同步字后与下一帧的intVersionID等比较,确定是否找到有效的同步字. * * 怎样更简单、有效帧同步? */ private boolean syncSearch() throws Exception int h, cur_mask = 0; boolean bfind = false; long start_pos = iraInput.getFilePointer(); while(!bfind) h = syncWord(); parseHeader(h); /若intVersionID等帧的特征未改变,不用与下一帧的同步头比较. if(boolSync) bfind = true; break; /与下一帧的同步头比较 cur_mask = 0xffe00000; /syncword cur_mask |= h & 0x180000; /intVersionID cur_mask |= h & 0x60000; /intLayer cur_mask |= h & 0x60000; /intSamplingFrequency /cur_mask |= h & 0xC0; /intMode /intModeExtension 不是始终不变. byte b4 = new byte4; if(iraInput.dump(intFrameSize-4, b4, 0, 4) 0xffff) System.out.println(n搜索 64K 未发现MP3帧后放弃。); break; if(!boolSync) boolSync = true; if(bfind & intStandardMask = 0xffe00000) /是第一帧: intStandardMask = cur_mask; longAllFrameSize = iraInput.length(); longFrameOffset = iraInput.getFilePointer()-4; longAllFrameSize -= longFrameOffset; parseVBR(); getTrackFrames(); getDuration(); printHeaderInfo(); /*System.out.println(Begining of syncword: bytes + (iraInput.getFilePointer()-4) + , frame_number = + frame_number);*/ return bfind; private int syncWord() throws Exception int ioff = -4; int h = 0, read_byte = 0; do if(read_byte = iraInput.read() = -1) return 0; ioff+; h = (h 0) boolSync = false; return h; private static boolean syncCheck(int h) if (h & intStandardMask) != intStandardMask | (h 19) & 3) = 1) / version ID:01 - reserved | (h 17) & 3) = 0) / Layer index: 00 - reserved | (h 12) & 0xf) = 0xf) | (h 12) & 0xf) = 0) | (h 10) & 3) = 3) return false; return true; private static int makeInt32(byte b, int off) int h = boff & 0xff; h = 8; h |= boff + 1 & 0xff; h = 8; h |= bof

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论