编解码的必要性

1.为什么要压缩

  1. 节省传输带宽;编码可以将数据进行压缩,减少传输资源浪费。
  2. 节省存储空间:当显示器正在播放一个1280*720视频,帧率是25,那么一秒所产生正常的数据大小为:1280*720(位像素)*25(张) / 8(1字节8位)(结果:B) / 1024(结果:KB) / 1024 (结果:MB) = 2.75MB,一般场景没必要这么大资源。

2.可以压缩什么信息

简单来说就是去除冗余信息

  • 空间冗余:图像相邻像素之间有较强的相关性
  • 时间冗余:视频序列的相邻图像之间内容相似
  • 编码冗余:不同像素值出现的概率不同
  • 视觉冗余:人的视觉系统对某些细节不敏感
  • 知识冗余:规律性的结构可由先验知识和背景知识得到

3.压缩类别

无损压缩(Lossless):Winzip

  • 压缩前解压缩后图像完全一致
  • 压缩比低(2:1~3:1)

有损压缩(Lossy):H.264/AVC

  • 压缩前解压缩后图像不一致
  • 压缩比高(10:1~20:1)
  • 利用人的视觉系统的特性

H.264简介

上面我们已知h.264是一种有损压缩,其采⽤了16*16的分块⼤⼩对,对视频帧图像进⾏相似⽐较和压缩编码。

1.序列

一段时间内图像变化不大的图像集我们就可以称之为一个序列。序列可以理解为有相同特点的一段数据。如果某个图像与之前的图像变换很大,很难参考之前的帧来生成新的帧,那么就结束这个序列,开始下一段序列。重复上一序列的做法,生成新的一段序列。

2. 帧类型

H264结构中,一个视频图像编码后的数据叫做一帧,一帧由一个片(slice)或多个片组成,一个片由一个或多个宏块(MB)组成,一个宏块由16x16的yuv数据组成。宏块作为H264编码的基本单位。H264使⽤帧内压缩和帧间压缩的⽅式提⾼编码压缩率,通过I帧、P帧和B帧策略来实现,连续帧之间的压缩。

I帧

帧内编码帧 ,I帧表示关键帧,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面)。

特点

  1. 它是一个全帧压缩编码帧。它将全帧图像信息进行JPEG压缩编码及传输
  2. 解码时仅用I帧的数据就可重构完整图像(无需参考其他帧)
  3. I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量)
  4. I帧是帧组GOP的基础帧(第一帧),在一组中只有一个I帧
  5. I帧所占数据的信息量比较大
  6. 压缩比为1:7(帧内压缩)

P帧

前向预测编码帧。P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画

特点

  1. P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差)
  2. 解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像
  3. P帧属于前向预测的帧间编码。它只参考前面最靠近它的I帧或P帧
  4. 由于P帧是参考帧,它可能造成解码错误的扩散
  5. 由于是差值传送,P帧的压缩比较高,压缩比为1:20

B帧

双向预测内插编码帧。B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别,换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。

特点

  1. B帧是由前面的I或P帧和后面的P帧来进行预测的
  2. B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量
  3. B帧是双向预测编码帧
  4. B帧压缩比最高,因为它只反映丙参考帧间运动主体的变化情况,预测比较准确
  5. B帧不是参考帧,不会造成解码错误的扩散
  6. B帧压缩比例高,1:50,但是CPU比较累

3.GOP(画面组)

GOP即Group of picture(图像组),指两个I帧之间的距离,Reference(参考周期)指两个P帧之间的距离。一个I帧所占用的字节数大于一个P帧,一个P帧所占用的字节数大于一个B帧。所以在码率不变的前提下,GOP值越大,P、B帧的数量会越多,平均每个I、P、B帧所占用的字节数就越多,也就更容易获取较好的图像质量;Reference越大,B帧的数量越多。

GOP结构一般有两个数字,如M=3,N=12。M指定I帧和P帧之间的距离,N指定两个I帧之间的距离。所以M=3,N=12,GOP结构为:IBBPBBPBBPBBI。在一个GOP内I frame解码不依赖任何的其它帧,p frame解码则依赖前面的I frame或P frame,B frame解码依赖前最近的一个I frame或P frame 及其后最近的一个P frame。

值得一提的是业界的一些并行压缩方案是可以基于gop来做压缩的。

4. IDR帧(关键帧)

IDR(Instantaneous Decoding Refresh)即时解码刷新。 在编码解码中为了方便,将GOP中首个I帧要和其他I帧区别开,把第一个I帧叫IDR,这样方便控制编码和解码流程,所以IDR帧一定是I帧,但I帧不一定是IDR帧;IDR帧的作用是立刻刷新,使错误不致传播,从IDR帧开始算新的序列开始编码。I帧有被跨帧参考的可能,IDR不会。

IDR的存在是为了解码的重同步,当解码器解码到 IDR 图像时,⽴即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始⼀个新的序列。这样,如果前⼀个序列出现重⼤错误,在这⾥可以获得重新同步的机会。IDR图像之后的图像永远不会使⽤IDR之前的图像的数据来解码。

H264压缩方式

H264采用的核心算法是帧内压缩和帧间压缩,帧内压缩是生成I帧的算法,帧间压缩是生成B帧和P帧的算法。

帧内(Intraframe)压缩也称为空间压缩(Spatialcompression)。当压缩一帧图像时,仅考虑本帧的数据而不考虑相邻帧之间的冗余信息,这实际上与静态图像压缩类似。帧内一般采用有损压缩算法,由于帧内压缩是编码一个完整的图像,所以可以独立的解码、显示。

帧间(Interframe)压缩的原理是:相邻几帧的数据有很大的相关性,或者说前后两帧信息变化很小的特点。也即连续的视频其相邻帧之间具有冗余信息,根据这一特性,压缩相邻帧之间的冗余量就可以进一步提高压缩量,减小压缩比。帧间压缩也称为时间压缩(Temporalcompression),它通过比较时间轴上不同帧之间的数据进行压缩。帧间压缩一般是无损的。帧差值(Framedifferencing)算法是一种典型的时间压缩法,它通过比较本帧与相邻帧之间的差异,仅记录本帧与其相邻帧的差值,这样可以大大减少数据量。

压缩方式说明

  1. 分组,也就是将一系列变换不大的图像归为一个组,也就是一个序列,也可以叫GOP(画面组);
  2. 定义帧,将每组的图像帧归分为I帧、P帧和B帧三种类型;
  3. 预测帧, 以I帧做为基础帧,以I帧预测P帧,再由I帧和P帧预测B帧;
  4. 数据传输, 最后将I帧数据与预测的差值信息进行存储和传输。

H264码流结构

H264码流是由一个个的NAL单元组成,其中SPS、PPS、IDR和SLICE是NAL单元某一类型的数据。

H.264原始码流(又称为“裸流”)是由一个一个的NALU组成的。其中每个NALU之间通过startcode(起始码)进行分隔,起始码分成两种:0x000001(3Byte)或者0x00000001(4Byte)。如果NALU对应的Slice为一帧的开始就用0x00000001,否则就用0x000001。
H.264码流解析的步骤就是首先从码流中搜索0x000001和0x00000001,分离出NALU;然后再分析NALU的各个字段。本文的程序即实现了上述的两个步骤。参考自视音频数据处理入门:H.264视频码流解析

#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef enum {NALU_TYPE_SLICE    = 1,NALU_TYPE_DPA      = 2,NALU_TYPE_DPB      = 3,NALU_TYPE_DPC      = 4,NALU_TYPE_IDR      = 5,NALU_TYPE_SEI      = 6,NALU_TYPE_SPS      = 7,NALU_TYPE_PPS      = 8,NALU_TYPE_AUD      = 9,NALU_TYPE_EOSEQ    = 10,NALU_TYPE_EOSTREAM = 11,NALU_TYPE_FILL     = 12,
} NaluType;typedef enum {NALU_PRIORITY_DISPOSABLE = 0,NALU_PRIRITY_LOW         = 1,NALU_PRIORITY_HIGH       = 2,NALU_PRIORITY_HIGHEST    = 3
} NaluPriority;typedef struct
{int startcodeprefix_len;      //! 4 for parameter sets and first slice in picture, 3 for everything else (suggested)unsigned len;                 //! Length of the NAL unit (Excluding the start code, which does not belong to the NALU)unsigned max_size;            //! Nal Unit Buffer sizeint forbidden_bit;            //! should be always FALSEint nal_reference_idc;        //! NALU_PRIORITY_xxxxint nal_unit_type;            //! NALU_TYPE_xxxx    char *buf;                    //! contains the first byte followed by the EBSP
} NALU_t;FILE *h264bitstream = NULL;                //!< the bit stream fileint info2=0, info3=0;static int FindStartCode2 (unsigned char *Buf){if(Buf[0]!=0 || Buf[1]!=0 || Buf[2] !=1) return 0; //0x000001?else return 1;
}static int FindStartCode3 (unsigned char *Buf){if(Buf[0]!=0 || Buf[1]!=0 || Buf[2] !=0 || Buf[3] !=1) return 0;//0x00000001?else return 1;
}int GetAnnexbNALU (NALU_t *nalu){int pos = 0;int StartCodeFound, rewind;unsigned char *Buf;if ((Buf = (unsigned char*)calloc (nalu->max_size , sizeof(char))) == NULL) printf ("GetAnnexbNALU: Could not allocate Buf memory\n");nalu->startcodeprefix_len=3;if (3 != fread (Buf, 1, 3, h264bitstream)){free(Buf);return 0;}info2 = FindStartCode2 (Buf);if(info2 != 1) {if(1 != fread(Buf+3, 1, 1, h264bitstream)){free(Buf);return 0;}info3 = FindStartCode3 (Buf);if (info3 != 1){ free(Buf);return -1;}else {pos = 4;nalu->startcodeprefix_len = 4;}}else{nalu->startcodeprefix_len = 3;pos = 3;}StartCodeFound = 0;info2 = 0;info3 = 0;while (!StartCodeFound){if (feof (h264bitstream)){nalu->len = (pos-1)-nalu->startcodeprefix_len;memcpy (nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);     nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bitnalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bitnalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bitfree(Buf);return pos-1;}Buf[pos++] = fgetc (h264bitstream);info3 = FindStartCode3(&Buf[pos-4]);if(info3 != 1)info2 = FindStartCode2(&Buf[pos-3]);StartCodeFound = (info2 == 1 || info3 == 1);}// Here, we have found another start code (and read length of startcode bytes more than we should// have.  Hence, go back in the filerewind = (info3 == 1)? -4 : -3;if (0 != fseek (h264bitstream, rewind, SEEK_CUR)){free(Buf);printf("GetAnnexbNALU: Cannot fseek in the bit stream file");}// Here the Start code, the complete NALU, and the next start code is in the Buf.  // The size of Buf is pos, pos+rewind are the number of bytes excluding the next// start code, and (pos+rewind)-startcodeprefix_len is the size of the NALU excluding the start codenalu->len = (pos+rewind)-nalu->startcodeprefix_len;memcpy (nalu->buf, &Buf[nalu->startcodeprefix_len], nalu->len);//nalu->forbidden_bit = nalu->buf[0] & 0x80; //1 bitnalu->nal_reference_idc = nalu->buf[0] & 0x60; // 2 bitnalu->nal_unit_type = (nalu->buf[0]) & 0x1f;// 5 bitfree(Buf);return (pos+rewind);
}/*** Analysis H.264 Bitstream* @param url    Location of input H.264 bitstream file.*/
int simplest_h264_parser(char *url){NALU_t *n;int buffersize=100000;//FILE *myout=fopen("output_log.txt","wb+");FILE *myout=stdout;h264bitstream=fopen(url, "rb+");if (h264bitstream==NULL){printf("Open file error\n");return 0;}n = (NALU_t*)calloc (1, sizeof (NALU_t));if (n == NULL){printf("Alloc NALU Error\n");return 0;}n->max_size=buffersize;n->buf = (char*)calloc (buffersize, sizeof (char));if (n->buf == NULL){free (n);printf ("AllocNALU: n->buf");return 0;}int data_offset=0;int nal_num=0;printf("-----+-------- NALU Table ------+---------+\n");printf(" NUM |    POS  |    IDC |  TYPE |   LEN   |\n");printf("-----+---------+--------+-------+---------+\n");while(!feof(h264bitstream)) {int data_lenth;data_lenth=GetAnnexbNALU(n);char type_str[20]={0};switch(n->nal_unit_type){case NALU_TYPE_SLICE:sprintf(type_str,"SLICE");break;case NALU_TYPE_DPA:sprintf(type_str,"DPA");break;case NALU_TYPE_DPB:sprintf(type_str,"DPB");break;case NALU_TYPE_DPC:sprintf(type_str,"DPC");break;case NALU_TYPE_IDR:sprintf(type_str,"IDR");break;case NALU_TYPE_SEI:sprintf(type_str,"SEI");break;case NALU_TYPE_SPS:sprintf(type_str,"SPS");break;case NALU_TYPE_PPS:sprintf(type_str,"PPS");break;case NALU_TYPE_AUD:sprintf(type_str,"AUD");break;case NALU_TYPE_EOSEQ:sprintf(type_str,"EOSEQ");break;case NALU_TYPE_EOSTREAM:sprintf(type_str,"EOSTREAM");break;case NALU_TYPE_FILL:sprintf(type_str,"FILL");break;}char idc_str[20]={0};switch(n->nal_reference_idc>>5){case NALU_PRIORITY_DISPOSABLE:sprintf(idc_str,"DISPOS");break;case NALU_PRIRITY_LOW:sprintf(idc_str,"LOW");break;case NALU_PRIORITY_HIGH:sprintf(idc_str,"HIGH");break;case NALU_PRIORITY_HIGHEST:sprintf(idc_str,"HIGHEST");break;}fprintf(myout,"%5d| %8d| %7s| %6s| %8d|\n",nal_num,data_offset,idc_str,type_str,n->len);data_offset=data_offset+data_lenth;nal_num++;}//Freeif (n){if (n->buf){free(n->buf);n->buf=NULL;}free (n);}return 0;
}

视频编解码之H.264相关推荐

  1. 视频编解码(h.264)的一些资源

    http://www.fastvdo.com/spie04/      H.264/AVC综述文章,包含了新的高精度拓展(Sullivan, Topiwala, and Luthra)  http:/ ...

  2. 编解码标准-H.264

    H.264是MPEG-4家族中的一员,即MPEG-4系列文档ISO-14496的第10部分,因此被称作MPEG-4 AVC,MPEG-4重点考虑灵活性和交互性,而H.264着重强调更高的编码压缩率和传 ...

  3. 【SVAC】国家视频编解码标准SVAC的特色和优势

    ###Date: 2018.5.27 ============================================================= 在SVAC1.0视频编解码标准中,有几 ...

  4. H.264/AVC视频编解码技术详解-殷汶杰-专题视频课程

    H.264/AVC视频编解码技术详解-46880人已学习 课程介绍         H.264/AVC是目前业界应用为广泛的视频压缩编码标准,包含了先进而且较为成熟的视频编码技术.本课程将从原理.标准 ...

  5. 视频教程-H.264/AVC视频编解码技术详解-其他

    H.264/AVC视频编解码技术详解 毕业于上海大学通信与信息工程学院,研究生学历,硕士学位.研究方向为视频处理与传输,对H.264/AVC.H.265/HEVC.AVS.AVS+.AVS2等视频编解 ...

  6. 音视频编解码技术之视频编码基本概念介绍

    视频压缩名字解释: 1.有损和无损压缩:在视频压缩中有损(Lossy )和无损(Lossless)的概念与静态图像中基本类似.无损压缩也即压缩前和解压缩后的数据完全一致.有损压缩意味着解压缩后的数据与 ...

  7. 新一代国际视频编解码标准正式出炉,腾讯超100项提案获标准采纳

    近日,新一代国际视频编解码标准(H.266/VVC)正式出炉.在此次标准制定过程中,腾讯有超过100项技术提案获得标准采纳,为国际视频压缩标准研究制定做出很多贡献. 据了解,H.266/VVC是由IS ...

  8. 【H.264/AVC视频编解码技术详解】十九:熵编码算法(5)——H.264的CABAC(上):语法元素的二值化方法...

    <H.264/AVC视频编解码技术详解>视频教程已经在"CSDN学院"上线,视频中详述了H.264的背景.标准协议和实现,并通过一个实战工程的形式对H.264的标准进行 ...

  9. 【H.264/AVC视频编解码技术具体解释】十三、熵编码算法(4):H.264使用CAVLC解析宏块的残差数据...

    <H.264/AVC视频编解码技术具体解释>视频教程已经在"CSDN学院"上线,视频中详述了H.264的背景.标准协议和实现,并通过一个实战project的形式对H.2 ...

  10. H.264/AVC视频编解码技术详解 第一章 视频信息与压缩编码

    H.264/AVC视频编解码技术详解系列笔记 是对 H.264/AVC视频编解码技术详解 课程的学习 文章目录 人与世界的交互 视频信号的表示方法 视频压缩编码 视频信息为什么可以被压缩? 视频压缩编 ...

最新文章

  1. Redis 6.0 新特性-多线程连环13问!
  2. 2020滑铁卢大学计算机科学学费,加拿大大学国际生学费上涨 滑铁卢大学学费上涨62%...
  3. Luogu 4721 【模板】分治 FFT
  4. Orleans解决并发之痛(四):Streams
  5. GC内存可视化器教程–第一部分
  6. LeetCode 37 解数独
  7. Filebeat 采集多个文件到es
  8. Vue.js 循环语句
  9. 方舟手游服务器能修改密码吗,明日方舟怎么改密码_明日方舟改密码方法详细解析一览[多图]...
  10. cmd输入pip报错_安装虚拟环境+pip安装XXX包的常见操作与报错解决
  11. Ubuntu-10.04中设置和修改root密码
  12. 仿金蝶进销存源码(含数据库脚本)
  13. 【Java -- 设计模式】UML 统一建模语言
  14. DockOne微信分享( 八十八):PPTV聚力传媒的Docker与DevOps
  15. Spring Data JPA + QueryDSL
  16. Power BI_柱状图中间空一列_横坐标显示
  17. 9月第2周业务风控关注 |国家计算机病毒应急处理中心:这十款App存在危险行为代码
  18. java17+javaFX17+openCV4.5.5 实现远程桌面功能 最全完整版
  19. 马云称自己的成就无关科技与钱;任正非:外籍员工可当华为 CEO,但有条件;雅虎宣布逐步关闭雅虎群组网站 | EA周报...
  20. linux的DNS服务器

热门文章

  1. Solid angle to Arnold for Cinema4D破解教程
  2. 莫兰迪紫rgb_莫兰迪rgb参数_译述北京 | RGB的前世今生
  3. 两化融合管理体系评定申请表概况
  4. Android ImageView实现反色显示的方法
  5. 啊哈C语言4.9练习
  6. 64行代码实现简单人脸识别
  7. vscode编译器添加c++万能头文件
  8. flexray VPX控制板设计方案详细
  9. word论文公式编号排版
  10. 网易云解析接口PHP源码,网易云音乐直链解析API源代码^-^