虚拟内存一种抽象的形式,它使得每一个进程都以为自己独占整个主存。每一个进程的内存分布都有统一的视图,被称为它的虚拟地址空间。
Linux的虚拟地址空间如图1.13所示。(其它的Unix系统也使用类似的布局。)
在Linux中,操作系统把虚拟地址空间最顶端的区域(译者注:内核空间)保留用于所有进程的公共代码和数据。地址空间的低端区域(译者注:用户空间)被用户进程用来存储代码和数据。注意表格中的地址空间增长方向是从下到上的。
(译者注:在Linux系统中(32位),0x00000000~0xbfffffff为用户空间,0xc0000000~0xffffffff为内核空间。)
每一个进程看到的虚拟地址空间是由一些被划分好的用于特定目的的区域组成。在本书的随后部分你会获取到更多关于这些区域的细节,但是简略地从低端开始向上看一下每个区域也是很有帮助的。
- Program code and data.所有的进程的代码都从相同固定的地址开始,接下来是数据区域,相当于C语言中的全局变量。代码和数据是直接用可执行文件的内容进行初始化,在我们例子里是hello文件。在第7章我们学习链接和加载时会学习更多的关于地址空间的这部分内容。
- Heap.在代码和数据区域之后紧跟着运行时的堆。代码和数据区域在程序开始运行一次性分配固定大小的区域,与它不同的是,堆的扩张和缩小是动态的,它是调用C标准库如malloc和free之后的运行结果。我们在第9章学习虚拟内存管理时将学习更多的关于堆的细节。
- Shared libraries.大概在地址空间的中间部分的区域用于装载了共享库如C标准库和数学库的代码和数据。共享库的概念非常强大但比较难以理解。你将会在第7章学习动态链接时了解它们是如何工作的。
- Stack.在用户虚拟内存地址空间的最顶端是用户栈,编译器利用它来实现函数调用。跟堆一样,在程序运行用户栈的扩张和缩小也是动态的。特别是我每们调用一次函数时,栈就是增长。每次函数返回时,栈就是缩小。你会在第3章学习到编译器如何使用栈。
- Kernel virtual memory.内核是操作系统的一部分,它总是长驻于内存。地址空间的最顶端区保留给内核使用。应用程序不允许读写这部分区域和直接调用内核代码段里定义的函数。
正常运作虚拟内存需要硬件和操作系统软件一系列的复杂交互,包括对处理器使用的每一个地址进行硬件转换。基本的思想是将进程的虚拟内存的内容存储在磁盘上,把主存当作磁盘的缓存使用。第9章将会介绍它的工作原理并解释为什么它对于现代操作是如此的重要。
libx264版本是128
libfaac版本是1.28
1、帧的划分
1.1 H.264帧
对于H.264而言每帧的界定符为00 00 00 01或者00 00 01。
比如下面的h264文件片断这就包函三帧数据
00 00 00 01 67 42 C0 28 DA 01 E0 08 9F 96 10 00
00 03 00 10 00 00 03 01 48 F1 83 2A 00 00 00 01
68 CE 3C 80 00 00 01 06 05 FF FF 5D DC 45 E9 BD
E6 D9 48 B7 96 2C D8 20 D9 23 EE EF …
第一帧是00 00 00 01 67 42 C0 28 DA 01 E0 08 9F 96 10 00 00 03 00 10 00 00 03 01 48 F1 83 2A
第二帧是00 00 00 01 68 CE 3C 80
第三帧是00 00 01 06 05 FF FF 5D DC 45 E9 BD E6 D9 48 B7 96 2C D8 20 D9 23 EE EF ..
帧类型有:
NAL_SLICE = 1
NAL_SLICE_DPA = 2
NAL_SLICE_DPB = 3
NAL_SLICE_DPC = 4
NAL_SLICE_IDR = 5
NAL_SEI = 6
NAL_SPS = 7
NAL_PPS = 8
NAL_AUD = 9
NAL_FILLER = 12,
我们发送RTMP数据时只需要知道四种帧类型,其它类型我都把它规类成非关键帧。
分别是
NAL_SPS(7), sps帧
NAL_PPS(8), pps帧
NAL_SLICE_IDR(5), 关键帧
NAL_SLICE(1) 非关键帧
帧类型的方式判断为界面符后首字节的低四位。
第一帧的帧类型为: 0x67 & 0x1F = 7,这是一个SPS帧
第二帧的帧类型为: 0x68 & 0x1F = 8,这是一个PPS帧
第三帧的帧类型为: 0x06 & 0x1F = 6,这是一个SEI帧
以上是我们利用帧界定符划分帧,并可以判断每一个帧的类型。
注意:如果是压缩图像成H264帧,我们就可不必进行帧界定,因为每一次压缩的输出都明确了该帧的大小(包括界定符),每一次的压缩的结果可能包函多帧。一会具体讨论。
1.2 AAC帧
对于AAC帧它的界定符是FF F1
这里我就不举例了,可通过查看AAC的二进制文件可以看到如下的帧结构。
FF F1 50 80 24 9F FD DE 04 00 00 6C 69 62 66 61 61 63 20 31 2E 32 38 00 00 42 15 95 ..
注意:那么对于AAC而言加上界定符每一帧的前7字节是帧的描述信息,也就是说AAC的祼数据是除去前面的7个字节的,在发送RTMP时,我们要去掉这7个字节。同样,如果我们是一边压缩一边发送RTMP,我们同样不需要界定帧,因为libfaac每次压缩完成的输出就是一个完整的帧数据,我们只需要将该帧打包发送即可。
综合上面的所述,如果我们只是一边压缩一边将压缩结果发送到RTMP服务器,那我们就可以不用对帧进行界定,如果我们是发送H264与AAC文件,那我们就要对帧进行界定。
2.视频与音频的编码信息
如果我们只是简答的将压缩数据打包发送给RTMP服务器,那么RTMP服务器是不可以对数据进行解码和播放的,在这之前我们要将音视频的视频的编码信息发送给RTMP服务器。很多人可能苦于寻找下面的三个编码参数而不得要领。其实要想得到也是很简单的。 阅读全文…