MPEG 1.0/2.0/2.5 对声音的压缩分三层:Layer I、Layer II和Layer III。相比于Layer3,Layer2的解码就简单得多了。
1.变量初始化 申明的成员变量在构造方法内初始化,这些常量值是从解码规范的文档里直接COPY过来的。
2.帧的数据结构 以Layer2编码的文件按帧存放,解码时也是逐帧解码。每一帧内依次存放位分配信息、增益因子选择信息、增益因子、主数据。采用标准立体声编码的Layer2一帧内的主数据有12个粒度组(granule),一个粒度组内最多可有32个子带(subband),每个子带两个声道。每个声道内3组样本值连续存放,每一组32个值。
3.解码过程 Layer2编码不采用心理声学模型,解码端不用IMDCT;Layer2编码端没有哈夫曼编码。逆量化没有采用解码Layer3那样的查表法而是直接运算,Layer2的逆量化公式也比Layer3的简单得多。解码一帧Layer2只需6步,这6个步骤在decodeFrame方法内注解出来,每一步的细节一看就懂,不再赘述。解码Layer2的源码如下:
/* * Layer2.java -- MPEG 1.0/2.0/2.5 Audio Layer II Decoder * 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.sf.net/> */ package decoder; public final class Layer2 implements ILayer123 { private static Header header; private static BitStream bs; private static Synthesis filter; private static int nch, aidx, sblimit; private static byte[][] allocation; //[2][32] private static byte[][] nbal; //[5][] private static byte[][] sbquant_offset; //[5][] private static byte[][] scfsi; //[2][32] private static byte[][][] scalefactor; //[2][32][3] private static int[] cq_steps; //[17] private static float[] cq_C; //[17] private static float[] cq_D; //[17] private static byte[] cq_bits; //[17] private static byte[] bitalloc_offset; //[8] private static byte[][] offset_table; //[6][15] private static byte[] group; //[17] private static int[] samplecode; //[3] private static float[][][] syin; //[2][3][32] // Layer1也用到factor[] public static float[] factor; //[63] public Layer2(BitStream bitstream,Header h, Synthesis filter, int wch) { header = h; bs = bitstream; this.filter = filter; nbal = new byte[5][]; // ISO/IEC 11172-3 Table 3-B.2a nbal[0] = new byte[] { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2 }; // ISO/IEC 11172-3 Table 3-B.2b nbal[1] = new byte[] { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2 }; // ISO/IEC 11172-3 Table 3-B.2c nbal[2] = new byte[] { 4, 4, 3, 3, 3, 3, 3, 3 }; // ISO/IEC 11172-3 Table 3-B.2d nbal[3] = new byte[] { 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; // ISO/IEC 13818-3 Table B.1 nbal[4] = new byte[] { 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; // ISO/IEC 11172-3 Table 3-B.1 factor = new float[] {2.00000000000000f, 1.58740105196820f, 1.25992104989487f, 1.00000000000000f, 0.79370052598410f, 0.62996052494744f, 0.50000000000000f, 0.39685026299205f, 0.31498026247372f, 0.25000000000000f, 0.19842513149602f, 0.15749013123686f, 0.12500000000000f, 0.09921256574801f, 0.07874506561843f, 0.06250000000000f, 0.04960628287401f, 0.03937253280921f, 0.03125000000000f, 0.02480314143700f, 0.01968626640461f, 0.01562500000000f, 0.01240157071850f, 0.00984313320230f, 0.00781250000000f, 0.00620078535925f, 0.00492156660115f, 0.00390625000000f, 0.00310039267963f, 0.00246078330058f, 0.00195312500000f, 0.00155019633981f, 0.00123039165029f, 0.00097656250000f, 0.00077509816991f, 0.00061519582514f, 0.00048828125000f, 0.00038754908495f, 0.00030759791257f, 0.00024414062500f, 0.00019377454248f, 0.00015379895629f, 0.00012207031250f, 0.00009688727124f, 0.00007689947814f, 0.00006103515625f, 0.00004844363562f, 0.00003844973907f, 0.00003051757813f, 0.00002422181781f, 0.00001922486954f, 0.00001525878906f, 0.00001211090890f, 0.00000961243477f, 0.00000762939453f, 0.00000605545445f, 0.00000480621738f, 0.00000381469727f, 0.00000302772723f, 0.00000240310869f, 0.00000190734863f, 0.00000151386361f, 0.00000120155435f }; // cq_xxx: Layer II classes of quantization, ISO/IEC 11172-3 Table 3-B.4 cq_steps = new int[] { 3, 5, 7, 9, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767, 65535 }; cq_C = new float[] { 1.3333333f, 1.6f, 1.1428571f, 1.77777778f, 1.0666667f, 1.0322581f, 1.015873f, 1.007874f, 1.0039216f, 1.0019569f, 1.0009775f, 1.0004885f, 1.0002442f, 1.000122f, 1.000061f, 1.0000305f, 1.00001525902f }; cq_D = new float[] { 0.5f, 0.5f, 0.25f, 0.5f, 0.125f, 0.0625f, 0.03125f, 0.015625f, 0.0078125f, 0.00390625f, 0.001953125f, 0.0009765625f, 0.00048828125f, 0.00024414063f, 0.00012207031f, 0.00006103516f, 0.00003051758f }; cq_bits = new byte[] {5,7,3,10,4,5,6,7,8,9,10,11,12,13,14,15,16}; sbquant_offset = new byte[][] { // ISO/IEC 11172-3 Table 3-B.2a {7,7,7,6,6,6,6,6,6,6,6,3,3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0}, // ISO/IEC 11172-3 Table 3-B.2b {7,7,7,6,6,6,6,6,6,6,6,3,3,3,3,3,3,3,3,3, 3,3,3,0,0,0,0,0,0,0}, // ISO/IEC 11172-3 Table 3-B.2c {5,5,2,2,2,2,2,2}, // ISO/IEC 11172-3 Table 3-B.2d {5,5,2,2,2,2,2,2,2,2,2,2}, // ISO/IEC 13818-3 Table B.1 {4,4,4,4,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1} }; bitalloc_offset = new byte[] { 0, 3, 3, 1, 2, 3, 4, 5 }; offset_table = new byte[][] { { 0, 1, 16 }, { 0, 1, 2, 3, 4, 5, 16 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 }, { 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16 }, { 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 } }; group = new byte[] { 2, 3, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; allocation = new byte[2][32]; scfsi = new byte[2][32]; scalefactor = new byte[2][32][3]; samplecode = new int[3]; syin = new float[2][3][32]; //nch,aidx,sblimit... nch = header.getChannels(); int bitrate = header.getBitrate() / nch; if(header.getVersion() == Header.MPEG1) if(bitrate <= 48) aidx = (bitrate == 32) ? 3 : 2; else if(bitrate <= 80) aidx = 0; else aidx = (bitrate == 48) ? 0 : 1; else //mpeg 2.0/2.5 aidx = 4; byte[] limit = {27, 30, 8, 12, 30}; sblimit = limit[aidx]; } private void requantization(int index, int gr, int ch, int sb) { int nb, s, c; int nlevels = cq_steps[index]; if ((nb = group[index]) != 0) { // degrouping c = bs.getBits17(cq_bits[index]); for (s = 0; s < 3; s++) { samplecode[s] = c % nlevels; c /= nlevels; } nlevels = (1 << nb) - 1; //用于计算fractional } else { nb = cq_bits[index]; for (s = 0; s < 3; s++) samplecode[s] = bs.getBits17(nb); } for (s = 0; s < 3; s++) { float fractional = 2.0f * samplecode[s] / (nlevels + 1) - 1.0f; // s'' = C * (s''' + D) syin[ch][s][sb] = cq_C[index] * (fractional + cq_D[index]); // s' = factor * s'' syin[ch][s][sb] *= factor[scalefactor[ch][sb][gr >> 2]]; } } private void stereo(int index, int gr, int sb) { int nb, s, c; int nlevels = cq_steps[index]; if ((nb = group[index]) != 0) { c = bs.getBits17(cq_bits[index]); for (s = 0; s < 3; s++) { samplecode[s] = c % nlevels; c /= nlevels; } nlevels = (1 << nb) - 1; } else { nb = cq_bits[index]; for (s = 0; s < 3; s++) samplecode[s] = bs.getBits17(nb); } for (s = 0; s < 3; s++) { float fractional = 2.0f * samplecode[s] / (nlevels + 1) - 1.0f; // s'' = C * (s''' + D) syin[0][s][sb] = syin[1][s][sb] = cq_C[index] * (fractional + cq_D[index]); // s' = factor * s'' syin[0][s][sb] *= factor[scalefactor[0][sb][gr >> 2]]; syin[1][s][sb] *= factor[scalefactor[1][sb][gr >> 2]]; } } public void decodeFrame() throws Exception { int maindata_begin ,bound, sb, ch; int slots = header.getMainDataSlots(); bs.append(slots); maindata_begin = bs.getBytePos(); bound = (header.getMode() == 1) ? ((header.getModeExtension() + 1) * 4) : 32; if(bound > sblimit) bound = sblimit; /* * 1. Bit allocation decoding */ for (sb = 0; sb < bound; sb++) for (ch = 0; ch < nch; ch++) allocation[ch][sb] = (byte)bs.getBits9(nbal[aidx][sb]); // 2..4 bits for (sb = bound; sb < sblimit; sb++) allocation[1][sb] = allocation[0][sb] = (byte)bs.getBits9(nbal[aidx][sb]); /* * 2. Scalefactor selection information decoding */ for (sb = 0; sb < sblimit; sb++) for (ch = 0; ch < nch; ch++) if (allocation[ch][sb] != 0) scfsi[ch][sb] = (byte)bs.getBits9(2); else scfsi[ch][sb] = 0; /* * 3. Scalefactor decoding */ for (sb = 0; sb < sblimit; ++sb) for (ch = 0; ch < nch; ++ch) if (allocation[ch][sb] != 0) { scalefactor[ch][sb][0] = (byte)bs.getBits9(6); switch (scfsi[ch][sb]) { case 2: scalefactor[ch][sb][2] = scalefactor[ch][sb][1] = scalefactor[ch][sb][0]; break; case 0: scalefactor[ch][sb][1] = (byte)bs.getBits9(6); case 1: case 3: scalefactor[ch][sb][2] = (byte)bs.getBits9(6); } if ((scfsi[ch][sb] & 1) == 1) scalefactor[ch][sb][1] = scalefactor[ch][sb][scfsi[ch][sb] - 1]; } int gr, index, s; for (gr = 0; gr < 12; gr++) { /* * 4. Requantization of subband samples */ for (sb = 0; sb < bound; sb++) for (ch = 0; ch < nch; ch++) if ((index = allocation[ch][sb]) != 0) { index = offset_table[bitalloc_offset[sbquant_offset[aidx][sb]]][index - 1]; requantization(index, gr, ch, sb); } else syin[ch][0][sb] = syin[ch][1][sb] = syin[ch][2][sb] = 0; //mode=1(Joint Stereo) for (sb = bound; sb < sblimit; sb++) if ((index = allocation[0][sb]) != 0) { index = offset_table[bitalloc_offset[sbquant_offset[aidx][sb]]][index - 1]; stereo(index, gr, sb); } else for (ch = 0; ch < nch; ch++) syin[ch][0][sb] = syin[ch][1][sb] = syin[ch][2][sb] = 0; for (ch = 0; ch < nch; ch++) for (s = 0; s < 3; s++) for (sb = sblimit; sb < 32; sb++) syin[ch][s][sb] = 0; /* * 5. Synthesis subband filter */ for (ch = 0; ch < nch; ch++) for (s = 0; s < 3; s++) filter.synthesisSubBand(syin[ch][s], ch); } // for gr=0 to 12 /* * 6. Ancillary bits */ int discard = slots + maindata_begin - bs.getBytePos(); bs.skipBytes(discard); } }
下一篇:(十七)用JAVA编写MP3解码器——解码Layer1
相关推荐
Java编写的解码器是一种基于Java编程语言实现的软件组件,专门用于解析和播放MP3音频文件。在本文中,我们将深入探讨Java MP3解码器的原理、实现细节以及其在面试和项目中的应用。 首先,理解MP3格式是至关重要的。...
标签"java mp3 无JMF 解码器"进一步强调了这个解码器的关键特性:它是用Java语言编写的,专注于MP3格式,且不依赖JMF。这使得它具有跨平台性,可以在任何支持Java的系统上运行。 压缩包内的文件"jmp123_400_utf8_...
总结来说,Java MP3音频文件解码器是一个独立的、用纯Java编写的工具,用于将MP3文件转换为可处理的原始音频数据。它的设计和实现涉及了音频编码原理、数据处理优化以及Java编程技术,对于理解和处理音频数据的...
《纯JAVA的MP3解码器jmp:深入解析与应用》 MP3解码器是数字音频处理领域的重要工具,它能够将存储的MP3格式音频数据转化为人类可听的声音信号。在众多的MP3解码器中,“jmp123”以其独特的纯JAVA实现和出色的性能...
这些头文件对于使用解码器的开发者来说至关重要,因为它们提供了与解码器交互的API,包括打开MP3文件、初始化解码器、解码音频帧和获取解码后的声音数据等功能。 最后,`Makefile`是构建系统的配置文件,它定义了...
基于通用可编程GPU的视频编解码器——架构、算法与实现
2. **尺度因子解码**:基于帧头信息,解码器计算出尺度因子,这是用于逆量化的关键参数之一。 3. **哈夫曼解码**:通过对已压缩的音频数据进行哈夫曼解码,还原出原本的音频数据。 4. **逆量化**:此步骤通过逆向...
- 在使用`silk2mp3`解码器时,确保所有相关组件(lame.exe和silk_v3_decoder.exe)都在同一目录下,否则程序可能无法正常工作。 - 转换过程中可能涉及版权问题,确保你有权利处理和转换这些音频文件。 - 音频质量和...
- 文件`example`可能包含了一个使用mina编写的服务器或客户端程序,其中包含了自定义编解码器的应用实例。 - `MinaCodec`可能是一个包含编码器和解码器的类,我们来详细分析其工作流程: - 在编码器中,通常有一...
例如,Decoder.java负责核心的解码逻辑,Header.java处理MP3文件的头部信息,ILayer123.java处理Layer 1、2、3的相关解码工作,而BitStream.java则处理位流的读取。此外,还有用于处理HTTP流和文件随机访问的辅助类...
Java编写的MP3播放器是一种基于Java编程语言开发的软件应用,主要用于播放音频文件,特别是MPEG音频层3(MP3)格式的音乐。在Java中实现MP3播放功能涉及多个核心技术和组件,下面将详细阐述相关的知识点。 1. **...
通过学习和实践,可以增强对音频编码解码的理解,掌握核心算法,并能动手编写自己的MP3解码器。不过,要注意的是,实际开发过程中还需要考虑版权问题和兼容性问题,确保解码器能处理各种不同编码标准的MP3文件。
总的来说,"jmf_mp3解码器"结合JLayer1.0.1的使用,为Java开发者提供了一个跨平台的解决方案,使得在Java应用程序中播放MP3文件变得简单而有效。这种技术的应用场景广泛,可以用于开发音乐播放器、多媒体教学软件、...
在描述中提到的VC下的C工程源码,意味着这个编解码器是用C语言编写,并且可以在Visual C++环境下编译和运行。这对于软件开发者来说非常有用,因为C语言的源代码通常更容易理解和修改,便于进行二次开发和定制。 ...
在本文中,我们将深入探讨MP3解码器的工作原理、千千静听和酷狗这两款流行的音乐播放器如何利用解码库来播放MP3文件,以及libmad这个特定的解码库。 首先,我们来看看MP3解码的基本过程。当一个MP3文件被创建时,...
MP3是 ISO/MPEG标准的一部分,ISO/MPEG标准描述了使用高性能感知编码方案的音频压缩,此标准一直在不断更新以满足“质高量小”的追求,现已形成 MPEG Layer 1、Layer 2、Layer 3三个音频编码解码方案。MPEG Layer 3...
JMP123是专门为Java开发者设计的轻量级MP3解码器,支持多种MP3编码方式,包括MPEG-1 Audio Layer III(通常所说的MP3)和MPEG-2 Audio Layer III。该库提供了一套简单的API,使得开发者能够方便地集成到自己的应用...
2. **解码Layer 3**:使用`layer3.c`中的函数解析Layer 3的数据,这涉及到Huffman解码、反量化、反向斯特瑞辛变换等步骤。 3. **重建PCM信号**:将解码后的频谱数据转换为时间域的PCM(脉冲编码调制)信号,这是可以...
这个库可能包含了MP3解码器,将压缩的MP3数据转换为Java Sound API可以理解和播放的原始PCM音频数据。使用这个库,开发者无需关心底层的解码细节,只需调用Java Sound API提供的类和方法,就能实现MP3文件的播放。 ...