zoukankan      html  css  js  c++  java
  • H 264简单介绍

    一、H264
    在H264协议里定义了三种帧,完整编码的帧叫I帧,参考之前的I帧生成的只包含差异部分编码的帧叫P帧,
    还有一种参考前后的帧编码的帧叫B帧。
    H264采用的核心算法是帧内压缩和帧间压缩,帧内压缩是生成I帧的算法,帧间压缩是生成B帧和P帧的算法。
     一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像
     二、音视频基础知识
     采样率表示了每秒钟的采样次数。
     比特率表示了每秒钟传输的音频数据量,该值也和采样率相关。
    采样率类似于动态影像的帧数,比如电影的采样率是24HZ,P
    AL制式的采样率是25HZ,NTSC制式的采样率是30HZ。
    当我们把采样到的一个个静止画面再以采样率同样的速度回放时,看到的就是连续的画面。
    同样的道理,把以44100HZ采样率记录的CD以同样的速率播放时,就能听到连续的声音。
    显然,这个采样率越高,听到的声音和看到的图像就越连贯。
    可是人的听觉和视觉器官能分辨的采样率是有限的,基本上高于44100HZ采样的声音,
    绝大部分人已经觉察不到其中的分别了。
    而声音的位数就相当于画面的颜色数(8位就是0-255),表示每个取样的数据量, 
    当然数据量越大,回放的声音越准确,不至于把开水壶的叫声和火车的鸣笛混淆。
    同样的道理,对于画面来说就是更清晰和准确,不至于把血和西红柿酱混淆。
    不过受人的器官的机能限制,16位的声音和24位的画面基本已经是普通人类的极限了,
    更高位数就只能靠仪器才能分辨出来了。比如电话就是3000HZ取样的7位声音,
    而CD是44100HZ取样的16位声音,所以CD就比电话更清楚。
    有了以上这两个概念,比特率就很容易理解了。以电话为例,每秒3000次取样,
    每个取样是7比特,那么电话的比特率是21000。而CD是每秒44100次取样,两个声道,
    每个取样是16位PCM编码,所以CD的比特率是44100*2*16=1411200,也就是说CD每秒的数据量大约是176KB。
    三、H264是的编码知识
    在H.264/AVC视频编码标准中,整个系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面(NAL)。
    其中,前者负责有效表示视频数据的内容,而后者则负责格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。
    因此我们平时的每帧数据就是一个NAL单元(SPS与PPS除外)。
    在实际的H264数据帧中,往往帧前面带有00 00 00 01 或 00 00 01分隔符,一
    般来说编码器编出的首帧数据为PPS与SPS,接着为I帧……
    我们还是接着看最上面图的码流对应的数据来层层分析,以00 00 00 01分割之后的下一个字节就是NALU类型,
    将其转为二进制数据后,解读顺序为从左往右算,如下:
    (1)第1位禁止位,值为1表示语法出错
    (2)第2~3位为参考级别
    (3)第4~8为是nal单元类型
    例如上面00000001后有67,68以及65
    其中0x67的二进制码为:
    0110 0111
    4-8为00111,转为十进制7,参考第二幅图:7对应序列参数集SPS
    其中0x68的二进制码为:
    0110 1000
    4-8为01000,转为十进制8,参考第二幅图:8对应图像参数集PPS
    其中0x65的二进制码为:
    0110 0101
    4-8为00101,转为十进制5,参考第二幅图:5对应IDR图像中的片(I帧)
    1、对于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 ..
    2、帧类型有:
    
    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 SPS帧
    NAL_PPS = 8 PPS帧
    NAL_AUD = 9
    NAL_FILLER = 12
    
    3、PPS 与SPS
    SPS 对于H264而言,就是编码后的第一帧,如果是读取的H264文件,就是第一个帧界定符和第二个帧界定符之间的数据的长度是4
    PPS 就是编码后的第二帧,如果是读取的H264文件,就是第二帧界定符和第三帧界定符中间的数据长度不固定。
    在H264码流中,都是以"0x00 0x00 0x01"或者"0x00 0x00 0x00 0x01"为开始码的,找到开始码之后,使用开始码之后的第一个字节的第5位判断是否为7(sps)或者8(pps),
    SDP中的H.264的SPS和PPS串,包含了初始化H.264解码器所需要的信息参数,包括编码所用的profile,level,图像的宽和高,deblock滤波器等
    再给avc解码器送数据流之前一定要把sps,pps信息送出,否则的话不能正常解码。而且在解码器stop之后再次start之前,比如seek,快进快退状态切换等,都需要重新发送一遍sps和pps信息
    pps sps 在片的头信息和数据解码前送至解码器,否则播放不出来
    rtmp数据包,在I帧数据前,有SPS也不会影响rtmp流的播放,但在转成ts数据包的时候,是将sps数据和I帧数据前加NALU头后,进行TS封装的。
    4、I 和IDR都是使用帧内预测的,要首个I帧和其他i帧区别开,所以才把第一个i帧叫做IDR。IDR帧的作用是立即刷新,使错误不至传播
    从IDR帧开始,重新算一个新的序列开始编码。而I帧不具有随机访问的能力,这个功能是由IDR承担。
    5、h264
    在H.264/AVC视频编码标准中,整个系统框架被分为了两个层面:视频编码层面(VCL)和网络抽象层面(NAL)。
    其中,前者负责有效表示视频数据的内容,而后者则负责格式化数据并提供头信息,以保证数据适合各种信道和存储介质上的传输。NAL占一个字节。
    
    NAL单元(NALU):NAL的基本语法结构,它包含一个字节的头信息和一系列来自VCL的称为原始字节序列载荷(RBSP)的字节流。 
    数据流是储存在介质上时: 每个NALU 前添加起始码:0x00000001(或者0x000001),用来指示一个 NALU的起始和终止位置。我们平时的每帧数据就是一个NAL单元(SPS与PPS除外)。
     编码器将每个NAL各自独立、完整地放入一个分组,因为分组都有头部,解码器可以方便地检测出NAL的分界,并依次取出NAL进行解码。
     每个NAL前有一个起始码 0x00 00 01(或者0x00 00 00 01),解码器检测每个起始码,作为一个NAL的起始标识,当检测到下一个起始码时,当前NAL结束。
     同时H.264规定,当检测到0x000000时,也可以表征当前NAL的结束。那么NAL中数据出现0x000001或0x000000时怎么办?H.264引入了防止竞争机制,
     如果编码器检测到NAL数据存在0x000001或0x000000时,编码器会在最后个字节前插入一个新的字节0x03
    三、流的基本概念
    1、
    四、rtmp协议
    1、rtmp客户端与服务器一般握手的顺序是:
    |client|Server | 
    |---C0+C1—->|<--S0+S1+S2– | 
    |---C2---->2、 Message(消息)
    
    这里的Message是指满足该协议格式的、可以切分成Chunk发送的消息,消息包含的字段如下:
    
    Timestamp(时间戳):消息的时间戳(但不一定是当前时间,后面会介绍),4个字节
    Length(长度):是指Message Payload(消息负载)即音视频等信息的数据的长度,3个字节
    TypeId(类型Id):消息的类型Id,1个字节
    Message Stream ID(消息的流ID):每个消息的唯一标识,
    划分成Chunk和还原Chunk为Message的时候都是根据这个ID来辨识是否是同一个消息的Chunk的,
    4个字节,并且以小端格式存储
    3、Chunking(Message分块)
    发送端,会把message 拆分成chunk,
    在一个Chunk发送完成之后才能开始发送下一个Chunk
    每个Chunk中带有MessageID代表属于哪个Message,接受端也会按照这个id来将chunk组装成Message
    数据量较大的Message可以被拆分成较小的“Message”,
    这样就可以避免优先级低的消息持续发送阻塞优先级高的数据
    hunk的默认大小是128字节,在传输过程中,通过一个叫做Set Chunk Size的控制信息可以设置
    Chunk数据量的最大值,在发送端和接受端会各自维护一个Chunk Size
    
    在实际发送时应对要发送的数据用不同的Chunk Size去尝试,通过抓包分析等手段得出合适的Chunk大小,
    并且在传输过程中可以根据当前的带宽信息和实际信息的大小动态调整Chunk的大小,
    从而尽量提高CPU的利用率并减少信息的阻塞机率
  • 相关阅读:
    Luckysheet如何初始化含合并单元格的数据
    Luckysheet如何一键导入本地Excel
    又发现一款纯js开源电子表格Luckysheet
    Sublime Text3 注册码(Windows/Build 3176版本)| 开发工具
    Python初学者笔记(4)-简单的通讯录
    Python初学者笔记(3):输出列表中的奇数/奇数项,字符串中的偶数项,字符串大小写转换
    安装wampserver出现“The Program can't start because MSVCR110.dll is missing from your computer. Try reinstalling the program to fix this problem”
    python初学者笔记(2):阿拉伯数字转换成中文大写
    Python初学者笔记:打印出斐波那契数列的前10项
    JavaScript弹出对话框的三种方式
  • 原文地址:https://www.cnblogs.com/Good-Life/p/9101741.html
Copyright © 2011-2022 走看看