皮皮网

皮皮网

【vlx怎么查看源码】【gotv源码港剧合集】【手部追踪gpu源码】sbr源码

时间:2024-12-29 07:14:40 分类:焦点

1.小弟初学汇编 怎样搭建开发环境?MASM怎么用?PWB是什么?
2.如何在C语言中嵌入汇编?
3.AAC音视频编码详解
4.BSC这个英文缩写是什么意思?
5.声音数字化的过程分为哪三个步骤

sbr源码

小弟初学汇编 怎样搭建开发环境?MASM怎么用?PWB是什么?

       汇编(六)——汇编语言程序格式及MASM

       汇编语言的实现也是先利用某种编辑器编写汇编语言源程序(*.ASM),然后经过汇编得到目标模块文件(*.OBJ)、连接后形成可执行文件(*.EXE)。

       1、汇编语言程序的语句格式

       汇编语源程序由语句序列构成。语句一般由分隔符分成的vlx怎么查看源码四个部分组成,它们有两种格式:

       (1)执行性语句——由硬指令构成的语句,它通常对应一条机器指令,出现在程序的代码段中:

       标号:硬指令助记符 操作数,操作数 ;注释

       (2)说明性语句——由伪指令构成的语句,它通常指示汇编程序如何汇编源程序:

       名字 伪指令助记符 参数,参数,... ;注释

       ◆执行性语句中,冒号前的标号反映该指令的逻辑地址;说明性语句中的名字可以是变量名、段名、子程序名或宏名等等,既反映逻辑地址又具有自身的各种属性。标号和名字很容易通过是否具有冒号来区分。

       ◆硬指令助记符可以是任何一条处理器指令,也可以是一条宏指令,伪指令助记符主要完成一些不产生CPU动作的说明性工作,在程序执行前由汇编程序完成处理。

       ◆处理器指令的操作数可以是立即数、寄存器和存储单元。伪指令的参数可以是常数、变量名、表达式等,可以有多个,参数之间用逗号隔开。

       ◆语句中由分号开始的部分是注释。

       2、汇编语言源程序

       这个以前已经学过,主要有简化段定义格式和完整段定义格式

       3、宏汇编程序MASM

       MASM6.,安装文件5张软盘,默认安装在C:\MASM目录下,完整的MASM汇编系统包含很多文件,但最基本的有如下几个:

       ML.EXE 汇编程序

       ML.ERR 汇编错误信息文件

       DOSXNT.EXE MS-DOS扩展文件

       LINK.EXE 连接文件

       LIB.EXE 子程序库管理文件

       如果采用集成开发环境PWB,主要涉及如下文件:

       PWWB.EXE 程序员工作平台

       NMAKER.EXE 工程维护程序

       NMAKE.EXE nmaker的MS-DOS扩展驱动程序

       CV.EXE 源代码调试器CodeView

       CVPACK.EXE 调试信息压缩器,它为CODEVIEW准备一个可执行文件

       HELPMAKE.EXE 帮助文件维护程序

       BSCMAKE.EXE 浏览数据库创建程序

       SBRPACK.EXE 浏览信息程序

       PWBRMAKE.EXE BSCMAKE兼容驱动程序

       *.MXT 各种PWB扩展工具文件

       *.XXT 各种语言的PWB扩展文件

       4、汇编语言的命令行开发过程

       (1)原程序的编写

       用编辑软件书写*.asm源程序,如

       LI6-1.ASM

       ;LI6-1.ASM

       .MODEL SMALL

       .STACK

       .DATA

       STRING DB 'Hello,Everybody!'

       .CODE

       .STARTUP

       MOV DX,OFFSET STRING

       MOV AH,9

       INT H

       .EXIT 0

       END

       (2)原程序的汇编

       汇编是将原程序翻译成由机器代码组成的目标模块文件的过程,如下:

       ML /c LI6-1.ASM

       如果源程序没有语法错误,则生成一个目标模块文件LI6-1.OBJ

       (3)目标文件的连接

       连接程序能把一个或多个目标文件和库文件和成一个可执行文件(.EXE、.COM文件),如下:

       LINK LI6-1.OBJ

       连接程序的一般格式:

       LINK [/参数选项] OBJ文件列表 [EXE文件名,MAP文件名,库文件][;]

       连接程序可以将多个模块文件连接起来,形成一个可执行文件;多个模块文件用“+”分隔。给出EE文件名就可以替代与第一个模块文件名相同的缺省名。给出MAP文件名将创建连接映像文件,否则不生成映像文件。库文件是指连接程序需要的子程序库等。“;”表示采用缺省值

       事实上,ML汇编程序可以自动调用LINK连接程序(ML表示MASM和LINK),实现汇编和连接依次进行,如下即可完成可执行文件的生成:

       ML LI6-1.ASM

       ML的命令行格式如下:

       ML [/参数选项] 文件列表 [/LINK连接参数选项]

       参数选项如下(注意参数是大小写敏感的):

       /AT——允许tiny存储模式(创建一个COM文件)

       /c——只汇编源程序,不进行自动连接

       /fl 文件名——川建一个汇编列表文件(扩展名LST)

       /Fr 文件名——创建一个可在PWB下浏览的.SBR源浏览文件

       /Fo 文件名——根据指定的文件名生成模块文件,而不是采用缺省名

       /Fe 文件名——根据指定的文件名生成可执行文件,而不是采用缺省名

       /Fm 文件名——创建一个连接映像文件(扩展名MAP)

       /I 路径名——设置需要包含进(INCLUDE)源程序的文件的所在路径

       /Sg——在生成的文件列表文件中,列出由汇编程序产生的指令

       /Sn——在创建列表文件时不产生符号表

       /Zi——生成模块文件时,加入调试程序CODEVIEW需要的信息

       /Zs——只进行语法检查,不产生任何代码

       /LINK——传递给连接程序LINK的参数

       列表文件是一种文本文件,含有源程序和目标代码,创建列表文件,输入如下命令:

       ML /Fl /Sg LI6-1.ASM

       该命令除产生模块文件LI6-1.OBJ和可执行文件LI6-1.EXE,还产生列表文件LI6-1.LST,采用/Sg,如果源程序具有.STARTUP、.EXIT伪指令以及流程控制伪指令.IF、.WHILE等,将在列表文件中得到相应的硬指令;否则列表文件只给出上述伪指令。LI6-1.LST如下:

       li6-1.lst

       Microsoft (R) Macro Assembler Version 6. // ::

       li6-1.asm Page 1 - 1

       ;LI6-1.ASM

       .MODEL SMALL

       .STACK

        .DATA

        6C 6C 6F 2C STRING DB 'Hello,Everybody!'

       

       6F

        .CODE

       .STARTUP

        *@Startup:

        BA ---- R * mov dx, DGROUP

        8E DA * mov ds, dx

        8C D3 * mov bx, ss

        2B DA * sub bx, dx

        D1 E3 * shl bx, h

       B D1 E3 * shl bx, h

       D D1 E3 * shl bx, h

       F D1 E3 * shl bx, h

        FA * cli

        8E D2 * mov ss, dx

        E3 * add sp, bx

        FB * sti

        BA R MOV DX,OFFSET STRING

       A B4 MOV AH,9

       C CD INT H

       .EXIT 0

       E B8 4C * mov ax, Ch

        CD * int h

       END

       Microsoft (R) Macro Assembler Version 6. // ::

       li6-1.asm Symbols 2 - 1

       Segments and Groups:

       N a m e Size Length Align Combine Class

       DGROUP . . . . . . . . . . . . . GROUP

       _DATA . . . . . . . . . . . . . Bit Word Public 'DATA'

       STACK . . . . . . . . . . . . . Bit Para Stack 'STACK'

       _TEXT . . . . . . . . . . . . . Bit Word Public 'CODE'

       Symbols:

       N a m e Type Value Attr

       @CodeSize . . . . . . . . . . . Number h

       @DataSize . . . . . . . . . . . Number h

       @Interface . . . . . . . . . . . Number h

       @Model . . . . . . . . . . . . . Number h

       @Startup . . . . . . . . . . . . L Near _TEXT

       @code . . . . . . . . . . . . . Text _TEXT

       @data . . . . . . . . . . . . . Text DGROUP

       @fardata? . . . . . . . . . . . Text FAR_BSS

       @fardata . . . . . . . . . . . . Text FAR_DATA

       @stack . . . . . . . . . . . . . Text DGROUP

       STRING . . . . . . . . . . . . . Byte _DATA

       0 Warnings

       0 Errors

       ◆列表文件有两部分内容。在第一部分源程序中,最左列是数据或指令在该段从0开始的相对偏移地址,向右依次是指令的机器代码字节个数、机器代码和汇编语言语句。机器代码后有字母"R"表示该指令的立即数/位移量现在不能确定或是只是相对地址,它将在程序连接或进入主存时才能定位。带有“*”的处理器指令是由前面一条伪指令产生的,采用/Sg选项时的列表文件才罗列。如果陈序中有错误(ERROR)或警告(WARMING),也会会在相应位置提示。gotv源码港剧合集

       列表文件的第二部分是标示符使用情况。对段名和组名给出他们的名字(NAME)、尺寸(Size)、长度(Length)、定位(Align)、组合(Combine)和类别(Class)属性;对符号给出他们的名字、类型(Type)、数值(Value)和属性(Attr)。采用简化段定义格式,有许多汇编系统的预定义标示符,例如@DATA等。

       ◆映像文件也是一种文本文件,含有每段在存储器中的分配情况。如下命令创建:

       ML /Fm LI6-1.ASM

       将产生LI6-1.MAP映像文件,如下:

       LI6-1.MAP

       Start Stop Length Name Class

       H H H _TEXT CODE

       H H H _DATA DATA

       H FH H STACK STACK

       Origin Group

       :0 DGROUP

       Address Publics by Name

       Address Publics by Value

       Program entry point at :

       映像文件中首先给出了该程序各个逻辑段的起点(Start)、终点(sTOP)、长度(Length)、段名(Name)和类别(Class);然后是段组(GROUP)位置和组名;最后提示程序开始执行的逻辑地址。注意,这里的起点、终点和段地址是以该程序文件开头而言的相对地址,实际的绝对地址需要在程序进入主存后确定。

       5、可执行程序的调试

       只要在操作系统下输入文件名即可:

       LI6-1

       操作系统装在该文件进入主存,开始运行,是用DEBUG调试时:

       DEBUG LI6-1.EXE

       其中,BX.CX反映程序的大小,CS:IP指向程序开始执行的第一条指令,SS:SP指向堆栈段,DS和ES并不指向程序数据段,而是指向程序前H处(这部分是该程序的短前缀PSP);所以,DS和ES应该在程序当中进行设置,正如该程序.STARTUP伪指令所完成的。采用简化段定义格式的程序,在主存中从低到高依次安排代码段、数据段和堆栈段。

       找的好辛苦呀

       大哥看的好的话就加给小弟呀

       呵呵

       祝你成功呀

如何在C语言中嵌入汇编?

       在 Visual C++ 中使用内联汇编- -

       使用内联汇编可以在 C/C++ 代码中嵌入汇编语言指令,而且不需要额外的汇编和连接步骤。在 Visual C++ 中,内联汇编是内置的编译器,因此不需要配置诸如 MASM 一类的独立汇编工具。这里,我们就以 Visual Studio .NET 为背景,介绍在 Visual C++ 中使用内联汇的相关知识(如果是早期的版本,可能会有些许出入)。

        内联汇编代码可以使用 C/C++ 变量和函数,因此它能非常容易地整合到 C/C++ 代码中。它能做一些对于单独使用 C/C++ 来说非常笨重或不可能完成的任务。

       一、 优点

        使用内联汇编可以在 C/C++ 代码中嵌入汇编语言指令,而且不需要额外的汇编和连接步骤。在 Visual C++ 中,内联汇编是内置的编译器,因此不需要配置诸如 MASM 一类的独立汇编工具。这里,我们就以 Visual Studio .NET 为背景,介绍在 Visual C++ 中使用内联汇的相关知识(如果是早期的版本,可能会有些许出入)。

        内联汇编代码可以使用 C/C++ 变量和函数,因此它能非常容易地整合到 C/C++ 代码中。它能做一些对于单独使用 C/C++ 来说非常笨重或不可能完成的任务。

        内联汇编的用途包括:

       使用汇编语言编写特定的函数;

       编写对速度要求非常较高的代码;

       在设备驱动程序中直接访问硬件;

       编写 naked 函数的初始化和结束代码。

       二、 关键字

        使用内联汇编要用到 __asm 关键字,它可以出现在任何允许 C/C++ 语句出现的地方。我们来看一些例子:

       简单的 __asm 块:

        __asm

        {

        MOV AL, 2

        MOV DX, 0xD

        OUT AL, DX

        }

       在每条汇编指令之前加 __asm 关键字:

        __asm MOV AL, 2

        __asm MOV DX, 0xD

        __asm OUT AL, DX

       因为 __asm 关键字是语句分隔符,所以可以把多条汇编指令放在同一行:

        __asm MOV AL, 2 __asm MOV DX, 0xD __asm OUT AL, DX

        显然,第一种方法与 C/C++ 的风格很一致,并且把汇编代码和 C/C++ 代码清楚地分开,还避免了重复输入 __asm 关键字,因此推荐使用第一种方法。

        不像在 C/C++ 中的"{ }",__asm 块的"{ }"不会影响 C/C++ 变量的作用范围。同时,__asm 块可以嵌套,而且嵌套也不会影响变量的作用范围。

        为了与低版本的 Visual C++ 兼容,_asm 和 __asm 具有相同的意义。另外,Visual C++ 支持标准 C++ 的 asm 关键字,但是它不会生成任何指令,它的手部追踪gpu源码作用仅限于使编译器不会出现编译错误。要使用内联汇编,必须使用 __asm 而不是 asm 关键字。

       三、 汇编语言

       1. 指令集

        内联汇编支持 Intel Pentium 4 和 AMD Athlon 的所有指令。更多其它处理器的指令可以通过 _EMIT 伪指令来创建(_EMIT 伪指令说明见下文)。

       2. MASM 表达式

        在内联汇编代码中,可以使用所有的 MASM 表达式(MASM 表达式是指用来计算一个数值或一个地址的操作符和操作数的组合)。

       3. 数据指示符和操作符

        虽然 __asm 块中允许使用 C/C++ 的数据类型和对象,但它不能使用 MASM 指示符和操作符来定义数据对象。这里特别指出,__asm 块中不允许 MASM 中的定义指示符(DB、DW、DD、DQ、DT 和 DF),也不允许使用 DUP 和 THIS 操作符。MASM 中的结构和记录也不再有效,内联汇编不接受 STRUC、RECORD、WIDTH 或者 MASK。

       4. EVEN 和 ALIGN 指示符

        尽管内联汇编不支持大多数 MASM 指示符,但它支持 EVEN 和 ALIGN。当需要的时候,这些指示符在汇编代码里面加入 NOP 指令(空操作)使标号对齐到特定边界。这样可以使某些处理器取指令时具有更高的效率。

       5. MASM 宏指示符

        内联汇编不是宏汇编,不能使用 MASM 宏指示符(MACRO、REPT、IRC、IRP 和 ENDM)和宏操作符(<>、!、&、% 和 .TYPE)。

       6. 段

        必须使用寄存器而不是名称来指明段(段名称"_TEXT"是无效的)。并且,段跨越必须显式地说明,如 ES:[EBX]。

       7. 类型和变量大小

        在内联汇编中,可以用 LENGTH、SIZE 和 TYPE 来获取 C/C++ 变量和类型的大大小。

        * LENGTH 操作符用来取得 C/C++ 中数组的元素个数(如果不是一个数组,则结果为 1)。

        * SIZE 操作符可以获取 C/C++ 变量的大小(一个变量的大小是 LENGTH 和 TYPE 的乘积)。

        * TYPE 操作符可以返回 C/C++ 类型和变量的大小(如果变量是一个数组,它得到的是数组中单个元素的大小)。

        例如,程序中定义了一个 8 维的整数型变量:

        int iArray[8];

        下面是 C 和汇编表达式中得到的 iArray 及其元素的相关值:

        __asm C Size

        LENGTH iArray sizeof(iArray)/sizeof(iArray[0]) 8

        SIZE iArray sizeof(iArray)

        TYPE iArray sizeof(iArray[0]) 4

       8. 注释

        内联汇编中可以使用汇编语言的注释,即";"。例如:

        __asm MOV EAX, OFFSET pbBuff ; Load address of pbBuff

        因为 C/C++ 宏将会展开到一个逻辑行中,为了避免在宏中使用汇编语言注释带来的混乱,内联汇编也允许使用 C/C++ 风格的注释。

       9. _EMIT 伪指令

        _EMIT 伪指令相当于 MASM 中的 DB,但是 _EMIT 一次只能在当前代码段(.text 段)中定义一个字节。例如:

        __asm

        {

        JMP _CodeLabel

        _EMIT 0x ; 定义混合在代码段的数据

        _EMIT 0x

        _CodeLabel: ; 这里是代码

        _EMIT 0x ; NOP指令

        }

       . 寄存器使用

        一般来说,不能假定某个寄存器在 __asm 块开始的时候有已知的值。寄存器的值将不能保证会从 __asm 块保留到另外一个 __asm 块中。

        如果一个函数声明为 __fastcall 调用方式,则其参数将通过寄存器而不是堆栈来传递。这将会使 __asm 块产生问题,因为函数无法被告知哪个参数在哪个寄存器中。如果函数接收了 EAX 中的参数并立即储存一个值到 EAX 中的话,原来的参数将丢失掉。另外,在所有声明为 __fastcall 的函数中,ECX 寄存器是必须一直保留的。为了避免以上的冲突,包含 __asm 块的函数不要声明为 __fastcall 调用方式。

       提示:如果使用 EAX、EBX、ECX、EDX、ESI 和 EDI 寄存器,你不需要保存它。但如果你用到了 DS、SS、SP、BP 和标志寄存器,那就应该用 PUSH 保存这些寄存器。

       提示:如果程序中改变了用于 STD 和 CLD 的方向标志,必须将其恢复到原来的值。

       四、吾爱源码手机版 使用 C/C++ 元素

       1. 可用的 C/C++ 元素

        C/C++ 与汇编语言可以混合使用,在内联汇编中可以使用 C/C++ 变量以及很多其它的 C/C++ 元素,包括:

       符号,包括标号、变量和函数名;

       常量,包括符号常量和枚举型成员;

       宏定义和预处理指示符;

       注释,包括"/**/"和"//";

       类型名,包括所有 MASM 中合法的类型;

       typedef 名称,通常使用 PTR 和 TYPE 操作符,或者使用指定的的结构或枚举成员。

        在内联汇编中,可以使用 C/C++ 或汇编语言的基数计数法。例如,0x 和 H 是相等的。

       2. 操作符使用

        内联汇编中不能使用诸如"<<"一类的 C/C++ 操作符。但是,C/C++ 和 MASM 共有的操作符(比如"*"和"[]"操作符),都被认为是汇编语言的操作符,是可以使用的。举个例子:

        int iArray[];

        __asm MOV iArray[6], BX ; Store BX at iArray + 6 (Not scaled)

        iArray[6] = 0; // Store 0 at iArray+ (Scaled)

       提示:在内联汇编中,可以使用 TYPE 操作符使其与 C/C++ 一致。比如,下面两条语句是一样的:

        __asm MOV iArray[6 * TYPE int], 0 ; Store 0 at iArray +

        iArray[6] = 0; // Store 0 at iArray +

       3. C/C++ 符号使用

        在 __asm 块中可以引用所有在作用范围内的 C/C++ 符号,包括变量名称、函数名称和标号。但是不能访问 C++ 类的成员函数。

        下面是在内联汇编中使用 C/C++ 符号的一些限制:

       每条汇编语句只能包含一个 C/C++ 符号。在一条汇编指令中,多个符号只能出现在 LENGTH、TYPE 或 SIZE 表达式中。

       在 __asm 块中引用函数必须先声明。否则,编译器将不能区别 __asm 块中的函数名和标号。

       在 __asm 块中不能使用对于 MASM 来说是保留字的 C/C++ 符号(不区分大小写)。MASM 保留字包含指令名称(如 PUSH)和寄存器名称(如 ESI)等。

       在 __asm 块中不能识别结构和联合标签。

       4. 访问 C/C++ 中的数据

        内联汇编的一个非常大的方便之处是它可以使用名称来引用 C/C++ 变量。例如,如果 C/C++ 变量 iVar 在作用范围内:

        __asm MOV EAX, iVar ; Stores the value of iVar in EAX

        如果 C/C++ 中的类、结构或者枚举成员具有唯一的名称,则在 __asm 块中可以只通过成员名称来访问(省略"."操作符之前的变量名或 typedef 名称)。然而,如果成员不是唯一的,你必须在"."操作符之前加上变量名或 typedef 名称。例如,下面的两个结构都具有 SameName 这个成员变量:

        struct FIRST_TYPE

        {

        char *pszWeasel;

        int SameName;

        };

        struct SECOND_TYPE

        {

        int iWonton;

        long SameName;

        };

        如果按下面方式声明变量:

        struct FIRST_TYPE ftTest;

        struct SECOND_TYPE stTemp;

        那么,所有引用 SameName 成员的地方都必须使用变量名,因为 SameName 不是唯一的。另外,由于上面的 pszWeasel 变量具有唯一的名称,你可以仅仅使用它的成员名称来引用它:

        __asm

        {

        MOV EBX, OFFSET ftTest

        MOV ECX, [EBX]ftTest.SameName ; 必须使用"ftTest"

        MOV ESI, [EBX]. pszWeasel ; 可以省略"ftTest"

        }

       提示:省略变量名仅仅是为了书写代码方便,生成的汇编指令还是一样的。

       5. 用内联汇编写函数

        如果用内联汇编写函数的话,要传递参数和返回一个值都是非常容易的。看下面的例子,比较一下用独立汇编和内联汇编写的函数:

        ; PowerAsm.asm

        ; Compute the power of an integer

        PUBLIC GetPowerAsm

        _TEXT SEGMENT WORD PUBLIC 'CODE'

        GetPowerAsm PROC

        PUSH EBP ; Save EBP

        MOV EBP, ESP ; Move ESP into EBP so we can refer

        ; to arguments on the stack

        MOV EAX, [EBP+4] ; Get first argument

        MOV ECX, [EBP+6] ; Get second argument

        SHL EAX, CL ; EAX = EAX * (2 ^ CL)

        POP EBP ; Restore EBP

        RET ; Return with sum in EAX

        GetPowerAsm ENDP

        _TEXT ENDS

        END

        C/C++ 函数一般用堆栈来传递参数,所以上面的函数中需要通过堆栈位置来访问它的参数(在 MASM 或其它一些汇编工具中,也允许通过名称来访问堆栈参数和局部堆栈变量)。

        下面的程序是使用内联汇编写的:

        // PowerC.c

        #include

        int GetPowerC(int iNum, int iPower);

        int main()

        {

        printf("3 times 2 to the power of 5 is %d\n", GetPowerC( 3, 5));

        }

        int GetPowerC(int iNum, int iPower)

        {

        __asm

        {

        MOV EAX, iNum ; Get first argument

        MOV ECX, iPower ; Get second argument

        SHL EAX, CL ; EAX = EAX * (2 to the power of CL)

        }

        // Return with result in EAX

        }

        使用内联汇编写的 GetPowerC 函数可以通过参数名称来引用它的参数。由于 GetPowerC 函数没有执行 C 的 return 语句,所以编译器会给出一个警告信息,我们可以通过 #pragma warning 禁止生成这个警告。

        内联汇编的其中一个用途是编写 naked 函数的初始化和结束代码。对于一般的函数,编译器会自动帮我们生成函数的初始化(构建参数指针和分配局部变量等)和结束代码(平衡堆栈和返回一个值等)。使用内联汇编,我们可以自己编写干干净净的函数。当然,此时我们必须自己动手做一些有关函数初始化和扫尾的工作。例如:

        void __declspec(naked) MyNakedFunction()

        {

        // Naked functions must provide their own prolog.

        __asm

        {

        PUSH EBP

        MOV ESP, EBP

        SUB ESP, __LOCAL_SIZE

        }

        .

        .

        .

        // And we must provide epilog.

        __asm

        {

        POP EBP

        RET

        }

        }

       6. 调用 C/C++ 函数

        内联汇编中调用声明为 __cdecl 方式(默认)的 C/C++ 函数必须由调用者清除参数堆栈,下面是一个调用 C/C++ 函数例子:

        #include

        char szFormat[] = "%s %s\n";

        char szHello[] = "Hello";

        char szWorld[] = " world";

        void main()

        {

        __asm

        {

        MOV EAX, OFFSET szWorld

        PUSH EAX

        MOV EAX, OFFSET szHello

        PUSH EAX

        MOV EAX, OFFSET szFormat

        PUSH EAX

        CALL printf

        // 压入了 3 个参数在堆栈中,调用函数之后要调整堆栈

        ADD ESP,

        }

        }

       提示:参数是按从右往左的顺序压入堆栈的。

        如果调用 __stdcall 方式的函数,则不需要自己清除堆栈。因为这种函数的返回指令是 RET n,会自动清除堆栈。大多数 Windows API 函数均为 __stdcall 调用方式(仅除 wsprintf 等几个之外),下面是一个调用 MessageBox 函数的例子:

        #include

        TCHAR g_tszAppName[] = TEXT("API Test");

        void main()

        {

        TCHAR tszHello[] = TEXT("Hello, world!");

        __asm

        {

        PUSH MB_OK OR MB_ICONINFORMATION

        PUSH OFFSET g_tszAppName ; 全局变量用 OFFSET

        LEA EAX, tszHello ; 局部变量用 LEA

        PUSH EAX

        PUSH 0

        CALL DWORD PTR [MessageBox] ; 注意这里不是 CALL MessageBox,而是调用重定位过的函数地址

        }

        }

       提示:可以不受限制地访问 C++ 成员变量,但是不能访问 C++ 的成员函数。

       7. 定义 __asm 块为 C/C++ 宏

        使用 C/C++ 宏可以方便地把汇编代码插入到源代码中。wap文章php源码但是这其中需要额外地注意,因为宏将会扩展到一个逻辑行中。

       为了不会出现问题,请按以下规则编写宏:

       使用花括号把 __asm 块包围住;

       把 __asm 关键字放在每条汇编指令之前;

       使用经典 C 风格的注释("/* comment */"),不要使用汇编风格的注释("; comment")或单行的 C/C++ 注释("// comment");

        举个例子,下面定义了一个简单的宏:

        #define PORTIO __asm \

        /* Port output */ \

        { \

        __asm MOV AL, 2 \

        __asm MOV DX, 0xD \

        __asm OUT DX, AL \

        }

        乍一看来,后面的三个 __asm 关键字好像是多余的。其实它们是需要的,因为宏将被扩展到一个单行中:

        __asm /* Port output */ { __asm MOV AL, 2 __asm MOV DX, 0xD __asm OUT DX, AL }

        从扩展后的代码中可以看出,第三个和第四个 __asm 关键字是必须的(作为语句分隔符)。在 __asm 块中,只有 __asm 关键字和换行符会被认为是语句分隔符,又因为定义为宏的一个语句块会被认为是一个逻辑行,所以必须在每条指令之前使用 __asm 关键字。

        括号也是需要的,如果省略了它,编译器将不知道汇编代码在哪里结束,__asm 块后面的 C/C++ 语句看起来会被认为是汇编指令。

        同样是由于宏展开的原因,汇编风格的注释("; comment")和单行的 C/C++ 注释("// commen")也可能会出现错误。为了避免这些错误,在定义 __asm 块为宏时请使用经典 C 风格的注释("/* comment */")。

        和 C/C++ 宏一样 __asm 块写的宏也可以拥有参数。和 C/C++ 宏不一样的是,__asm 宏不能返回一个值,因此,不能使用这种宏作为 C/C++ 表达式。

        不要不加选择地调用这种类型的宏。比如,在声明为 __fastcall 的函数中调用汇编语言宏可能会导致不可预料的结果(请参看前文的说明)。

       8. 转跳

        可以在 C/C++ 里面使用 goto 转跳到 __asm 块中的标号处,也可以在 __asm 块中转跳到 __asm 块里面或外面的标号处。__asm 块内的标号是不区分大小写的(指令、指示符等也是不区分大小写的)。例如:

        void MyFunction()

        {

        goto C_Dest; /* 正确 */

        goto c_dest; /* 错误 */

        goto A_Dest; /* 正确 */

        goto a_dest; /* 正确 */

        __asm

        {

        JMP C_Dest ; 正确

        JMP c_dest ; 错误

        JMP A_Dest ; 正确

        JMP a_dest ; 正确

        a_dest: ; __asm 标号

        }

        C_Dest: /* C/C++ 标号 */

        return;

        }

        不要使用函数名称当作标号,否则将转跳到函数中执行,而不是标号处。例如,由于 exit 是 C/C++ 的函数,下面的转跳将不会到 exit 标号处:

        ; 错误:使用函数名作为标号

        JNE exit

        .

        .

        .

        exit:

        .

        .

        .

        美元符号"$"用于指定当前指令位置,常用于条件跳转中,例如:

        JNE $+5 ; 下面这条指令的长度是 5 个字节

        JMP _Label

        NOP ; $+5,转跳到了这里

        .

        .

        .

        _Label:

        .

        .

        .

       五、在 Visual C++ 工程中使用独立汇编

        内联汇编代码不易于移植,如果你的程序打算在不同类型的机器(比如 x 和 Alpha)上运行,你可能需要在不同的模块中使用特定的机器代码。这时候你可以使用 MASM(Microsoft Macro Assembler),因为 MASM 支持更多方便的宏指令和数据指示符。

        这里简单介绍一下在 Visual Studio .NET 中调用 MASM 编译独立汇编文件的步骤。

        在 Visual C++ 工程中,添加按 MASM 的要求编写的 .asm 文件。在解决方案资源管理器中,右击这个文件,选择"属性"菜单项,在属性对话框中,点击"自定义生成步骤",设置如下项目:

        命令行:ML.exe /nologo /c /coff "-Fo$(IntDir)\$(InputName).obj" "$(InputPath)"

        输出:$(IntDir)\$(InputName).obj

        如果要生成调试信息,可以在命令行中加入"/Zi"参数,还可以根据需要生成 .lst 和 .sbr 文件。

        如果要在汇编文件中调用 Windows API,可以从网上下载 MASM 包(包含了 MASM 汇编工具、非常完整的 Windows API 头文件/库文件、实用宏以及大量的 Win 汇编例子等)。相应地,应该在命令行中加入"/I X:\MASM\INCLUDE"参数指定 Windows API 汇编头文件(.inc)的路径。MASM 的主页是:,里面可以下载最新版本的 MASM 包。

AAC音视频编码详解

       AAC是高级音频编码(Advanced Audio Coding)的缩写,起始于年,最初是基于MPEG-2的音频编码技术,旨在替代MP3格式。年,MPEG-4标准发布后,AAC重新集成了其他技术(PS、SBR等),形成了LC-AAC、HE-AAC和HE-AACv2三种主要编码方式,其中LC-AAC用于中高码率(>Kbps),HE-AAC(等同于AAC+SBR)用于中低码率(<Kbps),而新推出的HE-AACv2(等同于AAC+SBR+PS)适用于低码率(<Kbps)。大部分编码器在Kbps时不加PS,相当于普通的HE-AAC。

       AAC共有9种规格,以适应不同场合的需求,包括MPEG-2 AAC LC、MPEG-2 AAC Main、MPEG-2 AAC SSR、MPEG-4 AAC LC、MPEG-4 AAC Main、MPEG-4 AAC SSR、MPEG-4 AAC LTP、MPEG-4 AAC LD、MPEG-4 AAC HE等。其中LC和HE(适合低码率)使用最广泛。流行的Nero AAC编码程序仅支持LC、HE和HEv2这三种规格,编码后的AAC音频显示规格通常为LC。HE相当于AAC(LC)+SBR技术,HEv2则是AAC(LC)+SBR+PS技术。

       HE(高效性):HE-AAC v1(又称AACPlusV1,SBR)使用容器方法实现了AAC(LC)+SBR技术。SBR代表频段复制,主要集中在低频段,高频段幅度虽小但很重要,决定了音质。若对整个频段编码,为了保护高频而造成低频段编码过细,文件会很大;若保存低频的主要成分而失去高频成分,则会丧失音质。SBR将频谱分割,低频单独编码保存主要成分,高频单独放大编码保存音质,达到在减少文件大小的同时保持音质的目的。

       HEv2:使用容器方法包含了HE-AAC v1和PS技术。PS指参数立体声,原来的立体声文件文件大小是一个声道的两倍。但是两个声道的声音存在某种相似性,根据香农信息熵编码定理,相关性应被去除才能减小文件大小。因此,PS技术存储了一个声道的全部信息,然后用很少的字节用参数描述另一个声道与之不同的地方。

       AAC编码具有高压缩比、高质量、高效解码等特性,支持多种采样率和比特率、支持1至个音轨、支持个低频音轨、具备多种语言兼容能力、支持多达个内嵌数据流,支持更宽的声音频率范围,最高可达kHz,最低可达8KHz,远宽于MP3的KHz-kHz范围。AAC几乎不损失声音频率中的甚高、甚低频率成分,频谱结构更接近原始音频,声音保真度更好,专业评测显示,AAC声音更清晰,更接近原音。

       AAC的音频文件格式包括ADIF与ADTS,ADIF音频数据交换格式在磁盘文件中使用,ADTS音频数据传输流在比特流中使用,两者都有同步字,ADTS可以在任意帧解码。ADIF头信息包含原始数据块的组成,有六种元素:SCE、CPE、CCE、LFE、DSE、PCE、FIL。AAC文件处理流程包括判断文件格式、解ADIF头信息或寻找同步头、解ADTS帧头信息、错误检测、解块信息和元素信息。

       开源AAC解码器faad官方网站为audiocoding.com,faad2源代码下载地址为download.csdn.net。

BSC这个英文缩写是什么意思?

       若是 BSc

       意思是 理学士 (Bachelor of Science)

       若是 BSC

       意思是 浏览信息文件,由浏览信息维护工具(BSCMAKE)从原始浏览信息文件(.SBR)中生成,BSC文件可以用来在源代码编辑窗口中进行快速定位。

       我是在字典上查的,呵呵.

声音数字化的过程分为哪三个步骤

       1、引言

       就音频而言,无论是算法多样性,Codec种类还是音频编解码复杂程度都远远比视频要高。视频的Codec目前还主要是以宏块为处理单元,预测加变换的混合编码框架,例如H.和H.都是在这一框架下。而音频则相当复杂,且不同的场景必须要选择不同的音频编解码器。以下就是本次为大家分享的主要内容,希望通过此次分享可以使大家对音频编解码有一个整体的认识,并在实际应用中有参考的依据。

       本次分享的内容提纲:

       1)语音/音频编码总表;

       2)数字语音基本要素;

       3)为什么要压缩;

       4)编码器考虑的因素;

       5)语音经典编码模型;

       6)ISO;

       7)编码模型;

       8)USAC;

       9)编码;

       )使用选型考虑的因素。

       * 本次演讲PPT文稿,请从文末附件下载!

       (本文同步发布于:

       /thread--1-1.html)

       2、分享者

       刘华平:

       - 现为网易云音乐音视频实验室负责人,上海大学通信学院在职博士;

       - 曾任掌门集团(WIFI万能钥匙)音视频技术研发总监,资深研究员;

       - 行者悟空声学技术有限公司首席技术官(联合创始人);

       - 阿里巴巴前高级技术专家(P8), 阿里音乐音视频部门总监;

       - Visualon音频部门经理、盛大创新院研究员、Freescale 上海研发中心多媒体部门;

       - 早期 Google Android SDK多媒体架构的贡献者,开源 AMR_WB 编码器工程开发者。

       刘华平拥有5项技术发明专利、二十余篇专业论文和多项软件著作权,参与过浙江省杭州重大专项项目,浙江省金华科委项目,上海市科委项目(球谐域全景音频关键技术研究)。

       3、系列文章

       本文是系列文章中的第篇,本系列文章的大纲如下:

       《即时通讯音视频开发(一):视频编解码之理论概述》

       《即时通讯音视频开发(二):视频编解码之数字视频介绍》

       《即时通讯音视频开发(三):视频编解码之编码基础》

       《即时通讯音视频开发(四):视频编解码之预测技术介绍》

       《即时通讯音视频开发(五):认识主流视频编码技术H.》

       《即时通讯音视频开发(六):如何开始音频编解码技术的学习》

       《即时通讯音视频开发(七):音频基础及编码原理入门》

       《即时通讯音视频开发(八):常见的实时语音通讯编码标准》

       《即时通讯音视频开发(九):实时语音通讯的回音及回音消除概述》

       《即时通讯音视频开发(十):实时语音通讯的回音消除技术详解》

       《即时通讯音视频开发(十一):实时语音通讯丢包补偿技术详解》

       《即时通讯音视频开发(十二):多人实时音视频聊天架构探讨》

       《即时通讯音视频开发(十三):实时视频编码H.的特点与优势》

       《即时通讯音视频开发(十四):实时音视频数据传输协议介绍》

       《即时通讯音视频开发(十五):聊聊P2P与实时音视频的应用情况》

       《即时通讯音视频开发(十六):移动端实时音视频开发的几个建议》

       《即时通讯音视频开发(十七):视频编码H.、V8的前世今生》

       《即时通讯音视频开发(十八):详解音频编解码的原理、演进和应用选型》(本文)

       4、语言/音频编码总表

       ▲ 语言/音频编码总表

       上图展示的是语言/音频编码总表,可以看到其比视频编码要复杂得多,单纯的算法也远远比视频要更加复杂。

       5、数字语言基本要素

       数字声音具有三个要素:

       1)采样率;

       2)通道数;

       3)量化位数。

       ▲ 声音数字化的过程

       如上图所示,声音数字化的过程为:

       1)采样:在时间轴上对信号数字化;

       2)量化:在幅度轴上对信号数字化;

       3)编码:按一定格式记录采样和量化后的数字数据。

       6、为什么要压缩

       压缩音频,主要是为了在降低带宽负担的同时为视频腾出更多带宽空间。存储和带宽二大因素决定了语音压缩的必要性。

       我们看看下面的例子。

       长度为4分钟,采样频率为Hz,采样深度为bits,双声音Wav文件大小:

       Hz*bits*4minutes*2=(/1second)*bits*(4minutes*(seconds/1minutes)*2=bits/second*seconds=bits=/(8bits/1byte)*2=bytes=/(/1M)bytes=.MB

       MP3,kbps压缩后文件大小:

       kbps*4minutes=(kbits/1second)*(4minutes*(seconds/1minutes))=(kbits/1second)*seconds=kbits=kbits/(8bits/1byte)=kbytes=k/(k/1M)bytes=3.Mbytes=3.MB

       正如上面的例子,声音压缩后,存储大小为原大小的十分之一,压缩率十分可观!

       7、编码器考虑因素

       7.1 基本概念

       编码器考虑的因素:

       1)最佳压缩比;

       2)算法的复杂度;

       3)算法延时;

       4)针对特殊场景下的特定设计;

       5)兼容性。

       通过一些特定的压缩算法,可以压缩音频文件至原来的1/,同时人耳也无法分辨压缩前后的声音质量差异,需要满足多种条件才能实现这种效果;而对于编码器,无论是设计阶段还是使用阶段,我们都需要考虑最佳压缩效果、算法的复杂度与算法的延时,结合特殊场景进行特定的设计;而兼容性也是我们不能不考虑的重点。

       7.2 语音经典编码模型:发音模型

       ▲ 发音模型(原图点击查看)

       我们的很多编解码器都是基于综合人的发音模型与一些和听觉相关的理论支持研究提出的特定编解码算法。初期我们通过研究人的发音原理来设计音频编解码的算法,包括端到端的滤波或轻浊音等,只有充分理解人的发声原理我们才能在编解码端做出有价值的优化。

       7.2.1语音编码模型——LPC:

       ▲ 经典语音编码模型:LPC(原图点击查看)

       ▲ LPC 数学表达

       LPC作为经典语音编码模式,其本质是一个线性预测的过程。早期的G.7系列编码模型便是通过此模型对整个语音进行编码,上图展示的过程可与之前的人发声过程进行匹配,每个环节都有一个相应的模块用来支撑人发声的过程。其中使用了AR数学模型进行线性预测,此算法也是现在很多语音编码的重要组成模块。

       7.2.2语音编码模型——G.:

       ▲经典语音编码模型: G.(CELP)

       G.同样是经典的语音编码模型之一,也是我们学习语音编码的一个入门级Codec。G.的文档十分完善,包括每个模块的源代码在内都可直接下载。G.可以说是在早期发声模型基础上的改进,需要关注的性能指标是帧长与算法上的延时,包括语音质量的MOS分。G.也有很多变种,由于语音需要考虑系统兼容性,不同的系统指定携带的Codec也不同,音频编码的复杂程度要远高于视频编码。

       G. 建议了共轭结构的算术码本激励线性预测(CS-ACELP)编码方案。G.算法的帧长为ms, 编码器含5ms 前瞻,算法时延ms,语音质量MOS分可达4.0。

       7.3 语音经典编码模型——听觉模型

       ▲ ISO编码模型:心理声学模型

       除了研究人发声的原理,我们还需要研究人听声的原理,从而更好实现声音的收集与处理。一个声音信号是否能被人耳听见主要取决于声音信号的频率、强度与其他音的干扰。心理声学模型便是用来找出音频信号中存在的冗余信息从而实现在压缩声音信号的同时不影响听觉的目的。心理声学理论的成熟为感知编码系统奠定了理论基础,这里的感知编码主要是ISO编码模型,主要覆盖的声学原理有临界频带、绝对听觉阈值、频域掩蔽、时域掩蔽等。

       ▲ 听觉模型

       无论是MP3还是AAC以至于到后面的杜比音效都是基于听觉模型进行的探索与创新。

       7.3.1临界频带:

       由于声音频率与掩蔽曲线不是线性关系,为从感知上来统一度量声音频率,引入了“临界频带”的概念。通常认为,在Hz到kHz范围内有个监界频带。临界频带的单位叫Bark(巴克)。

       ▲ 临界频带

       临界频带主要用于心理声学模型。由于声音频率与掩蔽曲线并非线性关系,为从感知上来统一度量声音频率,我们引入了“临界频带”的概念。人耳对每段的某个频率的灵敏度不同,二者关系是非线性的。通常我们会将人可以听到的整个频率也就是从Hz到KHz分为个频带,可在其中进行时域或频域类的掩蔽,将一些冗余信息从编码中去除从而有效提升压缩率。

       7.3.2绝对听觉阈值:

       ▲ 绝对听觉阈值

       绝对听觉阈值也可有效提升压缩率,基于心理声学模型,可去除编码中的冗余部分。

       7.4 经典音频编码:ISO

       ▲ 经典音频编码:ISO

       我们可将最早的MP3 Layer1理解为第一代的ISO感知编码,随后的一些纯量化内容更多的是在压缩上进行改进而核心一直未改变。从MP3 Layer1到Layer2与Layer3,主要的改变是心理声学模型的迭代。

       ▲ MPEG1 LayerI Codec

       ▲ MPEG1 LayerIII Codec

       上图展示的是Encode与Decode的回路。输入的PCM首先会经过多子带分析与频域中的心理声学模型冗余处理,而后进行量化编码;Layer III中的是我们现在常说的MP3的Codec:Encode与Decode之间的整体回路,相比于Layer1多了几个处理环节以及霍夫曼编码。

       7.5 AAC协议族

       ▲ AAC家族

       AAC与G.一样包括很多系列,但AAC的巧妙之处在于向下兼容的特性。开始时我们就强调,所有Codec在设计时都需要考虑兼容性,瑞典的Coding Technology公司曾提出在兼容性上特别优化的方案。AAC Plus V1包括AAC与SBR,AAC Plus V2包括AAC+SBR+PS,现在常见的很多音乐类或直播音频编码都是基于AAC Plus协议族进行的。

       德国的霍朗浦学院曾在AAC低延时协议扩展方面做出一些探索并得到了AAC LD协议族,其原理仍基于传统的AAC模块,但在后端会对处理长度进行调整,例如之前是以bit为一个处理单位,那改进后则以bit为一个处理单位。除此之外AAC LD加入了LD-SBR与LD-MPS等,从而形成一个规模较大的AAC-ELD V2模块,可以说是十分巧妙。

       7.5.1AACPlus核心模块——SBR(Spectral Band Replication):

       ▲ SBR(Spectral Band Replication)

       我们可以看到,AAC可以说充分利用了频域扩展,用很小的代价实现诸多功能优化。AAC的核心之一是SBR,这是一种使用极少位数就可描述高频部分并在解码时进行特殊优化从而实现频域扩展的模块。上图展示的是不同压缩率模块所覆盖的频率取值范围,而使用AAC时需要注意一个被称为“甜点码率”的指标。无论是采样率还是码率都是变化的,在应用时选择何种码率十分关键。例如直播时采用Kbps即可在覆盖整个频段的同时保持良好音质。

       7.5.2AACPlus核心模块——PS(Parametric Stereo):

       ▲ :PS(Parametric Stereo)

       PS 描述参数:IID(Inter-channel Intensity Difference),,ICC(Inter-channel Cross-Correlation),IPD(Inter-channel Phase Difference)。

       ▲ AACPlus v2编码框图

       ▲ AACPlus v2解码框图

       PS模块也是AAC的核心模块之一,主要用于分析左右声道属性并使用非常少的位数表示左右声道相关性,而后在解码端将左右声道分离。这里比较巧妙的是PS的向下兼容特性,整体数据打包是分开进行的。如果获取到AAC、SBR、PS三者的基本数据包后,在解码阶段我们就只需AAC—LC。上图展示的就是AAC的解码框架,如果大家读过3GPP的代码就可发现其每一个模块都相当清楚。我们可根据文档读取代码并对应到每一个环节。

       7.5.3甜点码率:

       ▲ AAC 甜点码率

       甜点码率是一项很关键的指标。例如在手机直播应用场景中,一般的视频分辨率为×,音频码率大约在K左右。如果音频码率过大则会直接影响视频质量,因而我们需要控制音频码率在一个较为合适的范围内从而实现最佳的音画效果。在很多应用场景中可能需要系统根据不同的网络环境下载不同音质的文件,例如在2G环境中下载较小的文件,这样做主要是为了节省带宽并提高音频文件的播放流畅程度。

       7.6 AAC-ELD家族

       AAC-ELD家族产生背景:

       aacplus v2 已经在压缩和音质方面做到了近似于极致,但由于算法实现上的长达ms左右的延时极大的阻碍aacplus v2在实时通讯领域的应用。Fraunhofer IIS 为了解决这个问题,对AAC进行相关改进,形成了AAC-ELD协议族。

       ▲ AAC-ELD家族

       AAC-ELD家族带来的主要改进是低延迟。如果Codec的延迟太长便无法在一些特定场景中被使用。例如早期AAC Plus V2的整体延迟可达ms,如此高的延迟肯定无法被应用于语音通话等对实时性要求极高的应用场景。霍朗普学院推出的AAC-ELD可在保持音质的前提下将延迟降低至ms,相对于MP3最高长达ms的延迟而言提升巨大。

       7.7 应用中端到端的延迟

       ▲ 端到端的延时

       编解码过程也存在延时问题,这也是我们选择编解码器时需要考虑的最主要因素之一,编解码的延时主要由处理延时与算法延时组成,例如G.的算法延时为ms,而AAC-LC可达到一百毫秒以上。另外,播放端或采集端的长帧数量太多,播放时缓存太多等也会直接影响延时,我们在选择编解码器时需要考虑延时带来的影响。

       编解码器已经历了两个发展方向:

       1)一个是以G.7(G.)为例,根据发声模型设计的一套主要集中于语音方面的编解码算法;

       2)另一个是以ISO的MP3和AAC为例,根据心理声学模型设计的一套感知编码。

       最近的趋势是编码的统一:

       原来在语音场景下我们使用8K或K进行采样,音乐场景下则需使用覆盖到全频带的.1K进行采样,每个Codec都有一个频域覆盖的范围。在之前的开发中,如果应用场景仅针对压缩语音那么需要选择语音编码方案,如果应用场景针对压缩音乐则需要选择音乐编码方案,而现在的发展方向是通过一套编码从容应对语音与音乐两个应用场景,这就是接下来将要被提到的USAC。

       这里介绍两个比较典型的Codec:

       1)一个是Opus,通过其中集成的模块可实现根据传入音频文件的采样率等属性自动选择语音编码或音乐编码;

       2)另一个是EVS这也是霍朗普等组织推行的方案,已经尝试用于4G或5G之中。

       EVS (Enhanced Voice Services):

       主要是VoiceAge, Dolby, Fraunhofer, 华为联合开发的USAC编码器,低速率音乐编码质量很好。

       ▲ USAC

       由框图我们可以了解到USAC向下兼容的特性。

       编解码器可总结为经历了三个时代:

       1)发声模型;

       2)听觉感知;

       3)融合方案。

       接下来我将展示目前所有的Codec情况并整理为表格以方便大家检索查阅。

       8、解码器(Codec)总结

       8.1 IETF系列

       IETF作为标准协议联盟组织之一推出了以上Codec:Opus包括采样率为8kHz、甜点码率为kbps的窄带单声语音(SILK),采样率为kHz、甜点码率为kbps的宽带单声语音与采样率为kHz、甜点码率为kbps的全带单声语音(CELT),采用甜点码率意味着将压缩率和音质保持在一个良好的平衡状态。在一些窄带单声语音应用场景例如常见的微信语音聊天,其压缩率可达到原来的8.5%。Opus没有技术专利和源代码的门槛,使得其受到现在很多流媒体厂商的欢迎,Opus支持更广的码率范围,具备丰富采样率选择,可实现极低延迟与可变帧大小,也具备以往一些Codec的许多特性如CBR、VBR、动态调整等,支持的通道数量也更多。除此之外,Opus同样具备许多从SILK移植而来的特性或功能。如在VUIB传输上集成了扛丢包模式等。

       iLBC早在SILK未出现时就被提出同样具备抗丢包。的特性,高达.2kbps的甜点码率与4.的Mos使其音质较为良好,超过G.的相关指标;GSM就是最早手机网络仍停留在2G时代时流行的编码形式,主要用于蜂窝电话的编码任务。

       8.2 AMR系列

       AMR早在3G时期就被广泛应用,AMR-NB是最流行的语音编码器,具有压缩效果好,支持多种码率形式的特点;与此同时,这也是GSM与3G时期Android平台最早支持的窄带语音编码方案。AMR-WB作为AMR-NB向宽带的扩展版,主要用于3G和4G通话标准协议中,其甜点码率为.kbps。在实践中我们将码率参数调整为此值即可实现压缩率与质量的平衡。AMR-WB+则是上述两者的融合,三者共同构成AMR系列。

       8.3 ITU-T G系列

       ITU-T G系列包括最早的波形编码G到现在大家熟悉的G.这里我想强调的是G.1 Siren7、G.1c Siren与G Siren,例如G.可覆盖整个前频带且支持立体声。即使都属于老协议,但由于其优秀的兼容性,不应被我们忽略。

       将Opus与其他一些Codec进行对比我们可以看到,无论是质量还是延时控制,Opus的优势十分明显;加之Opus作为开源的免费方案,不存在专利限制,受到业界追捧也不足为奇。

       8.4 ISO系列

       ISO里我想强调的是MP3与AAC,二者同样支持很多码率。MP3的甜点码率为kbps,MP3 Pro的码率可达到MP3的一半;AAC支持8~khz的采样率,AAC-LC的甜点码率为kbps,HE-AAC的甜点码率为kbps,AAC-LD与ELD做到了AAC的低延时,实现了延时与压缩比的最佳平衡。

       8.5 3GPP系列:EVRC

       EVRC 是CDMA 中使用的语音编解码器,由高通公司年提出目标是取代QCELP。

       高通公司主推的3GPP是CDMA中使用的语音编解码器,在未来选择编解码器类型时我们需要特别考虑延时与帧长。由于语音编码种类很多,帧长也是复杂多变的,其背后的算法复杂程度,RAM、ROM占用等都是在实践当中需要着重考虑的。

       8.6 极低码率

       极低码率主要的应用场景是对讲机、卫星通讯、军工等。

       上图图表中的MELP最早由美国军方开发,现在绝大多数的对讲机都基于此模型进行扩展开发,压缩后的码率可达到2.4kbps而目前最极端的极低码率可实现bps,相当于压缩为原数据的0.2%,此时的音频文件仅能被用于传达语音内容而丢失了很多声色。

       8.7 全频带

       全频带中的组合也是多种多样。

       9、编解码使用注意

       9.1 License

       ▲ 开源项目常用的Lisence

       国内大部分企业在开发时容易忽视包括专利安全性在内的与License相关的内容。如果企业计划得比较长远,需要长期使用某项技术或企业规模不断扩大时则不能不考虑专利问题。专利费用包括Open Source与算法专利,二者完全独立互不干涉,如果我们从某家专利公司购买了AAC的专利算法,并不能获得此AAC专利的源代码,仅能获得与此技术相关的专利使用授权。专利公司会给予需要下载的文件列表,通过这种方式实现技术的授权使用。

       ▲ 一张图看懂Lisence(来自:阮一峰的博客)

       上面的二叉树图比较清晰地展示了代码授权的具体流程,随着企业的规模化发展日趋成熟,企业应当规范自身的技术使用行为,尽可能避免专利纠纷带来的不利影响。

       9.2 专利

       ▲ 2个著名的多媒体技术专利池

       主流语音编解码技术拥有两个专利池:

       1)MPEG-LA;

       2)Via Licensing。

       很多非常复杂的Codec涉及高达上千个专利,与之相关的企业或组织多达几十个,为专利授权而与每一个企业或组织进行洽谈显然是不现实的,因而专利池的出现使得技术授权更加规范清晰,方便企业统一处理技术授权问题。

       9.3 常见Codec Patent License

       希望大家在使用技术的同时尊重知识产权,助力技术创新可持续发展。

       、讲稿PPT下载

       (因无法上传附件,请从原文附件下载:

       /thread--1-1.html)

       附录:更多音视频技术资料

       实时音视频开发的其它精华资料:

       《实时语音聊天中的音频处理与编码压缩技术简述》

       《网易视频云技术分享:音频处理与压缩技术快速入门》

       《学习RFC:RTP/RTCP实时传输协议基础知识》

       《基于RTMP数据传输协议的实时流媒体技术研究(论文全文)》

       《声网架构师谈实时音视频云的实现难点(视频采访)》

       《浅谈开发实时视频直播平台的技术要点》

       《还在靠“喂喂喂”测试实时语音通话质量?本文教你科学的评测方法!》

       《实现延迟低于毫秒的P实时音视频直播的实践分享》

       《移动端实时视频直播技术实践:如何做到实时秒开、流畅不卡》

       《如何用最简单的方法测试你的实时音视频方案》

       《技术揭秘:支持百万级粉丝互动的Facebook实时视频直播》

       《简述实时音视频聊天中端到端加密(E2EE)的工作原理》

       《移动端实时音视频直播技术详解(一):开篇》

       《移动端实时音视频直播技术详解(二):采集》

       《移动端实时音视频直播技术详解(三):处理》

       《移动端实时音视频直播技术详解(四):编码和封装》

       《移动端实时音视频直播技术详解(五):推流和传输》

       《移动端实时音视频直播技术详解(六):延迟优化》