1. MP3文件结构解析

1.1. 概述

1.1.1. 音频相关术语

  • ID3:

一般位于一个mp3文件的开头或末尾的若干字节内,记录该mp3文件的歌手、标题、专辑名称、年代、风格等信息,ID3分位两个版本,V1版ID3在文件末尾的固定128字节,以TAG字符开头,若没有则认为无ID3V1信息,V2版ID3位于mp3的开头,长度可变。

  • 采样率:

每秒从连续信号中提取并组成离散信号的采样个数,它用赫兹(Hz)来表示,采样率是指将模拟信号转换成数字信号时的采样频率,也就是单位时间内采样多少点,采样频率越高声音的还原就越真实越自然,在当今的主流采集卡上,采样频率一般共分为22.05KHz、44.1KHz、48KHz三个等级,22.05KHz只能达到FM广播的声音品质,44.1KHz则是理论上的CD音质界限,48KHz则更加精确一些。

  • 比特率:

比特率是指每秒传送的比特(bit)数。单位为bps(Bit Per Second),比特率越高,传送的数据越大。在音频、视频领域,比特率常翻译为码率,比特率表示经过编码(压缩)后的音、视频数据每秒钟需要用多少个比特来表示,而比特就是二进制里面最小的单位,要么是0,要么是1。比特率与音、视频压缩的关系,简单的说就是比特率越高,音频、视频的质量就越好,但编码后的文件就越大;如果比特率越少则情况刚好相反。

比特率=采样率*采样位数*声道数

  • 码率/码流/位率:

是指音频、视频文件在单位时间内使用的数据流量,通俗一点的理解就是取样率,是音频、视频编码中质量控制中最重要的部分,一般我们用的单位是Kb/s、Mb/s。一般来说码流越大,压缩比就越小,质量就越高。码流越大,说明单位时间内取样率越大,数据流,精度就越高,处理出来的文件就越接近原始文件

  • 编码:

从信息论的观点来看,描述信源的数据是信息和数据冗余之和,即:数据=信息+数据冗余。音频信号在时域和频域上具有相关性,也即存在数据冗余。将音频作为一个信源,音频编码的实质是减少音频中的冗余。

自然界中的声音非常复杂,波形极其复杂,通常我们采用的是脉冲代码调制编码,即PCM编码。PCM通过抽样、量化、编码三个步骤将连续变化的模拟信号转换为数字编码

  • 解码:

编码的逆过程

1.1.2. MP3简述

MP3全称为MPEG Audio Layer 3,它是一种高效的计算机音频编码方案,它以较大的压缩比将音频文件转换成较小的扩展名为.mp3的文件,基本保持源文件的音质,MP3是ISO/MPEG标准的一部分,

ISO/MPEG标准描述了使用高性能感知编码方案的音频压缩,此标准一直在不断更新以满足“质高量小”的追求,现已形成MPEG Layer1、Layer2、Layer3三种音频编解码方案,分别对应MP1、MP2、MP3 这三种声音文件

MPEG(Moving Picture Expert Group)是ISO下的一个动态图像专家组,它指定的MPEG标准广泛的应用于各种多媒体中,MPEG标准包括视频和音频标准,其中音频标准已制定出MPEG-1、MPEG-2、MPEG-2 ACC、MPEG-4。MPEG-1和MPEG-2标准使用同一个音频编解码族Layer1、2、3,MP3绝大多数使用的是MPEG1标准

MP3音频压缩包含编码和解码两部分,编码是将原始信号转换成电平信号的过程,解码即是逆过程,MP3 采用了感知音频编码(PerceptualAudio Coding)这一失真算法。人耳感受声音的频率范围是20Hz-20kHz,MP3截掉了大量的冗余信号和无关的信号,编码器通过混合滤波器组将原始声音变换到频率域,利用心理声学模型,估算刚好能被察觉到的噪声水平,再经过量化,转换成Huffman编码,形成MP3位流。解码器要简单得多,它的任务是从编码后的谱线成分中,经过反量化和逆变换,提取出声音信号。

MP3文件数据由多个帧组成,帧是MP3文件最小组成单位。每个帧又由帧头、附加信息和声音数据组成。每个帧播放时间是0.026秒,其长度随位率的不同而不等。有些MP3文件末尾有些额外字节存放非声音数据的说明信息。

1.2. MP3文件结构

MP3文件大体上分为三个部分:ID3V2+音频数据+ID3V1

1.3. ID3V2解析

ID3V2一共有四个版本,ID3V2.1/2.2/2.3/2.4,目前流行的播放软件一般只支持第三版即ID3V2.3,由于ID3V1记录在文件的末尾处,ID3V2就只能记录在文件的首部了,也是因为这个原因,对ID3V2的操作比ID3V1要慢,而且ID3V2的结构比ID3V1的结构复杂的多,但是ID3V2可以记录更多的信息,长度可变

ID3V2.3由一个标签头和若干个标签帧或者一个扩展标签头组成,至少要有一个标签帧,每一个标签帧记录一种信息,例如作曲、标题等

1.3.1. 标签头

位于文件开始处,长度为10字节,结构如下:

char Header[3];    /*必须为“ID3”否则认为标签不存在*/

char Ver;         /*版本号ID3V2.3 就记录3*/

char Revision;     /*副版本号此版本记录为0*/

char Flag;        /*标志字节,只使用高三位,其它位为0 */

char Size[4];      /*标签大小*/

注:标签大小,不能确定具体包括哪些内容,解析歌曲文件后,发现没有哪些字节之和会等于该值,详见下面的实例分析

标志字节一般为0,定义如下(abc000000B)

a:表示是否使用Unsynchronisation

b:表示是否有扩展头部,一般没有,所以一般也不设置

c:表示是否为测试标签,99.99%的标签都不是测试标签,不设置

标签大小共四个字节,每个字节只使用低7位,最高位不使用恒为0,计算时将最高位去掉,得到28bit的数据,计算公式如下:

Size=(Size[0]&0x7F)*0x200000+(Size[1]&0x7F)*0x400+(Size[2]&0x7F)*0x80+(Size[3]&0x7F)

以《金南玲 - 逆流成河.mp3》为例,使用WinHex工具打开如下,读者可自己对照上述结构,本章结束会给出详细的结构分析

1.3.2. 标签帧

每个标签帧都有10个字节的帧头(和标签头不是一个东西,虽然他们刚好都是10字节,标签头只有一个,每个标签帧都有一个帧头)和至少一个字节的内容构成,标签帧与标签头/其他标签帧无特殊字节分割,只能通过帧头信息来确定帧内容的大小。

帧头长度10字节,定义如下:

char ID[4]; /*标识帧,说明其内容,例如作者/标题等*/

char Size[4]; /*帧内容的大小,不包括帧头,不得小于1*/

char Flags[2]; /*标志帧,只定义了6 位*/

标识帧,常见的内容如下:

TIT2=标题

TPE1=作者

TALB=专集

TRCK=音轨格式:N/M 其中N为专集中的第N首,M为专集中共M首,N和M    为ASCII 码表示的数字

TYER=年代是用ASCII 码表示的数字

TCON=类型直接用字符串表示

COMM=备注格式:"eng\0备注内容",其中eng 表示备注所使用的自然语言

帧内容大小,计算公式如下:

Size = Size[0]*0x100000000 + Size[1]*0x10000+ Size[2]*0x100 +Size[3];

标志帧,使用每个字节的高三位,其他位均为0(abc00000B xyz00000B)

a -- 标签保护标志,设置时认为此帧作废

b -- 文件保护标志,设置时认为此帧作废

c -- 只读标志,设置时认为此帧不能修改

x -- 压缩标志,设置时一个字节存放两个BCD 码表示数字

y-- 加密标志

z-- 组标志,设置时说明此帧和其他的某帧是一组

1.4. 音频数据解析

每个帧都有一个帧头,长度是四个字节,帧后面可能有2字节的CRC校验,取决于帧头的第16位,为0则无校验,为1则有校验,后面是可变长度的附加信息,对于标准的MP3文件来说,其长度是32字节,紧接其后的是压缩的声音数据,当解码器读到此处时就进行解码了。

1.4.1. 数据帧帧头

帧头长4字节,结构如下:

typedef FrameHeader

{

unsigned int sync:11;                        //同步信息

unsigned int version:2;                      //版本

unsigned int layer: 2;                           //层

unsigned int error protection:1;           // CRC校验

unsigned int bitrate_index:4;              //位率

unsigned int sampling_frequency:2;         //采样频率

unsigned int padding:1;                    //帧长调节

unsigned int private:1;                       //保留字

unsigned int mode:2;                         //声道模式

unsigned int mode extension:2;        //扩充模式

unsigned int copyright:1;                           // 版权

unsigned int original:1;                      //原版标志

unsigned int emphasis:2;                  //强调模式

}HEADER, *LPHEADER;

详细说明:

1.4.2. 帧长度与真大小

帧大小即每帧的采样数,表示一帧数据中采样的个数,该值是恒定的,如下表所示:

帧长度是压缩时每一帧的长度,包括帧头的4个字节。它将填充的空位也计算在内。Layer 1的一个空位长4字节,Layer 2和Layer 3的空位是1字节。当读取MPEG文件时必须计算该值以便找到相邻的帧。注意:因为有填充和比特率变换,帧长度可能变化

计算公式如下:

Layer 1:Len(字节) = ((每帧采样数/8*比特率)/采样频率)+填充*4

Layer2/3:Len(字节) = ((每帧采样数/8*比特率)/采样频率)+填充

例:MPEG1 Layer3 比特率128000,采样率44100,填充0,帧长度为:((1152/8*128K)/44.1K+0=417字节

1.4.3. 帧持续时间

计算公式:

每帧持续时间(毫秒) = 每帧采样数 / 采样频率 * 1000

例:1152/441000*1000=26ms

1.4.4. 帧数据

在帧头后边是Side Info(姑且称之为通道信息)。对标准的立体声MP3文件来说其长度为32字节。当解码器在读到上述信息后,就可以进行解码了。

对于mp3来说现在有两种编码方式,一种是CBR,也就是固定位率,固定位率的帧的大小在整个文件中都是是固定的(公式如上所述),只要知道文件总长度,和从第一帧帧头读出的信息,就都可以通过计算得出这个mp3文件的信息,比如总的帧数,总的播放时间等等,要定位到某一帧或某个时间点也很方便,这种编码方式不需要文件头,第一帧开始就是音频数据。另一种是VBR,就是可变位率,VBR是XING公司推出的算法,所以在MP3的FRAME里会有“Xing"这个关键字(也有用"Info"来标识的,现在很多流行的小软件也可以进行VBR压缩,它们是否遵守这个约定,那就不得而知了),它存放在MP3文件中的第一个有效帧的数据区里,它标识了这个MP3文件是VBR的。同时第一个帧里存放了MP3文件的帧的总个数,这就很容易获得了播放总时间,同时还有100个字节存放了播放总时间的100个时间分段的帧索引,假设4分钟的MP3歌曲,240S,分成100段,每两个相邻INDEX的时间差就是2.4S,所以通过这个INDEX,只要前后处理少数的FRAME,就能快速找出我们需要快进的帧头。其实这第一帧就相当于文件头了。不过现在有些编码器在编码CBR文件时也像VBR那样将信息记入第一帧,比如著名的lame,它使用"Info"来做CBR的标记。

1.4.5. VBR头文件

VBR文件头位于MP3文件中第一个有效帧的数据区,详细结构如下:

1.5. ID3V1解析

ID3 V1.0标准并不周全,存放的信息少,无法存放歌词,无法录入专辑封面、图片等。V2.0是一个相当完备的标准,但给编写软件带来困难,虽然赞成此格式的人很多,在软件中真正实现的却极少。绝大多数MP3仍使用ID3 V1.0标准。此标准是将MP3文件尾的最后128个字节用来存放ID3信息

1.6. 附录

1.6.1. 帧标识

AENC:Audioencryption

APIC:Attached picture

COMM:Comments

COMR:Commercial

ENCR:Encryptionmethod registration

EQUA:Equalization

ETCO:Event timingcodes

GEOB:Generalencapsulated object

GRID:Groupidentification registration

IPLS:Involvedpeople list

LINK:Linkedinformation

MCDI:Music CDidentifier

MLLT:MPEGlocationlookup table

OWNE:Ownership

PRIV:Private

PCNT:Playcounter

POPM:Popularimeter

POSS:Positionsynchronisation

RBUF:Recommendedbuffer size

RVAD:Relativevolume adjustment

RVRB:Reverb

SYLT:Synchronizedlyric/text

SYTC:Synchronizedtempo codes

TALB:Album/Movie/Showtitle

TBPM:BPM(beats perminute)

TCOM:Composer

TCON:Content type

TCOP:Copyrightmessage

TDAT:Date

TDLY:Playlistdelay

TENC:Encoded by

TEXT:Lyricist/Textwriter

TFLT:Filetype

TIME:Time

TIT1:Content groupdeion

TIT2:Title/songname/contentdeion

TIT3:Subtitle/Deionrefinement

TKEY:Initial key

TLAN:Language(s)

TLEN:Length

TMED:Media type

TOAL:Originalalbum/movie/show title

TOFN:Originalfilename

TOLY:Originallyricist(s)/text writer(s)

TOPE:Originalartist(s)/performer(s)

TORY:Originalrelease year

TOWN:Fileowner/licensee

TPE1:Leadperformer(s)/Soloist(s)

TPE2:Band/orchestra/accompaniment

TPE3:Conductor/performerrefinement

TPE4:Interpreted,remixed, or otherwise modified by

TPOS:Partof a set

TPUB:Publisher

TRCK:Tracknumber/Position in set

TRDA:Recordingdates

TRSN:Internetradio station name

TRSO:Internetradio station owner

TSIZ:Size

TSRC:ISRC(internationalstandard recording code)

TSSE:Software/Hardwareand settings used for encoding

TYER:Year

TXXX:Userdefinedtext information

UFID:Unique fileidentifier

USER:Terms of use

USLT:Unsychronizedlyric/text tranion

WCOM:Commercialinformation

WCOP:Copyright/Legalinformation

WOAF:Officialaudio file webpage

WOAR:Officialartist/performer webpage

WOAS:Officialaudio source webpage

WORS:Officialinternet radio station homepage

WPAY:Payment

WPUB:Publishersofficial webpage

WXXX:UserdefinedURL link

1.6.2. 音乐类型

0="Blues";

1="ClassicRock";

2="Country";

3="Dance";

4="Disco";

5="Funk";

6="Grunge";

7="Hip-Hop";

8="Jazz";
9="Metal";
10="NewAge";
11="Oldies";
12="Other";
13="Pop";
14="R&B";
15="Rap";
16="Reggae";
17="Rock";
18="Techno";
19="Industrial";
20="Alternative";
21="Ska";
22="Deathl";
23="Pranks";
24="Soundtrack";
25="Euro-Techno";
26="Ambient";
27="Trip-Hop";
28="Vocal";
29="Jazz+Funk";
30="Fusion";
31="Trance";
32="Classical";
33="Instrumental";
34="Acid";
35="House";
36="Game";
37="SoundClip";
38="Gospel";
39="Noise";
40="AlternRock";
41="Bass";
42="Soul";
43="Punk";
44="Space";
45="Meditative";
46="InstrumentalPop";
47="InstrumentalRock";
48="Ethnic";
49="Gothic";
50="Darkwave";
51="Techno-Industrial";
52="Electronic";
53="Pop-Folk";
54="Eurodance";
55="Dream";
56="SouthernRock";
57="Comedy";
58="Cult";
59="Gangsta";
60="Top40";
61="ChristianRap";
62="Pop/Funk";
63="Jungle";
64="NativeAmerican";
65="Cabaret";
66="NewWave";
67="Psychadelic";
68="Rave";
69="Showtunes";
70="Trailer";
71="Lo-Fi";
72="Tribal";
73="AcidPunk";
74="AcidJazz";
75="Polka";
76="Retro";
77="Musical";
78="Rock&Roll";
79="HardRock";

80="Folk";
81="Folk-Rock";
82="NationalFolk";
83="Swing";
84="FastFusion";
85="Bebob";
86="Latin";
87="Revival";
88="Celtic";
89="Bluegrass";
90="Avantgarde";
91="GothicRock";
92="ProgessiveRock";
93="PsychedelicRock";
94="SymphonicRock";
95="SlowRock";
96="BigBand";
97="Chorus";
98="EasyListening";
99="Acoustic";
100="Humour";
101="Speech";
102="Chanson";
103="Opera";
104="ChamberMusic";
105="Sonata";
106="Symphony";
107="BootyBass";
108="Primus";
109="PornGroove";
110="Satire";
111="SlowJam";
112="Club";
113="Tango";
114="Samba";
115="Folklore";
116="Ballad";
117="PowerBallad";
118="RhythmicSoul";
119="Freestyle";
120="Duet";
121="PunkRock";
122="DrumSolo";
123="Acapella";
124="Euro-House";
125="DanceHall";

126="Goa";
127="Drum&Bass";
128="Club-House";
129="Hardcore";
130="Terror";
131="Indie";
132="BritPop";
133="Negerpunk";
134="PolskPunk";
135="Beat";
136="ChristianGangstaRap";
137="Heavyl";
138="Blackl";
139="Crossover";
140="ContemporaryChristian";
141="ChristianRock";
142="Merengue";
143="Salsa";
144="Trashl";
145="Anime";
146="JPop";
147="Synthpop";

1.7. 实例分析

1.7.1. 歌曲信息

1.7.2. 结构解析

1.7.2.1. 标签头

标签头:10字节,00H-09H

标签大小:

Size=(Size[0]&0x7F)*0x200000+(Size[1]&0x7F)*0x400+(Size[2]&0x7F)*0x80+(Size[3]&0x7F)

=(0x07&0x7F)*0x400+(0x34&0x7F)*0x80+(0x60&0x7F)

=0x1C00+0x1A00+0x60

=0x3660=13920

1.7.2.2. TSSE标签帧

1.7.2.3. COMM标签帧

帧内容大小:

Size = Size[0]*0x100000000 + Size[1]*0x10000+ Size[2]*0x100 +Size[3]

=0x02*0x100+0x07

=0x207=519

1.7.2.4. TALB标签帧

1.7.2.5. TIT2标签帧

1.7.2.6. TPE1标签帧

1.7.2.7. TPOS标签帧

1.7.2.8. TRCK标签帧

1.7.2.9. APIC标签帧

此处省略N多字节………

帧内容大小:

Size = Size[0]*0x100000000 + Size[1]*0x10000+ Size[2]*0x100 +Size[3]

=0x01*0x10000+0xD3*0x100+0xD7

=0x10000+0xD300+0xD7

=0x1D3D7=119767

1.7.2.10. 未知数据

不清楚该段数据具体作用,目测是填充字节。

1.7.2.11. 音频数据

篇幅有限,只分析第一帧数据,其他帧与此无异。

帧头解析:

FF=11111111 红色

FB=1111 1011 红色黑色绿色紫色

E0=1110 0000 蓝色橄榄色深红色橙色

00=00000000 白色浅绿色深蓝色褐色粉红色

红色:11位,同步信息,所有位均为1,第一个字节恒为FF

黑色:2位,版本,MPEG1

绿色:2位,层,Layer3

紫色:1位,无CRC校验

蓝色:4位,位率,单位是kbps,320

橄榄色:2位,采样频率,44.1K

深红色:1位,用来调整文件头长度,无需调整

橙色:1位,保留字,未使用

白色:2位,表示声道模式,立体声Stereo

浅绿色:2位,声道模式为Joint Stereo时才使用

深蓝色:1位,文件是否合法,不合法

褐色:1位,是否原版,非原版

粉红色:2位,用于声音经降噪压缩后再补偿的分类,未定义

根据以上信息可计算:

帧长度=帧头+通道信息+帧内容= ((1152/8*320)/44.1=1044字节

每帧持续时间=1152/44.1*1000=26.12ms

因为该歌曲为CBR即固定位率歌曲,所以每帧的数据长度都是1044字节,26ms。

1.7.2.12. 其他数据

该歌曲无ID3V1信息。

最后的320字节,题主也是笨笨的没弄懂其具体含义~

1.8. 说明

word文档下载地址:http://download.csdn.net/detail/u010650845/9705899

MP3文件结构解析(超详细)相关推荐

  1. 2022年全国职业院校技能大赛中职组网络安全竞赛——隐写术应用解析(超详细)

    2022年全国职业院校技能大赛中职组网络安全竞赛--隐写术应用解析(超详细) B-8任务八:隐写术应用 *任务说明:仅能获取Server8的IP地址 环境需求私信博主 1.找出文件夹1中的文件,将文件 ...

  2. 区间DP解析超详细版!!街边老奶奶也喜欢看的好博客

    区间DP解析超详细版!! 文章目录 区间DP解析超详细版!! 1. 概念入门 2. 线性石子归并 3. 环形石子归并 4. 奇怪的题题目目 5. 区间DP的优化 附录 在上章 背包 (<-点击传 ...

  3. mqtt报文解析—超详细

    文章目录 一.报文结构 二.固定报头 三.剩余长度 四.mqtt控制报文 Ⅰ.CONNECT 1.固定报头 2. 可变报头 2.1.协议名 2.2.协议级别 2.3.连接标志 2.4 保持连接 2.5 ...

  4. Java集合系列---HashMap源码解析(超详细)

    1 HashMap 1)特性: 底层数据结构是数组+链表+红黑树运行null键和null值,,非线程安全,不保证有序,插入和读取顺序不保证一致,不保证有序,在扩容时,元素的顺序会被重新打乱 实现原理: ...

  5. windows平台编译CEF支持H264(MP3、MP4)超详细

  6. Android技能树 — 网络小结(6)之 OkHttp超超超超超超超详细解析

    前言: 本文也做了一次标题党,哈哈,其实写的还是很水,各位原谅我O(∩_∩)O. 介于自己的网络方面知识烂的一塌糊涂,所以准备写相关网络的文章,但是考虑全部写在一篇太长了,所以分开写,希望大家能仔细看 ...

  7. 单片机数字钟(调时,调时闪烁,万年历,年月日)超详细解析

    2019/07/13 单片机数字钟(调时,调时闪烁,万年历,年月日)超详细解析 发表日期:2019/07/13 单片机开发板:巫妖王2.0, 使用同款开发板可直接上板测试 文档说明: 实现功能 : 一 ...

  8. 【算法】超详细的遗传算法(Genetic Algorithm)解析

    转自:https://www.jianshu.com/p/ae5157c26af9 [算法]超详细的遗传算法(Genetic Algorithm)解析 00 目录 遗传算法定义 生物学术语 问题导入 ...

  9. 【lnmp+ELK+Nginx+GeoIP】超详细新版ELK8.5.0解析收集Nginx日志并实现数据可视化与IP地址地图可视化教程-2022年11月版

    超详细新版ELK8.5.0+lnmp1.9解析收集Nginx日志并实现数据可视化与IP地址地图可视化教程-2022年11月版 前言 1.基础环境和所需要的软件包 1.1服务器配置(仅供参考) 1.2 ...

最新文章

  1. 编写linux下跑马灯应用程序,01 arm11 led 跑马灯程序
  2. 加速AI应用落地,英特尔AI 2.0的进阶之道
  3. CSS 会被继承的属性
  4. map和vector的迭代器失效问题(某公司招聘笔试试题)
  5. classmethod和staticmethod
  6. “数据库审计”关键词,重回Google第一位置
  7. 关于 MySQL5.7.log 版本导出 SQL 语句再导入 8.0.13 版本出现 Incorrect datetime value: ‘0000-00-00 00:00:00‘ 错误的解决办法
  8. Linux Makefile 中的陷阱【转】
  9. Dapp开发教程四 Asch Dapp Dice Game
  10. CVPR2020 | 遮挡也能识别?地平线提出用时序信息提升行人检测准确度
  11. Mysql初级第二天(wangyun)
  12. c语言中转义字符 0,【填空题】在C语言中,用“\\”开头的字符序列称为转义字符, 转义字符‘\\n’的功能是_____; 转义字符‘\\0’的功能是_____;...
  13. python学习笔记(九)之语句1
  14. 算法知识点——(4)降维
  15. rpm、dpkg、yum、apt比较
  16. 创客使用Fusion 360 - 制作模型
  17. 全球诺贝尔奖得主最多的30所大学
  18. 2021年高考成绩查询湖南电信,湖南省通信管理局关于开展2021年全省电信网码号资源年报和检查工作的通知...
  19. ps2021神经网络滤镜不能用,ps2021没法用神经元滤镜
  20. Python3下的NLTK及nltk_data安装问题(Ubuntu环境)

热门文章

  1. 可穿戴式脑电图传感器在室内热舒适度测量中的应用
  2. 利用FFmpeg将立体声转为单声道wav
  3. 态路小课堂丨特种光纤之光谱光纤跳线
  4. 51单片机之温湿度检测系统(DTH11、OLED、LCD1602)
  5. FANUC机器人发生SRVO-454 CPU总线失败报警时的解决办法
  6. 【原神】matlab gui 记录角色等阶天赋
  7. 通过https方式连接远程仓库,因修改用户名或密码导致推送本地代码到远程仓库失败的问题解决办法!
  8. 10个简洁的Python编码技巧
  9. Winform3、事件触发机制学习:事件的注册和定义和参数含义
  10. 百度地图三维盒子模型标注