当前位置: 首页 > news >正文

音视频及H264/H256编码相关原理

一、音视频封装格式原理:

          我们播放的视频文件一般都是用一种封装格式封装起来的,封装格式的作用是什么呢?一般视频文件里不光有视频,还有音频,封装格式的作用就是把视频和音频打包起来。 所以我们先要解封装格式,看有哪些视频流和哪些音频流,此时的音频流和视频流都还是压缩数据,不能直接用于显示的,这就需要解码。

        

        如FFmpeg 视频文件就是一个容器 (视频流(H264) 音频流(aac))。

      1、视频文件封装格式:

          封装格式(也叫容器),就是将已经编码压缩好的视频轨和音频轨按照一定的格式放到一个文件中,也就是说仅仅是一个外壳,或者大家把它当成一个放视频轨和音频轨的文件夹也可以。

      2、音视频编码方式:

  • 视频编码方式:将视频像素数据(RGB,YUV 等)压缩成视频码流,从而降低视频的数据量。包含有HEVC(H265)、H264、MPEG4、MPEG2、VP9等;
  • 音频编码方式:将音频采样数据(PCM 等)压缩成音频码流,从而降低音频的数据量。包含有AAC、MP3、WMV、AC-3。

       3、编解码方式和封装格式的关系:

                「视频封装格式」= 视频 + 音频 +视频编解码方式 等信息的容器。

       4、RGB/YUV概念:

        通常我们采用RGB模型来表示颜色,RGB模型中,每种颜色需要3个数字分别表示R、G、B,每个数字占用1个bit字节,这样总共需要24bits

        YUV能更高效颜色模型用更少的bit来表示颜色,Y——表示亮度,也就是灰阶值,U和V表示色度分量。

  •  YCbCr颜色模型基本原理:

        假设我们定义一个 「亮度(Luminance)」 的概念来表示颜色的亮度,那它就可以用含 R、G、B 的表达式表示为:

    Y = kr*R + kg*G + kb*B

        Y 即「亮度」,kr、kg、kb 即 R、G、B 的权重值。

        可以定义一个 「色度(Chrominance)」 的概念来表示颜色的差异

    Cr = R – YCg = G – YCb = B – Y

        Cr、Cg、Cb 分别表示在 R、G、B 上的色度分量.。

  • YUV:关键是在于它的亮度信号 Y 和色度信号 U、V 是分离的,那就是说即使只有 Y 信号分量而没有 U、V 分量,我们仍然可以表示出图像,只不过图像是黑白灰度图像。在YCbCr 中 Y 是指亮度分量,Cb 指蓝色色度分量,而 Cr 指红色色度分量。
  • YCbCr 与 RGB 相互转换的公式:
    Y = 0.299R + 0.587G + 0.114BCb = 0.564(B - Y)Cr = 0.713(R - Y)R = Y + 1.402CrG = Y - 0.344Cb - 0.714CrB = Y + 1.772Cb

        

二、H264编码框架:

         视频编码方式就是指通过特定的压缩技术,将某个视频格式的文件转换成另一种视频格式的文件的方式。H.264和H265编码是目前视频格式中用得最广泛的编码方式,H.264创造了多参考帧、多块类型、整数变换、帧内预测等新的压缩技术,使用了更精细的分像素运动矢量(1/4、1/8)和新一代的环路滤波器,使得压缩性能大大提高,系统更加完善。H.265是ITUTVCEG继H.264之后所制定的新的视频编码标准。H.265标准围绕着现有的视频编码标准H.264,保留原来的某些技术,同时对一些相关技术加以改进。H.265旨在在有限的带宽下传输更高质量的网络视频,仅需要原先的一半带宽即可播放相同质量的视频。

        1、H264码流文件分层:

  • VCL(Video Coding Layer,视频编码层):负责高效的视频内容表示,VCL数据即编码处理的输出,它表示被压缩编码后的视频数据序列。
  • NAL(Network AbstractionLayer,网络提取层):负责以网络所要求的恰当的方式对数据进行打包和传送,是传输层。不管是在本地播放还是在网络上播放,都要通过这一层来传输。

        2、H264编码原理:

  •  H.264/AVC并未明确表述一个编解码器如何实现,而是规定了一个编码的视频比特流的句法和该比特流的解码方法,因此在实现上有较大的灵活性。H264和以前的H261、H.263、MPEG-1、MPEG-4 等的编解码器功能模块的组成类似,不同的部分是其内部各功能模块的细节部分,H.264编解码器的功能组成如下:

        

  •  H.264/AVC 编解码器的工作原理。H.264编码器采用变换和预测混合编码方式。编码时,首先输入的帧或场Fn以宏块为单位被编码器处理。宏块有帧内和帧间两种模式。帧内模式使用当前帧内已编码的宏块进行预测。帧间模式使用以往一个或多个帧作为参考进行运动预测。然后,对预测值和原始值的差值进行变换、量化、重新排序和编码,对量化系统X进行逆量化、逆变换后,与预测系统相加,得到未经滤波的uF*帧,对uF*帧进行块间滤波,得到当前重构帧 Fn*。而解码过程相对比较简单,对于编码器的各部分进行逆向操作,结果经逆量化、逆变换后通过滤波器得到重构输出图像。H.264编解码器工作原理如图:

        

         3、H264码流分析:

        H264码流的结构中包含 :H264视频序列——图像——片组——片——NALU——宏块 ——像素。从大到小排序               

  • H264编码格式:在 VCL数据传输或存储之前,这些编码的VCL数据先被映射或封装进NAL单元中。每个NAL单元包括一个原始字节序列负载(RBSP,RawByteSequencePayload)和一组对应于视频编码的 NAL 头信息。RBSP的基本结构:在原始编码数据的后面添加了结尾标记,一个比特“1”和若干比特“0”,以便字节对齐。H.264码流NAL单元序列如图        
  •  NAL Header:NAL头由一个字节组成,禁止位(1位)、重要性指示位(2位)、NALU类型(5位)。         

        

  •  RBSP:包括一系列的NAL单元,每个NAL单元包含一个RBSP。典型的RBSP单元序列。每个单元都按独立的NAL单元传送。NAL单元的信息头(1字节)定义了RBSP单元的类型,NAL单元的其余部分为RBSP数据。        

     

  • SODB ,String Of Data Bits 原始数据比特流:因为它是流的形式,所以长度不一定是8倍数,它是由 VLC 层产生的。由于我们计算机是以8倍数去处理数据所以计算机在处理H264时,就需要 RBSP。
  • RBSP,SODB + tailing bits (原始字节序列载荷):由于它是一个压缩流,SODB 不知道是在何处结束,所以算法在SODB最后一位补一个1,没有按字节对齐的则补 0。
  • EBSP (扩展字节序列载荷):在生成压缩流之后,在每一帧的开头加一个起始位,这个起始位一般是 00 00 00 01 或者是 00 00 01。所以在h264码流中规定每有两个连续的00 00,就增加一个0x03。
  • EBSP 和 RBSP的区别:NALU的组成部分为(NALU = NALU Header + RBSP),严格来说NALU的组成部分为(NALU = NALU Header + EBSP);
  •  NALU单元中的参数集:SPS(序列参数集)作用于一系列连续的编码图像;PSS(图像参数集)作用于编码视频序列中一个或多个独立的图像。参数集是一个独立的数据单位,不依赖于参数集外的其他句法元素。一个参数集不对应某个特定的图像或序列,同一序列参数集可以被一个或者多个图像参数集引用。同理,同一个图像参数集也可以被一个或者多个图像引用只在编码器认为需要更新参数集的内容时,才会发出新的参数集。         
  •  NALU中的视频帧:生成的H264视频帧是由多个切片组成的。一个H264的帧至少由一个切片组成,不能没有切片,可以是一个到多个不能没有。在网络传输的时候一个H264帧可能需要切开去传,一个一次传不完,这就按照切片来切。每一个切片组成一个NAL Unit。
  • 切片与宏块的关系:在切片数据中,包含若干个宏块。在一个宏块中,又包含了宏块类型、宏块预测、残差数据。

        4、H264码流结构图:        

         5、H264码流NAL单元解码流程:

        首先从NAL单元中提取出RBSP语法结构,然后按照下图所示的流程处理RBSP语法结构。输入的是NAL单元,输出结果是经过解码的当前图像的样值点。 NAL单元中分别包含了序列参数集和图像参数集。图像参数集和序列参数集在其他NAL单元传输过程中作为参考使用,在这些数据NAL单元的片头中,通过语法元素pic_parameter_set_id设置它们所使用的图像参数集编号;而相应的每个图像参数集中,通过语法元素seq_paramter_set_id设置他们使用的序列参数集编号。        

         6、H264解码详解:

         H264是新一代的编码标准,以高压缩高质量和支持多种网络的流媒体传输著称,在编码方面,我理解的他的理论依据是:参照一段时间内图像的统计结果表明,在相邻几幅图像画面中,一般有差别的像素只有10%以内的点,亮度差值变化不超过2%,而色度差值的变化只有1%以内。所以对于一段变化不大图像画面,我们可以先编码出一个完整的图像帧A,随后的B帧就不编码全部图像,只写入与A帧的差别,这样B帧的大小就只有完整帧的1/10或更小!B帧之后的C帧如果变化不大,我们可以继续以参考B的方式编码C帧,这样循环下去。这段图像我们称为一个序列(序列就是有相同特点的一段数据),当某个图像与之前的图像变化很大,无法参考前面的帧来生成,那我们就结束上一个序列,开始下一段序列,也就是对这个图像生成一个完整帧A1,随后的图像就参考A1生成,只写入与A1的差别内容。

  • GOP:在H264中图像以序列为单位进行组织,一个序列是一段图像编码后的数据流,以I帧开始,到下一个I帧结束。 

  • GOP序列说明:在 H.264协议里定义了3种帧,完整编码的帧叫I帧,参考之前的I帧生成的只对差异部分进行编码的帧叫P帧,还有一种参考前后的帧进行编码的帧叫B帧。在H264中图像以序列为单位进行组织,一个序列是一段图像编码后的数据流,以帧开始,到下一个I帧结束,中间部分也被称为一个GOP。一个序列的第一个图像叫作IDR图像(立即刷新图像),IDR图像都是I帧图像。H.264引入IDR图像是为了解码的重新同步,当解码器解码到IDR图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找下一个参数集,开始解码一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。一个序列就是一段内容差异不太大的图像编码后生成的一串数据流。当运动变化比较少时,一个序列可以很长,因为运动变化少就代表图像画面的内容变动很小,所以就可以是一个Ⅰ帧,然后一直是P帧、B帧。当运动变化多时,一个序列可能会比较短,比如只包含一个I和几个P、B帧。
  •  I帧:指帧内编码帧,I帧表示关键帧,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面)。特点如下:
    1. 它是一个全帧压缩编码帧。它将全帧图像信息进行JPEG压缩编码及传输;
    2. 解码时仅用I帧的数据就可以重构完整图像;
    3. I帧描述了图像背景和运动主体的详情;
    4. I帧不需要参考其他画面生成;
    5. I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各的质量);
    6. I帧是帧组GOP的基础帧(第1帧),在一组中只有一个I帧;
    7. I帧不需要考虑运动矢量;
    8. I帧所占数据的信息量比较大。
  • P帧的预测与重构:P帧是以I帧为参考帧,在I帧中找出P帧“某点”的预测值和运动矢量,取预测差值和运动矢量一起传送。在接收端根据运动矢量从I帧中找出P帧“某点”的预测值并与差值相加以得到P帧“某点”样值,从而可得到完整的P帧。 P帧特点如下::
    1. P帧是I帧后面相隔1~2帧的编码帧;
    2. P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差);
    3. 解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像;
    4. P帧属于前向预测的帧间编码。它只参考前面最靠近它的I帧或P帧;
    5. P帧可以是其后面P帧的参考帧,也可以是其前后的B帧的参考帧;
    6. 由于P帧是参考帧,它可能造成解码错误的扩散; 7.由于是差值传送,P帧的压缩比较高。
  • B帧:双向预测内插编码帧。B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别(具体比较复杂,有4种情况,但我这样说简单些),换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累。

 

 

 

 

相关文章:

音视频及H264/H256编码相关原理

一、音视频封装格式原理: 我们播放的视频文件一般都是用一种封装格式封装起来的,封装格式的作用是什么呢?一般视频文件里不光有视频,还有音频,封装格式的作用就是把视频和音频打包起来。 所以我们先要解封装格式&#…...

查看cpu进程数

import multiprocessing from multiprocessing import Pool# 导入 Pool 允许你创建一个进程池 # 进程池是一组工作进程,它们可以并行地执行多个任务# multiprocessing.cpu_count(): 返回当前机器上的CPU核心数 sum_cpu multiprocessing.cpu_count()use_cpu max(1,…...

MySQL优化篇

文章目录 库表结构优化1.规范和反规范化2.数据类型选择3.主键类型选择 索引优化聚簇索引和辅助索引(一切的起源)复合索引 查询优化 库表结构优化 1.规范和反规范化 表设计之间性能和数据完整性,耦合和解耦合之间的取舍。 进而考虑是要冗余…...

Python3 笔记:部分专有名词解释

1、python 英 /ˈpaɪθən/ 这个词在英文中的意思是蟒蛇。但据说Python的创始人Guido van Rossum(吉多范罗苏姆)选择Python这个名字的原因与蟒蛇毫无关系,只是因为他是“蒙提派森飞行马戏团(Monty Python's Flying Ci…...

javaAPI文档中文版(JDK11在线版)java帮助文档,掌握文档java学习事半功倍。

🌠个人主页 : 赶路人- - 🌌个人格言 : 要努力成为梧桐,让喜鹊在这里栖息。 要努力成为大海,让百川在这里聚积。 11.by,prep.凭,靠,沿 [baɪ] 12.press,v.按,压 [prɛs] 菜鸟教程javaAPI文档中文…...

移动端适配:vw适配方案

vw (Viewport Width) 是一种长度单位,代表视口宽度的百分比。1vw 等于视口宽度的1%。在网页设计和前端开发中,vw 单位常用于实现响应式设计和屏幕适配,尤其是针对不同尺寸和分辨率的移动设备。 为什么使用vw适配? 响应式: 使用v…...

实战Java虚拟机-实战篇

一、内存调优 1.内存溢出和内存泄漏 内存泄漏(memory leak):在Java中如果不再使用一个对象,但是该对象依然在GC ROOT的引用链上,这个对象就不会被垃圾回收器回收,这种情况就称之为内存泄漏。内存泄漏绝大…...

力扣:349. 两个数组的交集

349. 两个数组的交集 给定两个数组 nums1 和 nums2 ,返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。 示例 1: 输入:nums1 [1,2,2,1], nums2 [2,2] 输出:[2]示例 2: …...

深度学习之基于Matlab的BP神经网络交通标志识别

欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景与意义 随着智能交通系统(ITS)的快速发展,交通标志识别&#xff0…...

Linux备份服务及rsync企业备份架构(应用场景)

备份服务概述 备份服务:需要使用到脚本,打包备份,定时任务. 备份服务:rsyncd服务,不同主机之间数据传输. 特点: rsync是个服务也是命令使用方便,具有多种模式传输数据的时候是增量传输 增量与全量: 全量 :无论多少数据全部推…...

用手机打印需要下载什么软件

在快节奏的现代生活中,打印需求无处不在,无论是工作文件、学习资料还是生活小贴士,都可能需要一纸呈现。然而,传统的打印方式往往受限于时间和地点,让人倍感不便。今天,就为大家推荐一款便捷又省钱的手机打…...

Storm在Java中的应用

Storm在Java中的应用主要体现在构建分布式实时计算系统,用于处理大数据流。以下是一些Storm在Java中的具体应用场景和步骤: 实时数据处理:Storm可以实时地接收、处理和传输数据。对于需要快速响应的应用场景,如在线广告、金融交易…...

Java 面试题日常练习

### 基础知识 1. **什么是 JVM?解释其架构。** - JVM(Java Virtual Machine)是 Java 程序的运行时环境。其架构包括类加载器子系统、运行时数据区(堆、栈、本地方法栈、PC 寄存器、方法区)、执行引擎和本地方法接口…...

卷爆短剧出海:五大关键,由AIGC重构

短剧高温下,谈谈AIGC的助攻路线。 短剧,一个席卷全球的高温赛道。 以往只是踏着霸总题材,如今,内容循着精品化、IP化的自然发展风向,给内容、制作、平台等产业全链都带来新机,也让短剧消费走向文化深处&am…...

LLM实战:当网页爬虫集成gpt3.5

1. 背景 最近本qiang~关注了一个开源项目Scrapegraph-ai,是关于网页爬虫结合LLM的项目,所以想一探究竟,毕竟当下及未来,LLM终将替代以往的方方面面。 这篇文章主要介绍下该项目,并基于此项目实现一个demo页面&#x…...

Flutter底部导航栏和顶部Tab切换完整代码

题记 —— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天。 目前市场上绝大部分App的布局结构基本统一:底部导航顶部导航,底部导航页里嵌套顶部导航栏,顶部导航页里嵌套图文…...

Jupyter 使用手册: 探索交互式计算的无限可能

什么是 Jupyter? Jupyter 是一个开源的 Web 应用程序,可用于创建和共享包含实时代码、可视化和叙述性文本的文档。它最初是作为 IPython 项目的一部分开发的,后来发展成为支持多种编程语言的交互式计算环境。 应用场景 作为一个开源的交互式计算环境,Jupyter 在以下几个领域…...

IP地址显示“不安全”怎么办|已解决

解决IP地址显示“不安全”的问题,通常需要确保网站或服务使用HTTPS协议进行加密通信,可以通过部署SSL证书来解决,以下是具体的解决步骤: 1 申请IP地址SSL证书:网站管理员应向证书颁发机构(CA)申…...

国内安全实用的图纸透明加密软件厂家,靠谱的透明加密软件供应商--安秉信息

设计类图纸安全已经成为企业需要注意的问题,在当前互联网设计行业、汽车制造设计、机械制造行业等相关企业都需要对企业内部图纸的保护需求,现在在互联网中,企业数据泄露的事情已经层出不穷,企业对核心图纸的数据安全工作需要重点…...

【kubernetes】探索k8s集群中kubectl的陈述式资源管理

目录 一、k8s集群资源管理方式分类 1.1陈述式资源管理方式:增删查比较方便,但是改非常不方便 1.2声明式资源管理方式:yaml文件管理 二、陈述式资源管理方法 2.1查看版本信息 2.2查看资源对象简写 2.3配置kubectl自动补全 2.4node节点…...

VUE 创建组件常见的几种方式

在 Vue.js 中,组件的创建和使用通常遵循以下三种方法: 1. 全局组件 全局组件是通过 Vue.component() 方法创建的,注册后的组件可以在任何新创建的 Vue 实例(包括根实例)的模板中使用。 Vue.component(my-component,…...

华为OBS命令行简单使用

华为OBS(Object Storage Service)是一种云存储服务,提供了高可靠、高性能、安全的数据存储能力。通过使用OBS的命令行工具obsutil,用户可以方便地进行文件上传、下载、删除等操作,而无需依赖图形界面。下面&#xff0c…...

避免超卖!深入解析高并发分布式锁架构

1.引入并发控制的必要性 并发控制是一切分布式系统设计的基石,确保数据一致性、系统稳定性和最终的用户体验。要理解为什么需要并发控制,就必须先探讨并发对系统可能造成的问题。 1.1. 理解并发问题 多线程和分布式环境中,无数的进程和线程…...

latent diffusion 原理+代码

latent diffusion - Github 以下代码来自 作者: 李宝璐 链接: https://libaolu312.github.io/2023/11/27/Latent-Diffusion-Models-原理和代码/ 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处&…...

Unity开发——好用的数值概率公式

1、血量、伤害两个因素作用,击杀目标 正常状态下:hp - attackValue; 特殊状态下:attackValue *2; //伤害翻倍 如飞机/坦克大战中,击杀对方;受到伤害时,装备道具磨损失效; public int…...

微信小程序的自定义组件

一、创建自定义组件 (1)定义: 把页面重复的代码部分封装成为一个自定义组件,以便在不同的页面中重复使用,有助于代码的维护。 (2)组成: 自定义组件的组成:json文件&a…...

【算法刷题day57】Leetcode:739. 每日温度、496.下一个更大元素 I

文章目录 Leetcode 739. 每日温度解题思路代码总结 Leetcode 496.下一个更大元素 I解题思路代码总结 草稿图网站 java的Deque Leetcode 739. 每日温度 题目:739. 每日温度 解析:代码随想录解析 解题思路 维护一个单调栈,当新元素大于栈顶&a…...

【EXCEL_VBA_实战】两组数据比对是否一致(字符串数组)

工作背景:比对两组数据是否一致(位置非一一对应) 思路构建:两组数据转换为两组字符串数组,比对所包含元素是否相同 问题点:A数组的第一个元素不一定与B数组的第一个元素对应,此时无法通过公式…...

寻找峰值 ---- 二分查找

题目链接 题目: 分析: 因为题目中要找的是任意一个峰值即可, 所以和<山脉数组的峰值索引>这道题差不多因为峰值左右都小于峰值, 所以具有"二段性", 可以使用二分查找算法如果nums[mid] < nums[mid 1], mid一定不是峰值, 所以left mid 1如果nums[mid] &…...

C语言--输入一个整数代表秒数,将这个数转化为对应的小时数、分钟数、和秒数

#include <stdio.h>int main() {int h,m,s;scanf("%d",&s);ms/60;//计算分钟数ss%60;//剩余的秒数hm/60;//计算小时数mm%60;//剩余的分钟数printf("%d %d %d\n",h,m,s); } //先将分钟数求出&#xff0c;再将多出的秒求出作为最后的打印的s //再用…...