1.定义解码一帧的接口 ILayer123
Layer1、Layer2和Layer3这三个类都实现了ILayer123的decodeFrame方法。
// ILayer123.java package jmp123.decoder; public interface ILayer123 { public void decodeFrame(int intFirstChannel, int intLastChannel) throws Exception; }
2.封装解码器 对帧头解码之后可以知道当前待解码的文件是采用MPEG Audio的哪一层压缩方式,根据压缩层的 不同,解码器自动初始化Layer1、Layer2和Layer3这三个类中的某一个实例。你也就明白了为什么我们把这三 个类的大部分初始化放在其构造方法内的道理了。class Decoder的decodeFrame方法完成解码和播放一帧的任务。
//Decoder.java package jmp123.decoder; import jmp123.output.Audio; public final class Decoder { public final static int CH_LEFT = 0; public final static int CH_RIGHT = 1; public final static int CH_BOTH = 2; private static int intFirstChannel, intLastChannel; private static int intChannels; private static int intOutputChannel; private static int intForwardMultiple; private ILayer123 layer123; public Decoder(BitStream objBS, Header objHeader) { intChannels = objHeader.getChannels(); switch(objHeader.getLayer()) { case 1: layer123 = new Layer1(objBS, objHeader); break; case 2: layer123 = new Layer2(objBS, objHeader); break; case 3: layer123 = new Layer3(objBS, objHeader); break; } // 设置参数缺省值 intForwardMultiple = 1; setOutputChannel(CH_BOTH); } public void decodeFrame() throws Exception { layer123.decodeFrame(intFirstChannel, intLastChannel); if(intChannels == 1 && intOutputChannel == CH_BOTH) { int i; byte[] buf = Synthesis.bytePCMBuf; for(i = 0; i < 4608; i += 4) { buf[i+2] = buf[i]; buf[i+3] = buf[i+1]; } } if(intForwardMultiple == 1) Audio.write(Synthesis.bytePCMBuf, 4608); else { //变速变调? int i, k = 0, i0, i1, N = intForwardMultiple; byte[] buf = Synthesis.bytePCMBuf; for(i = 0; i < 4608; i += N << 2) { i0 = (buf[1+i] << 8) | (buf[2+i] & 0xff); i1 = (buf[3+i] << 8) | (buf[4+i] & 0xff); buf[k++] = (byte)i0; buf[k++] = (byte)(i0 >>> 8); buf[k++] = (byte)i1; buf[k++] = (byte)(i1 >>> 8); } Audio.write(buf, k); } } /* * intWhichChannel - 输出的声道: CH_LEFT/CH_RIGHT/CH_BOTH */ public static void setOutputChannel(int intWhichChannel) { intOutputChannel = intWhichChannel; switch (intWhichChannel) { case CH_LEFT: intFirstChannel = intLastChannel = 0; break; case CH_RIGHT: intFirstChannel = intLastChannel = 1; break; case CH_BOTH: default: if(intChannels == 1) intFirstChannel = intLastChannel = 0; else { intFirstChannel = 0; intLastChannel = 1; } break; } } public static void setForwardMultiple(int intMultiple) { if(intMultiple < 1 || intMultiple > 8) intMultiple = 1; intForwardMultiple = intMultiple; } }
解码、播放一个文件的类class PlayingThread:
// PlayingThread.java package jmp123.player; import jmp123.decoder.BitStream; import jmp123.decoder.Decoder; import jmp123.decoder.Header; import jmp123.instream.IRandomAccess; import jmp123.instream.BuffRandAcceFile; import jmp123.instream.BuffRandAcceURL; import jmp123.output.Audio; public final class PlayingThread implements Runnable { private Decoder objDec123; private Header objHeader; private IRandomAccess objIRA; public PlayingThread(String strFileName) throws Exception { strFileName.toLowerCase(); if (strFileName.startsWith("http://")) objIRA = new BuffRandAcceURL(strFileName); else objIRA = new BuffRandAcceFile(strFileName); objHeader = new Header(objIRA); } public void run() { int frame_count = 0; Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 2); try { if (objHeader.syncFrame() == false) return; objHeader.printHeaderInfo(); objDec123 = new Decoder(new BitStream(objIRA), objHeader); Audio.open(objHeader.getFrequency()); // Playing while (true) { objDec123.decodeFrame(); if (objHeader.syncFrame() == false) break; if ((++frame_count & 0x7) == 0x7) //每8帧(44.1kHz,时长约0.2s)更新一次 objHeader.printState(); } objHeader.printState(); Audio.close(); } catch (Exception e) { //e.printStackTrace(); } objIRA.close(); } }
MP3解码引擎(engine)的编写过程就讲解完了,作为一个完整的程序,应该把播放器代码也出来,我只 写了一个简单的命令行播放器意思意思。MP3解码的关键技术方面的资料不太容易查阅到,其中泛泛而谈的比较 多,网上盛行互相抄袭。开放源代码的程序是我们获得这些细节的一种途径。
这话说得狠牛,MPG123是优秀的MP3解码器,它的算法的确优秀。但他们不提供技术方面的其 它文档,只从源码码琢磨解码细节是一件比较痛苦的事。我花时间把最关键的“多相合成滤波”算法 整理出来,就是前面的贴子《(十四)用JAVA编写MP3解码器——多相合成滤波》和《MP3解码之DCT(32→64)快 速算法的展开》。如果你想了解MP3解码技术细节的话,强烈建议你看看,一是向别人的堪称经典的优秀算法学 习,二是希望有一天能有这方面的爱好者提出自己的更为优秀的算法。
3.迷你播放器 经过上述封装之后,写一个基于命令行的迷你播放器就是很简单的事情了。播放器通常的做法 是将解码、播放放入一个线程,把播放控制放在另一个线程。对基于命令行的播放器来说,播放时不交互, 开不开线程都可以。
PlayingThread类完成了对播放一个文件的封装,实现了Runnable接口是为了便于实现以“后台”方式解码、播 放。
class PlayingThread中的这一行:
Thread.currentThread().setPriority(Thread.NORM_PRIORITY + 2);
为解码播放线程设置了更高的优先级,这对流畅解码播放是很有必要的,防止你在运行其它稍 复杂的任务时播放时断时续。
命令行播放器class Player :
/* * Player.java -- JAVA MPEG 1.0/2.0/2.5 Layer I/II/III mini Player * 简称:jmp123 * Copyright (C) 2010 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * If you would like to negotiate alternate licensing terms, you may do * so by contacting the author: <http://jmp123.sourceforge.net/> */ package jmp123.player; import jmp123.player.PlayingThread; /* * class Play -- 简单的命令行播放器示例 */ public class Player { public static void main(String args[]) { if (args.length > 0) { try { new Thread(new PlayingThread(args[0])).start(); //new PlayingThread(args[0]).run(); } catch (Exception e) {} } else showMsg(); } //------------------------------------------------------------------------- private static void showMsg() { System.out.println( "jmp123 - JAVA mini MPEG 1.0/2.0/2.5 Layer I/II/III Decoder and Player\n" +"Copyright (C) 2010 LeiW (Email:ly2697@sina.com)\n\n" +"This program is free software: you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation, either version 3 of the License, or\n" +"(at your option) any later version.\n\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n\n" +"Usage: \njava -jar jmp123.jar <mp3 FileName or URL>"); } }
其main方法内的 new Thread(new PlayingThread(args[0])).start();以新开一个线程以“后台”方式解码、播放;
其main方法内的 //new PlayingThread(args[0]).run();在主程序中解码播放。
你可以在这两行中任选一行来实现你的解码、播放方式。如果你打算写调用本解码库的GUI播放器,需要 注意两点:(1)必须开线程以“后台”方式解码播放;(2)控制“播放/暂停”调用静态方法Audio.(true)暂停音 频输出并阻塞解码过程,调用Audio(false)继续音频输出和解码。
播放器中只需用一行代码就可以完成对解码、播放一个文件的调用,是不是很方便呢?
需要指出的是,播放时快进的同时不回放监听的话就超简单,快进同时能够监听是一件很难实现的事,涉及这 方面技术的有许多专利算法,包括大名鼎鼎的杜比司的算法。他们的算法不得而知。由于要改变抽样的样本数 使噪声急剧增加,我尝试过几种方法消噪,结果都不理想,难道非得将时域信号转换为频域,经过滤波后再转 换回来?有简单点的折衷办法把噪声降低到可接受的范围吗?也希望能有这方面的爱好者研究研究有所发现。
附件里jmp123_xxx(xxx表示日期)内包含:本程序JAR包、两个批命令播放示例、一个自述文件Readme.txt、 一个许可协议文本。如果你在试用本程序时发现bug,楼下有请。
文件下载 在jmp123主页 http://jmp123.sourceforge.net/ (或 ttp://jmp123.sf.net )下载最新的程序和源 码。源码和程序的API文档已经放上去了~
【全文完】
上一篇:(十七)用JAVA编写MP3解码器——解码Layer1
相关推荐
Java编写的解码器是一种基于Java编程语言实现的软件组件,专门用于解析和播放MP3音频文件。在本文中,我们将深入探讨Java MP3解码器的原理、实现细节以及其在面试和项目中的应用。 首先,理解MP3格式是至关重要的。...
读取MP3文件需要使用Java的I/O流,如FileInputStream和BufferedInputStream,来高效地读取和处理文件内容。 8. **用户界面设计**: 使用JavaFX或Swing库可以创建包含播放/暂停按钮、音量控制器、播放列表等元素的...
标签"java mp3 无JMF 解码器"进一步强调了这个解码器的关键特性:它是用Java语言编写的,专注于MP3格式,且不依赖JMF。这使得它具有跨平台性,可以在任何支持Java的系统上运行。 压缩包内的文件"jmp123_400_utf8_...
【作品名称】:基于jmp123解码器的mp3播放器 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【项目介绍】: java mp3播放器,解码...
因此,更常见的方式是将解码任务交给外部专用的硬件,如独立的MP3解码芯片,或者使用嵌入式系统上的软件解码器,如MadPlayer或MAD Library。软件解码器需要在微控制器上运行,这需要考虑内存限制和处理速度,因此...
总结来说,Java MP3音频文件解码器是一个独立的、用纯Java编写的工具,用于将MP3文件转换为可处理的原始音频数据。它的设计和实现涉及了音频编码原理、数据处理优化以及Java编程技术,对于理解和处理音频数据的...
MP3解码器和MP3播放器是音频处理领域中的两个关键组件,它们在数字音频技术中占有重要地位。在本项目中,开发者使用了经典的Visual C++ 6.0(简称VC6.0)作为开发环境,创建了一个完整的MP3播放解决方案。这个解决...
【标题】"易语言制作——MP3播放器"揭示了这个项目的核心是使用易语言(Easy Language)开发的一款能够播放MP3音乐的软件。易语言是一种面向初学者和专业人士的中文编程语言,它以简洁易懂的语句设计,使得编程更加...
《纯JAVA的MP3解码器jmp:深入解析与应用》 MP3解码器是数字音频处理领域的重要工具,它能够将存储的MP3格式音频数据转化为人类可听的声音信号。在众多的MP3解码器中,“jmp123”以其独特的纯JAVA实现和出色的性能...
MP3播放器与MP3解码器是音频处理领域中的两个关键组件,它们在数字音乐体验中扮演着重要角色。MP3是一种广泛使用的音频压缩格式,它能够在保持相对高质量的同时,大幅度减小音频文件的大小,便于存储和分享。 ### ...
这个压缩包文件的标题揭示了它的核心内容——一个使用jmp123解码器的MP3播放器项目。jmp123是一个开源的、用C语言编写的MP3解码库,它能够解析并解码MP3音频文件,将压缩的数字音频数据转化为可以播放的格式。这个...
《使用Java编写MP3播放器》是一份关于利用Java编程语言实现MP3音频解码的文档。MP3作为广泛使用的音频压缩格式,其解码技术是数字音频处理领域的重要组成部分。该文档旨在介绍如何利用Java编写一个MP3解码器,并提供...
MP3解码器控制台播放器是一种用于在命令行界面(控制台)中播放MP3音频文件的应用程序。这类播放器通常由程序员或对技术有深入理解的用户使用,因为它们提供了一种直接且轻量级的方式来播放音频,而不依赖于图形用户...
基于通用可编程GPU的视频编解码器——架构、算法与实现
Java编写的简单MP3播放器代码是一个典型的Java应用程序,它实现了音频播放功能,特别是针对MP3格式的音乐文件。在本文中,我们将深入探讨这个项目的各个方面,包括Java编程语言的基础,MP3音频处理,以及XML数据处理...
开发者可以通过分析源码,学习如何开启和使用硬件解码器,以实现更节能、高性能的播放。 此外,乐看播放器的源代码可能包含了自定义控件和用户界面设计。在Android应用中,UI设计直接影响用户体验。通过研究源码,...
在本文中,我们将深入探讨如何使用Java编程语言来实现一个MP3播放器。MP3播放器是音频处理软件,能够读取、解码并播放MP3格式的音频文件。Java以其跨平台的特性,成为开发此类应用的理想选择。让我们一起探讨实现这...
解码包是一种集合了多种音视频解码器的软件,它的主要作用是帮助播放器识别并处理各种编码格式的媒体文件。在"Windows Media Player 解码包"中,包含了能够使Windows Media Player支持更多格式的解码器,如DivX、...
3. **音频处理**:理解音频编码和解码原理,以及如何使用Java的AudioSystem类和其他音频库(如Java Layer)进行音频播放。 4. **文件I/O操作**:读取M3U播放列表文件,获取MP3文件的路径,并加载到播放器中。 5. *...