H.264笔记之一

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

H.264标准写得比较繁复,所以考虑在浏览完Whitepaper之后就开始研读X264代码。X264代码风格还是比较清晰简洁的。

根据对标准的理解,Picture Order Count在Slice解码的一开始就被提及:

I0 B1 B2 P3 B4 B5 P6
I0 P3 B1 B2 P6 B4 B5

于是I0的POC是0,P3的POC是3,B1是1……

为了支持H264复杂的帧存机制,X264以专门的一个模块frame.c进行处理。

common/frame.c中包括一组帧缓冲操作函数。包括对帧进行FILO和FIFO存取,空闲帧队列的相应操作等。

以下逐个函数分析encoder.c中编码一帧的函数x264_encoder_encode中有关frame的调用:

x264_reference_update
这个函数里最主要的工作的是将上一个参考帧放入参考帧队列,并从空闲帧队列中取出一帧作为当前的参考工作帧(即解码操作的目的帧),即h->fdec。

x264_t结构体维护着CODEC的诸多重要信息,其中成员frames是一个指示和控制帧编码过程的结构。其中current是已经准备就绪可以编码的帧,其类型已经确定;next是尚未确定类型的帧;unused用于回收不使用的frame结构体以备今后再次使用。frames结构体中i_input指示当前输入的帧的(播放顺序)序号。i_delay设置为由B帧个数(和线程个数)确定的帧缓冲延迟,在多线程情况下为i_delay = i_bframe + i_threads - 1(显然当线程数为1的单线程情形,该缓冲延迟就是B帧个数,至于多线程如何工作已经超出本文讨论范围)。而判断B帧缓冲填充是否足够则通过条件判断:h->frames.i_input <= h->frames.i_delay + 1 - h->param.i_threads。
x264_encoder_encode每次会以参数送入一帧待编码的帧pic_in,函数首先会从空闲队列中取出一帧用于承载该新帧,而它的i_frame被设定为播放顺序计数,如:fenc->i_frame = h->frames.i_input++。
x264_encoder_encode在根据上述判据确定B帧缓冲充满的情况下才进行后续编码工作。


当当前队列(current队列)可用帧为0时,需要对next队列中的帧进行判决,需要进行如下过程:
1. 调用x264_slicetype_decide
这个函数确定当前条带(帧)的类型
其中首先调用x264_ratecontrol_slice_type,依据码率控制逐个求出next列表中所有帧的类型(虽然在当前并不全部用到,见后)。
随后统计审查并调整next列表,保证IDR帧满足有关最大关键帧间隔的要求的正常出现:即针对frm->i_frame - h->frames.i_last_idr >= h->param.i_keyint_max作判断。审查按顺序针对所有被判定为B系或AUTO类型的帧进行(这些帧在审核过程中被确认为B帧),直到遇到第一个不是这样的帧。
如果某个帧被指定为IDR,则一个GOP在它之前结束。

2. 而后,即将next列表中已经判定的一系列帧(先后是一些B帧和一个非B帧)转移到current列表中。在这个过程中:
原始序列(播放顺序)B0, B1, B2, P,转移后的顺序为P, B0, B1, B2。在使用bframe_pyramid模式时,中间的B帧要前置,即上述顺序变为:P, B1, B0, B2。

此时,就可以从current队列中取出一帧,进行编码,现在记这帧叫h->fenc。
首先做几项和帧有关的设置工作:
1. 如果f_enc是IDR,则将最近IDR序号标记h->frames.i_last_idr设置为i_frame。
2. 根据f_enc的类型确定NAL和SLICE类型相关参数。
3. 设置POC为2 * (h->fenc->i_frame - h->frames.i_last_idr)。并使得h->fdec和h->fenc的主要帧参数一致。

随后进行以下一些过程:
x264_reference_build_list
在这个函数中,我们将遇到参考帧列表h->frames.reference和H.264很有特色的双列表(h->fref0、h->fref1)。前者中放置了所有可用于参考的参考帧。
首先将所有reference列表中的帧按照POC和h->fenc的POC的大小关系不同复制到双列表中,其中h->fref0放置POC较小的那些。然后对双列表进行排序,使得h->fref0中的帧POC按从大到小排列,h->fref1按从小到大排列,于是这两个列表中靠前的帧的POC比较接近当前帧h->fenc。在这里,一个特殊的情况是,对于P帧(只需要用到列表h->fref0做参考),其排序依据是i_frame_num而不是POC,因此需要对这种情况的列表h->fref0置位需重排序标记。最后对双列表的长度做限制。

x264_ratecontrol_start
码率控制初始化,在以后专门的话题中论述。
在初始化后,从码率控制体中获得全局QP值:i_global_qp = x264_ratecontrol_qp( h )。

如果当前是B条带(帧),则调用x264_macroblock_bipred_init
该函数设置一些参考帧关系矩阵,关系矩阵以fref0的索引为行坐标,以fref1的索引为列坐标。主要包括:dist_scale_factor,bipred_weight,矩阵值主要由相应帧的POC决定。后续讨论。

x264_slice_init
内部调用x264_slice_header_init,它对Header进行配置,含义以后讨论。

bs_init
初始化码流工作上下文。

随后将帧类型表现到码流中。接着写SEI,SPS和PPS。

然后就是最关键的写条带(即主要的编码工作)开始的地方:
x264_slices_write
这里通过x264_stack_align调用x264_slice_write,为了将栈做4字节对齐,以提高运行效率。

x264_slice_write函数是编码一帧的关键函数,将在下一章中论述。

H.264笔记之二——宏块结构 这里主要有一下几个过程:1. 初始化h->stat.frame,即全部清零。2. 写条带头:x264_slice_header_write,即把刚才x264_slice_header_init设置的一些参数写入。3. 如果是CABAC编码,则初始化CABAC。有关CABAC在后续相关章节讨论。4. 遍历一帧中的所有宏块,这是编码的主要部分:for( mb_xy = h->sh.i_first_mb 阅读详情

相关推荐

H.264笔记整理3

H.264整理3 转自:http://www.hellotongtong.com/avcodecbase/avcodecbase-h264-learning120.html 需求 在移动端做音视频开发不同于基本的UI业务逻辑工作,音视频开发需要你懂得音视频中一些基本概念,针对编解码而言,我们必须提前懂得编解码器的一些特性,码流的结构,码流中一些重要信息如sps,pps,vps,start code以及基本的工作原理,而大多同学都只是一知半解,所以导致代码中的部分内容虽可以简单理解却...

福优学苑@音视频+流媒体 1342

X264多线程分析

X264多线程分析  <br />这一次的文章将分析X264的多线程过程,也可以说是并行编码过程。<br /> <br />1. 编译并行编码的x264<br />从X264的帮助命令行可以看到,添加--threads项可以调整运行的线程数,可是当我完成X264编译,视图对手头的YUV进行编码的时候,发现在自己的双核计算机上,只能发挥50%的效率,即使使用--threads n 也无济于事,提示就是没有打开pthread支持。Pthreads定义了一套 C程序语言类型、函数与常量,它以 pthread.h

wutong_login的专栏 3462

H264基本知识

压缩比为1%

站在树顶端设计的男人 1万+

X264代码学习(七)

X264代码主要的部分分为三个步骤,即数据的读入与存放,视频编码层(VCL)的视频编码和网络提取层(Network Abstraction Layer,NAL)单元输出。   数据的读入与存放:X264开辟了unused、next、current、refrence等区域分别保存未处理原始图片序列、即将编码帧序列、当前编码帧和参考帧序列,同时还开辟了fenc和fdec区域用于存放已编码帧和重构帧 ...

wmnmtm的专栏 179

帧类型决策-x264_slicetype_decide()

/* lookahead队列中的帧类型确定 过程: 1.计算每一帧的时长duration 2.对lookahead里的每一帧进行帧类型分析 ·x264_ratecontrol_slice_type() ·x264_slicetpye_analyse() 3.对一段BBB...BBB(IDR/I/P) 1.检查BREF是否合规 2.检查Keyframe,设置...

workspace 1233

x264的参考帧管理机制

x264的参考帧管理机制

m0_60259116的博客 1090

H.264 编码笔记

H.264 视频编码技术解析

m0_60856753的博客 1648

H.264学习笔记

H.264凭借其出色的压缩效率、灵活的编码方式以及高质量的视频表现,成为了现代视频技术的核心标准之一。它不仅减少了存储需求,还提高了流媒体和实时视频传输的可行性。对于从高清到超高清视频,H.264的编码能力仍然广泛适用。H.264的帧结构设计(I帧、P帧和B帧)极大地提高了视频编码的压缩效率。I帧保存完整的图像信息,P帧通过参考之前的帧减少冗余数据,而B帧则通过双向参考提供进一步的压缩优势。这种帧间的协同工作大幅降低了带宽需求和存储成本,同时保持了视频的高质量。NALU头。

zfenggo的博客 1193

h.264优化笔记

目前 H.264编解码器的实现可以采用以下几种方式 Ø 采用奔腾 Pentium 四代机实现 H.264 编解码最早就是在 PC 平台上实现的 由于简单易开发 基于该平台的研究得到最多 JVT 的 JM 参考代码是就是基于 PC 平台的 此方案的优点是利用当前最新的 PC 资源 以及较强的软件工具 Intel 的 SSE2 和 MMX 提供了较完整的多媒体指令集和流水线 其缺点是占用资源

qq_27901569的博客 449

H.264笔记

H.264标准写得比较繁复,所以考虑在浏览完Whitepaper之后就开始研读X264代码。X264代码风格还是比较清晰简洁的。 根据对标准得理解,Picture Order Count在Slice解码的一开始就被提及: I0 B1 B2 P3 B4 B5 P6 I0 P3 B1 B2 P6 B4 B5 于是I0的POC是0,P3的POC是3,B1是1…… 为了支持H26

szu030606的专栏 5978

H.264笔记之三——帧内预测

本章讨论的代码主要位于common/predict.c中。x264_macroblock_cache_load函数在每个宏块解码之前初始化某些状态,在x264_slice_write函数的宏块处理循环中被调用。i_mb_xy:   当前宏块的索引i_mb_4x4:  当前宏块中第一个4x4块的索引i_mb_8x8:  当前宏块中第一个8x8块的索引i_top_y:   上方宏块的y索引i_top_

quanben 4347

H.264+JM学习笔记

H.264特点H.264支持4:2:0的连续或隔行视频的编码和解码。H.264基本概念1、宏块 在视频编码中,一个编码图像通常划分成若干宏块组成,一个宏块由一个亮度像素块和附加的两个色度像素块组成。一般来说,亮度块为16x16大小的像素块,而两个色度图像像素块的大小依据其图像的采样格式而定,如:对于YUV420采样图像,色度块为8x8大小的像素块。每个图象中,若干宏块被排列成片的形式,视频

上官宏竹的专栏 5109

H.264笔记之三——环路内滤波

    H.264环路内滤波顾名思义在编码侧开启后解码部分必须跟随开启,因此是该视频编码方案的不可分割的组成部分。    以下整理了Baseline情形下环路滤波的四种情形:    All cases that may exist for Baseline    Bs = 4: either is intra, MB edge    Bs = 3: either is intra, blo

quanben 2661
上一篇: 绕轴旋转问题
下一篇: H.264笔记之二——宏块结构
quanben
博客等级 码龄22年 175粉丝 199原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值