FFmpeg H264/H265边界填充一
来源:互联网 发布:深入浅出node.js 编辑:程序博客网 时间:2024/06/04 19:32
在H264和H265编解码标准中,运动补偿的参考像素可越过参考图像的边界。图像边界之外的参考像素是不存在的,标准使用边界处的像素来填充处于边界之外的像素值。
1. 标准填充
标准对填充的算法做了如下的描述,如图1所示的两个图,分别描述了H264和H265亮度分量的标准填充算法(H265色度和亮度分量的填充算法是一致的,但是由于H264色度运动补偿和亮度补偿算法不一致,所以H264色度的填充方式和亮度填充方式略有差异。但是总得来说,他们的原理都是用边界值填充不存在的像素值)。虽然这两个图中的变量名不一样,但表示的是同一个意思。
(a).H264填充算法
(b).H265填充算法
图1. 标准填充算法
标准算法在描述填充算法时,是一个一个的像素去判断是否越界,然后再去填充相应的像素值。这种方法的性能较差,会影响编解码效率。
2. FFmpeg填充算法
FFmpeg使用了memcpy的方式,一次填充好几个像素值,该方法可以相对提高填充的效率。图2(a)简要说明了FFmpeg中垂直填充的例子。其中[0,start_y)是超出上边界的部分,这部分像素需要使用start_y处的像素行进行填充;[start_y,end_y]处的像素值是实际存在的,可以直接拷贝;(start_y,bh]处的像素是超出边界下部分的像素值,需要使用边界end_y处的像素值填充。实际中,一般不会出现图2(a)所示的情况,实际中一般出现图2(b)所示的情况,要么是上边界越界,要么是下边界越界,几乎不会出现上下边界都有越界的情况。因为在H264中宏块大小为16×16,而亮度运动补偿为6抽头滤波,如图3所示,所以H264最大只需要21×21的空间来存储当前块所需的参考像素。H265原理与此类似,只是CTU的大小为64,同时使用8抽头滤波,所以最大只需要71×71的空间来存储当前块所需的参考像素。
(a) (b)
图2. 垂直填充
图3. 运动补偿
3. FFmpeg源代码分析
void FUNC(ff_emulated_edge_mc)(uint8_t *buf, const uint8_t *src, ptrdiff_t buf_linesize, ptrdiff_t src_linesize, int block_w, int block_h, int src_x, int src_y, int w, int h){ int x, y; int start_y, start_x, end_y, end_x; if (!w || !h) return; av_assert2(block_w * sizeof(pixel) <= FFABS(buf_linesize)); if (src_y >= h) { src -= src_y * src_linesize; src += (h - 1) * src_linesize; src_y = h - 1; } else if (src_y <= -block_h) { src -= src_y * src_linesize; src += (1 - block_h) * src_linesize; src_y = 1 - block_h; } if (src_x >= w) { src += (w - 1 - src_x) * sizeof(pixel); src_x = w - 1; } else if (src_x <= -block_w) { src += (1 - block_w - src_x) * sizeof(pixel); src_x = 1 - block_w; } start_y = FFMAX(0, -src_y); start_x = FFMAX(0, -src_x); end_y = FFMIN(block_h, h-src_y); end_x = FFMIN(block_w, w-src_x); av_assert2(start_y < end_y && block_h); av_assert2(start_x < end_x && block_w); w = end_x - start_x; src += start_y * src_linesize + start_x * sizeof(pixel); buf += start_x * sizeof(pixel); // top for (y = 0; y < start_y; y++) { memcpy(buf, src, w * sizeof(pixel)); buf += buf_linesize; } // copy existing part for (; y < end_y; y++) { memcpy(buf, src, w * sizeof(pixel)); src += src_linesize; buf += buf_linesize; } // bottom src -= src_linesize; for (; y < block_h; y++) { memcpy(buf, src, w * sizeof(pixel)); buf += buf_linesize; } buf -= block_h * buf_linesize + start_x * sizeof(pixel); while (block_h--) { pixel *bufp = (pixel *) buf; // left for(x = 0; x < start_x; x++) { bufp[x] = bufp[start_x]; } // right for (x = end_x; x < block_w; x++) { bufp[x] = bufp[end_x - 1]; } buf += buf_linesize; }}
ff_emulated_edge_mc函数第15~18行是判断参考的像素块是否超出参考图像的下边界,如图4(a)所示,当前src对应的坐标为(src_x,src_y),第16行代码的含义是将像素的坐标设置为(src_x,0),第17行代码的含义是将像素的坐标设置为(src_x,h-1),也即将当前图像的y坐标指向最后一行像素所在的位置,第18行将y坐标值src_y同步设置为h-1。
第19~22行是判断参考的像素是否超出参考图像的上边界,如图4(b)所示。24~26行是判断参考像素是否超出参考图像的右边界,如图4(c)所示,27~29行判断参考图像是否超出参考图像的左边界,如图4(d)所示。
32~35行根据15~30行代码计算像素垂直拷贝和水平拷贝边界范围。40和41行确定像素拷贝的源地址和目的地址。
(a). 超出下边界 (b). 超出上边界
(c).超出右边界 (d).超出左边界
图4. 超出边界的四种特殊情况
第44~46行对应4(b)将超出上边界部分用边界处的值填充。第50~53行将未超出边界区域的像素拷贝填充到临时空间中。第57~60行将超出下边界的部分用下边界行的像素值填充。68~70行用左边界填充超出左边界的部分,73~75行用右边界填充超出右边界的部分。如图5所示各区域的示意图,其中5号区域是在边界以内的区域,2区域是超出上边界的部分,4区域是超出左边界的部分,6是超出右边界的部分,8是超出下边界的部分,1是超出上边界和超出左边界的部分,3是超出上边界和右边界的部分,7是超出下边界和左边界的部分,9是超出下边界和右边界的部分,当然,针对某一个特定的宏块或者CTU,不会同时存在这9个区域。其中2号区域将使用2号和5号区域重叠的像素行填充,4号区域将使用4号和5号区域重叠的像素列填充,6号区域将使用6号区域和5号区域重叠的像素列填充,8号区域将使用8号区域和5号区域重叠的像素行填充,1号区域将使用1号区域和5号区域重叠的那一个像素点填充(也就是1号区域右下角和5号区域左上角重叠的那一个像素点填充),同理,3号区域将使用3号区域和5号区域重叠的那一个像素点填充,7号区域将使用7号区域和5号区域重叠的那一个像素点填充,9号区域将使用9号区域和5号区域重叠的那一个像素点填充。
图5. 各区域示意图
- FFmpeg H264/H265边界填充一
- FFmpeg H264/H265边界填充一
- FFmpeg H264/H265边界填充二--videodsp.asm
- ffmpeg h264转h265
- FFMPEG H264/H265 编码延迟问题
- ffmpeg 编码H265和H264对比
- FFMPEG H264/H265 编码延迟问题
- H264 H265
- 使用ffmpeg的lib库解码H264/H265
- ffmpeg h265
- H265/H264/Mjpeg/mpeg
- H265 H264重要链接
- h264和h265
- ffmpeg h265 usage example
- H264/H265 PS 流分析
- ffmpeg 实现视频h264编码 (一)
- ffmpeg h264
- h264帧边界识别
- oracle创建sequence和触发器trigger
- python错误之NameError
- centos6.5,centos6.6 logstash无法使用service方式启动方式。
- 基于 Python 的数据结构与算法分析学习记录(6-6)—— 分析树
- fbx sdk c# wrapper
- FFmpeg H264/H265边界填充一
- HDU 3449 Consumer (依赖背包)
- centos apache 使用 mod_proxy_fcgi 支持多版本 php
- 黑马安卓52期视频下载 共64.2G 视频教程下载
- keil error:malformed via file....
- 牛腩新闻发布系统--点击修改类别
- python手动安装第三方扩展库的有效方法
- equals和hashcode方法
- 二叉树基本操作及面试题