A. iOS 视频h264 和 h265 硬编码-代码
在iOS开发中,H265编码因其优点被广泛应用。要进行H265硬编码,关键在于判断设备支持性(iPhone 7及以上,iOS 11以上版本)和初始化编码器设置。以下是一些关键编码设置:
编码过程中,对每一帧数据进行处理,例如构造连续的时间戳、设置H264的最大码率(H265暂不支持)以及使用进行编码。编码完成后,涉及截取I帧、提取SPS/PPS等信息并写入文件。
码流数据结构上,H264和H265有不同,H265中vps在流数据的最前面。H264码流由NALU单元构成,包含图像数据和参数信息,如FormatDesc、SPS和PPS。通过CMVideoFormatDescriptionRef、CMBlockBufferRef和时间信息,可以创建CMSampleBuffer用于解码。
B. FFmpeg-视频编码-YUV编码出H264
编码出来的h264数据可以直接使⽤ffplay播放
int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align);
函数的作⽤是通过指定像素格式、图像宽、图像⾼来计算所需的内存⼤⼩
重点说明⼀个参数 align :此参数是设定内存对⻬的对⻬数,也就是按多⼤的字节进⾏内存对⻬:
av_image_alloc()是这样定义的。此函数的功能是按照指定的宽、⾼、像素格式来 分配图像内存 。
int av_image_alloc(uint8_t *pointers[4], int linesizes[4], int w, int h, enum AVPixelFormat pix_fmt, int align);
int av_image_fill_arrays(uint8_t *dst_data[4], int dst_linesize[4], const uint8_t *src, enum AVPixelFormat pix_fmt, int width, int height, int align);
av_image_fill_arrays()函数 ⾃身不具备内存申请的功能 ,此函数类似于格式化已经申请的内存,即通过 av_malloc()函数申请的内存空间,或者av_frame_get_buffer()函数申请的内存空间。
av_image_fill_arrays()中 参数具体说明 :
视频码率是视频数据(包含视频⾊彩量、亮度量、像素量)每秒输出的位数。⼀般⽤的单位是kbps。
在视频会议应用中,视频质量和网络带宽占用是矛盾的,通常情况下视频流占用的带宽越高则视频质量也越高;如要求高质量的视频效果,那么需要的网络带宽也越大;解决这一矛盾的钥匙当然是视频编解码技术。评判一种视频编解码技术的优劣,是比较在相同的带宽条件下,哪个视频质量更好;在相同的视频质量条件下,哪个占用的网络带宽更少。
是不是视频码率越高,质量越好呢?理论上是这样的,然而在我们肉眼分辨的范围内,当码率高到一定程度,感觉没有什么差别。所以码率设置有它的最优值,H.264(也叫AVC或X.264)的文档中,视频的建议码率如下:
鉴于x264的参数众多,各种参数的配合复杂,为了使⽤者⽅便,x264建议如⽆特别需要可使 ⽤preset和tune设置。这套开发者推荐的参数较为合理,可在此基础上在调整⼀些具体参数以符合⾃⼰需要,⼿动设定的参数会覆盖preset和tune⾥的参数。
使⽤ ffmpeg -h encoder=libx264 命令查询相关⽀持的参数
x264是⼀个 H.264/MPEG4 AVC 编码器,本指南将指导新⼿如何创建⾼质量的H.264视频。 对于普通⽤户通常有两种码率控制模式:CRF(Constant Rate Factor)和Two pass ABR。码率控制是⼀种决定为每⼀个视频帧分配多少⽐特数的⽅法,它将决定⽂件的⼤⼩和质量的分配。
如果你在编译和安装libx264 ⽅⾯需要帮助,请查看ffmpeg和x264编译指南: http://ffmpeg.org/trac/ffmpeg/wiki/CompilationGuide
量化⽐例的范围为0~51,其中0为⽆损模式, 23 为缺省值,51可能是最差的。该数字越⼩,图像质量越 好。从主观上讲,18~28是⼀个合理的范围。18往往被认为从视觉上看是⽆损的,它的输出视频质量和输 ⼊视频⼀模⼀样或者说相差⽆⼏。但从技术的⻆度来讲,它依然是有损压缩。
若CRF值加6,输出码率⼤概减少⼀半;若CRF值减6,输出码率翻倍。通常是在保证可接受视频质量的前提下选择⼀个最⼤的CRF值,如果输出视频质量很好,那就尝试⼀个更⼤的值,如果看起来很糟,那就尝 试⼀个⼩⼀点值。
预设是⼀系列参数的集合,这个集合能够在编码速度和压缩率之间做出⼀个权衡。⼀个编码速度稍慢的预 设会提供更⾼的压缩效率(压缩效率是以⽂件⼤⼩来衡量的)。这就是说,假如你想得到⼀个指定⼤⼩的⽂ 件或者采⽤恒定⽐特率编码模式,你可以采⽤⼀个较慢的预设来获得更好的质量。同样的,对于恒定质量编码模式,你可以通过选择⼀个较慢的预设轻松地节省⽐特率。
如果你很有耐⼼,通常的建议是使⽤最慢的预设。⽬前所有的预设按照编码速度降序排列为:
tune是x264中重要性仅次于preset的选项,它是视觉优化的参数,tune可以理解为视频偏好(或者视频类型),tune不是⼀个单⼀的参数,⽽是由⼀组参数构成 -tune 来改变参数设置。当前的 tune包括:
如果你不确定使⽤哪个选项或者说你的输⼊与所有的tune皆不匹配,你可以忽略--tune 选项。 你可以使⽤-tune来查看tune列表,也可以通过x264 --fullhelp来查看tune所采⽤的参数配置。
另外⼀个可选的参数是-profile:v,它可以将你的输出限制到⼀个特定的 H.264 profile。⼀些⾮常⽼的或者 要被淘汰的设备仅⽀持有限的选项,⽐如只⽀持baseline或者main。
所有的profile 包括:
查找指定的编码器
初始化
设置编码器参数
将codec_ctx和codec进行绑定
分配pkt和frame
计算出每一帧的数据 像素格式 * 宽 * 高
读取YUV数据
格式化已经申请的内存,将YUV数据,格式化放入frame中
发送YUV数据进编码器
从编码器中获取encode的packet数据
encode的packet数据写入文件
C. 手写H264编码器
在视频编码领域,H.264作为新一代标准,以其高压缩率和高质量着称。本文将深入探讨视频编码中三种关键帧(I帧、P帧和B帧)的概念及其编码原理。
1. **帧类型解析**
**I帧**:帧内编码帧,表示关键帧,解码时仅需本帧数据,完整保留画面信息。
**P帧**:前向预测编码帧。描述与前一关键帧(或P帧)的差异,解码时需要前一帧的缓存。
**B帧**:双向预测内插编码帧。记录与前后帧的差异,解码时需前后两帧数据。
2. **压缩算法详解**
**帧内压缩**:仅考虑本帧数据,类似于静态图像压缩,适用于独立解码显示。
**帧间压缩**:利用相邻帧之间的冗余信息,通过比较数据差异进行压缩,适用于连续视频的高效编码。
**运动预测编码**:在P帧编码中,通过搜索参考帧中与当前帧块最相似的块,描述差异,显着减少数据量。
3. **手写H264编码器**
实现一个H264编码器需要理解基本图像处理知识、信号时域和频域原理,以及傅立叶变换技术。
**第一步**:有损图像压缩。将RGB图像转换为YUV格式,对Y分量进行8x8块的DCT变换,量化和压缩。
**第二步**:宏块误差计算。定义运动预测编码原理,通过比较宏块差异,生成P帧。
**第三步**:运动预测编码实现。搜索参考帧中与当前帧宏块最相似的位置,记录差异。
**第四步**:P帧编码。将搜索结果进行压缩,生成最终P帧数据。
**第五步**:实现GOP生成。通过I帧和P帧构建视频流,确保连续播放。
**第六步**:容器组装。将编码后的GOP以特定格式保存,如MP4,形成完整视频文件。
通过上述步骤,理解并实现H264编码器的基础原理,为视频压缩和流媒体传输提供了坚实的基础。掌握这些技术不仅能够优化视频质量与存储,还能在实时通信和网络应用中发挥关键作用。
D. 音视频入门——H.264编码(宏块+片+帧)浅析
(1)图像冗余信息:空间冗余、时间冗余
(2)视频编码关键点:压缩比、算法复杂度、还原度
(3)H.264的2大组成部分:视频编码层VCL和网络抽象层面NAL Network Abstract Layer,
(1)宏块 MB macroblock
(2)片 slice
(3)帧 frame
(4)I帧、B帧、P帧
(5)帧率 fps
(6)像素->宏块->片->帧->序列->码流
我们了解了什么是宏快,宏快作为压缩视频的最小的一部分,需要被组织,然后在网络之间做相互传输。
H264更深层次 —》宏块 太浅了
如果单纯的用宏快来发送数据是杂乱无章的,就好像在没有集装箱 出现之前,货物总是随意被堆放到船上。
上货(编码),下货是非常痛苦的。 当集装箱出现之后,一切都发生了改变,传输效率大大增高。
集装箱可以理解成H264编码标准,他制定了相互传输的格式,将宏快 有组织,有结构,有顺序的形成一系列的码流。这种码流既可 通过 InputStream 网络流的数据进行传输,也可以封装成一个文件进行保存
H264: H264/AVC是广泛采用的一种编码方式 。 主要作用是为了传输
组成H264码流的结构中 包含以下几部分 ,从大到小排序依次是
NAL层:(Network Abstraction Layer,视频数据网络抽象层): 它的作用是H264只要在网络上传输,在传输的过程每个包以太网是1500字节,而H264的帧往往会大于1500字节,所以要进行拆包,将一个帧拆成多个包进行传输,所有的拆包或者组包都是通过NAL层去处理的。
VCL层:(Video Coding Layer,视频数据编码层): 对视频原始数据进行压缩
H264是一种码流 类似与一种不见头,也不见尾的一条河流。如何从和流中取到自己想要的数据呢,
在H264的标砖中有这样的一个封装格式叫做"Annex-B"的字节流格式。 它是H264编码的主要字节流格式。
几乎市面上的编码器是以这种格式进行输出的。起始码0x 00 00 00 01 或者 0x 00 00 01 作为分隔符。
两个 0x 00 00 00 01之间的字节数据 是表示一个NAL Unit
切片头:包含了一组片的信息,比如片的数量,顺序等等
H264中,以16x16的宏块为编码最小单元,一个宏块可以被分成多个4x4或8x8的块
同一个宏块内,像素的相似程度会比较高,若16x16的宏块中,像素相差较大,那么就需要继续细分
当然,像素块越小,编码的复杂度也会随之增加,编码效率自然就会降低。但是这样是值得的,因为图像的压缩效率有了显着提高,也就是编码后得到的相同质量的图像,H.264的压缩比更大,占用的空间及带宽更小。
不合理的分块会出现块效应,即块与块之间色差明显
海思在3559之后有deblock的接口可以应对块效应,3519上用的很多
在I帧中,全部宏块都采用帧内预测的方式,所以解码时仅用I帧的数据就可重构完整图像,不须要参考其余画面而生成。web
H.264中规定了两种类型的I帧:普通I帧(normal Iframes)和IDR帧(InstantaneousDecoding Refresh, 即时解码刷新)。 IDR帧实质也是I帧,使用帧内预测。IDR帧的做用是当即刷新,会致使DPB(Decoded Picture Buffer参考帧列表)清空,而I帧不会。因此IDR帧承担了随机访问功能,一个新的IDR帧开始,能够从新算一个新的Gop开始编码,播放器永远能够从一个IDR帧播放,由于在它以后没有任何帧引用以前的帧。若是一个视频中没有IDR帧,这个视频是不能随机访问的。全部位于IDR帧后的B帧和P帧都不能参考IDR帧之前的帧,而普通I帧后的B帧和P帧仍然能够参考I帧以前的其余帧。IDR帧阻断了偏差的积累,而I帧并无阻断偏差的积累。算法
一个GOP序列的第一个图像叫作 IDR 图像(当即刷新图像),IDR 图像都是 I 帧图像,但I帧不必定都是IDR帧,只有GOP序列的第1个I帧是IDR帧。缓存
疑问:按照GOP、IDR帧、I帧的解释,若是一个GOP出现除去第一个IDR帧以外的I帧,是不存在的,那这样的话,就不存在非IDR的I帧了,但是为何还要说明非IDR的I帧呢。svg
解答:H264编码存在多种编码方式CBR、VBR、CVBR、ABR等等,VBR编码模式下图像内容变化差别很大时,会动态调整I帧的数量,所以GOP的概念须要修正:两个IDR帧之间的间隔为一组GOP,一组GOP中能够出现非IDR的I帧。编码
P帧:前向预测编码帧。P帧表示的是这一帧跟以前的一个关键帧(或P帧)的差异,解码时须要用以前缓存的画面叠加上本帧定义的差异,生成最终画面,P帧没有完整画面数据,只有与前一帧的画面差别的数据。P帧的压缩率20code
B帧:双向预测内插编码帧。B帧是双向差异帧,也就是B帧记录的是本帧与先后帧的差异,要解码B帧,不只要取得以前的缓存画面,还要解码以后的画面,经过先后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,约为50,可是解码时CPU会比较累。orm
通常能够输出H264帧的USB摄像头,使用的是BP-Baseline Profile,只有I帧与P帧。视频
而slice呢,也是对宏块的划分
本文简单叙述了;音视频中的H264编码中的,宏块、帧、片。音视频还有更深入的学习,知识范围很广,需要一套很详细的学习资料与路线。我推荐上面的一套入门到精通资料辅佐。