Java Mp3转化WAV/PCM音频数据,解码详细解析,提取每一帧数据集合/比特流/播放,一行代码!

导言


解码过程

Mp3结构

MP3 文件一般分为三部分:ID3V2,Frame,ID3V1也属于帧,叫标签帧,Frame 部分叫数据帧,在MP3 文件内不一定有标签帧,但一定有数据帧.

ID3V2解析

开始处,长度为10字节,结构如下:

标签头

    public static int discard(int num){int result = 0, mask = 0x7F;while ((mask ^ 0x7FFFFFFF)==1){result = num & ~mask;result <<= 1;result |= num & mask;mask = ((mask + 1) << 8) - 1;num = result;}return result;}

恢复:

    public static int recovery(int num) {byte[] D = new byte[4];D[0] = (byte) (num & 0xff);D[1] = (byte) (num >> 8 & 0xff);D[2] = (byte) (num >> 16 & 0xff);D[3] = (byte) (num >> 24 & 0xff);int Result = 0x0;Result = Result | D[0];Result = Result | (D[1] << 7);Result = Result | (D[2] << 14);Result = Result | (D[3] << 21);return Result;}

标签帧

Frame解析-标签帧

所有的Mp3文件的数据帧开始的两个字节都必需是“FF FA”或者 “FF FB”

名称

位长

说 明

同步信息

11

第2字节

所有位均为1,第1字节恒为FF。

版本

2

00-MPEG 2.5 ,01-未定义,10-MPEG 2 ,11-MPEG 1

2

00-未定义 ,01-Layer 3,10-Layer 2 ,11-Layer 1

CRC校验

1

0-校验 ,1-不校验

位率

4

第3字节

取样率,单位是kbps,如:采用MPEG-1 Layer 3,64kbps是,值为0101。

bits V1,L1---V1,L2---V1,L3---V2,L1---V2,L2---V2,L3

0000--free--free--free--free--free--free

0001--32--32--32--32(32)--32(8)--8 (8)

0010--64--48--40--64(48)--48(16)--16 (16)

0011--96--56--48--96(56)--56(24)--24 (24)

0100--128--64--56--128(64)--64(32)--32 (32)

0101--160--80--64--160(80)--80(40)--64 (40)

0110--192--96--80--192(96)--96(48)--80 (48)

0111--224--112--96--224(112)--112(56)--56 (56)

1000--256--128--112--256(128)--128(64)--64 (64)

1001--288--160--128--288(144)--160(80)--128 (80)

1010--320--192--160--320(160)--192(96)--160 (96)

1011--352--224--192--352(176)--224(112)--112 (112)

1100--384--256--224--384(192)--256(128)--128 (128)

1101--416--320--256--416(224)--320(144)--256 (144)

1110--448--384--320--448(256)--384(160)--320 (160)

1111--bad--bad--bad--bad--bad--bad

V1 - MPEG 1,V2 - MPEG 2 and MPEG 2.5

L1 - Layer 1 ,L2 - Layer 2 , L3 - Layer 3

"free" :位率可变 "bad" :不允许值

采样频率

2

MPEG-1: 00-44.1kHz ,01-48kHz ,10-32kHz ,11-未定义

MPEG-2: 00-22.05kHz , 01-24kHz ,10-16kHz ,11

MPEG-2.5: 00-11.025kHz ,01-12kHz ,10-8kHz ,11-未定义

帧长调节

1

用来调整文件头长度,0-无需调整,1-调整

保留字

1

没有使用

声道模式

2

第 4字节

00-立体声 ,01-联合立体声(是基于帧与帧完成的), 10-双声道 ,11-单声道

扩充模式

2

声道是01时用:Value强度立体声,MS立体声

00 off off

01 on off

10 off on

11 on on

版权

1

0-不合法 1-合法

原版标志

1

0-非原版 1-原版

强调方式

2

用于声音经降噪压缩后再补偿的分类,很少用到,今后也可能不会用。

00-未定义 01-50/15ms 10-保留 11-CCITT J.17

帧长计算

MPEG帧的采样表

MPEG 1

MPEG 2(LSF)

MPEG 2.5(LSF)

Layer 1

384

384

384

Layer 2

1152

1152

1152

Layer 3

1152

576

576

每帧播放时长

ID3V1尾部说明

字节

长度-bytes

内容

1-3(A)

3

存储了“TAG”字符,表示ID3V1标准,后面歌曲信息。

4-33(B)

30

歌名称

34-63(C)

30

作者名称

64-93(D)

30

专辑名称

94-97(E)

4

年份

98-125(F)

28

附注

126(G)

1

保留位

127(H)

1

音轨号

127(I)

1

MP3音乐类别一共147种

Mp3解码还原流程

MP3解码经MP3编码方式压缩后的音频数据还原成原始PCM数据的过程。

解码导言

上代码

最适合新手的,最快捷的

import IOS_SHOGUN_Component.__response;
import IOS_SHOGUN_Component.decodeAean.Mp3DecodeException;import javax.sound.sampled.SourceDataLine;
import java.io.*;
public class Java {public static void main(String[] X) throws IOException {try {try (SourceDataLine Mp3 = __response.Debug_PlayMp3("Mp3地址")) {}} catch (Mp3DecodeException e) {throw new RuntimeException(e);}}
}

直接导出数据

两种存储方式

TaskList<String>方式

内容:

注意:

import IOS_SHOGUN_Component.TaskList;
import IOS_SHOGUN_Component.__response;
import IOS_SHOGUN_Component.decodeAean.Mp3DecodeException;
import java.io.*;
public class Java {public static void main(String[] X) throws IOException {try {TaskList<String> Data=__response._mp3_extract_mode_Base64("路径");//保存了每一帧的PCM解码数据byte[] PCM=__response._base64_T_X2(Data.get(0));} catch (Mp3DecodeException e) {throw new RuntimeException(e);}}
}

流方式

import IOS_SHOGUN_Component.__response;
import IOS_SHOGUN_Component.decodeAean.Mp3DecodeException;
import java.io.*;
public class Java {public static void main(String[] X) throws IOException {try {ByteArrayInputStream I=__response._mp3_extract_mode_IStream("路径");ByteArrayOutputStream O=__response._mp3_extract_mode_OStream("路径");} catch (Mp3DecodeException e) {throw new RuntimeException(e);}}
}

快捷方式还有很多

你也可以直接导出成pcm格式文件

Mp3是缓存数据不是-本地数据怎么提取转换成Pcm数据?

翻译成ByteArrayInputStream

翻译成ByteArrayOutputStream

非快捷方式

import IOS_SHOGUN_Component.decodeAean.AudioBuffer;
import IOS_SHOGUN_Component.decodeAean.DecodeSuperclasses;
import IOS_SHOGUN_Component.decodeAean.Header;
import IOS_SHOGUN_Component.decodeAean.Mp3DecodeException;
import IOS_SHOGUN_Component.mp3_Decode;import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import java.io.*;
public class Java {public static void main(String[] X) throws IOException, Mp3DecodeException {mp3_Decode Create = new mp3_Decode(new mp3_Decode.Audio(), AudioBuffer.STREAM, mp3_Decode.LocalData);Create.open("路径/流的方式", false);if (Create.onCreateAndStart()) {DecodeSuperclasses DECODE = Create.getPCM_DecodeSuperclasses();Header Head = DECODE.getRecording();AudioFormat af = new AudioFormat((float) Head.getSamplingRate(), 16, Head.getChannels(), true, false);SourceDataLine DataLineSource;try {DataLineSource = AudioSystem.getSourceDataLine(af);} catch (LineUnavailableException var8) {throw new RuntimeException(var8);}try {DataLineSource.open(af, 8 * Head.getPcmSize());} catch (LineUnavailableException var7) {throw new RuntimeException(var7);}DataLineSource.start();ByteArrayInputStream D = DECODE.getAudioBuffer().getPcmDataExportIStream();byte[] DD = new byte[DECODE.getAudioBuffer().getOffset()];while (D.read(DD) != -1) {DataLineSource.write(DD, 0, DD.length);}}}
}
import IOS_SHOGUN_Component.*;
import IOS_SHOGUN_Component.decodeAean.AudioBuffer;
import IOS_SHOGUN_Component.decodeAean.Mp3DecodeException;
import java.io.*;
public class Java {public static void main(String[] X) throws IOException, Mp3DecodeException {//参数Audio,音频输出类,存储方式,是否是本地引入/缓存引入(CacheData),缓存引入时,它只能执行转化程序。mp3_Decode.Audio a=new mp3_Decode.Audio();mp3_Decode Create = new mp3_Decode(a, AudioBuffer.STREAM, mp3_Decode.LocalData);Create.open("流/路径", true);if (Create.onCreateAndStart()){//创建解码向导};}
}
import IOS_SHOGUN_Component.*;
import IOS_SHOGUN_Component.decodeAean.AudioBuffer;
import IOS_SHOGUN_Component.decodeAean.Mp3DecodeException;
import java.io.*;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;public class Java {public static void main(String[] X) throws IOException, Mp3DecodeException {SequenceCachedPool C=new SequenceCachedPool(1,2,100, TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>(10));//创建一个池做操作控制//参数Audio,音频输出类,存储方式,是否是本地引入/缓存引入(CacheData),缓存引入时,它只能执行转化程序。mp3_Decode.Audio a=new mp3_Decode.Audio();mp3_Decode Create = new mp3_Decode(a, AudioBuffer.STREAM, mp3_Decode.LocalData);Create.open("流/路径", true);C.submit(()->{try {TimeUnit.SECONDS.sleep(5);Create.close();//5秒后退出} catch (InterruptedException e) {throw new RuntimeException(e);}});if (Create.onCreateAndStart()){//创建解码向导};}
}

更推荐这样做

代码

import IOS_SHOGUN_Component.*;
import IOS_SHOGUN_Component.decodeAean.AudioBuffer;
import IOS_SHOGUN_Component.decodeAean.Mp3DecodeException;
import java.io.*;
public class Java {public static void main(String[] X) throws IOException, Mp3DecodeException {//注意这里必须是AudioBuffer.BASE64,不然不管以任何方式获取base64的PCM纯音频数据都将为空!mp3_Decode Create = new mp3_Decode(new mp3_Decode.Audio(), AudioBuffer.BASE64, mp3_Decode.LocalData);Create.open("D:\\WindowsDataStorageFolder\\CSDN2.mp3", false);//为false只做转化if (Create.onCreateAndStart()){TaskList<String> Data=Create.getPCM_dataLine().getPcmDataTaskList();//或者//TaskList<String> Data=Create.getPCM_DecodeSuperclasses().getAudioBuffer().getPcmDataTaskList();console.success("数据总长%s".formatted("PCM数据段总长->"+Data.getBase64Statistics()));};}
}

结尾

如果你喜欢的话就点个赞吧。

本文链接:https://my.lmcjl.com/post/6506.html

展开阅读全文

4 评论

留下您的评论.