音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合
libyuv
libyuv 是 Google 开源的实现各种 YUV 与 RGB 之间相互转换、旋转、缩放等的库。它是跨平台的,可在 Windows、Linux、Mac、Android 等操作系统,x86、x64、arm 架构上进行编译运行,支持 SSE、AVX、NEON 等 SIMD 指令加速。
准备工作
一张图片
下载 rainbow-700x700.bmp BMP 图片 或者 自己准备一张图片(知道分辨率,如:700x700)

FFmpeg 工具包
根据自己的系统,下载 FFmpeg Static 工具包。
得到所需的 yuv420p 文件
将上面准备的图片转换成 YUV420P 格式:
ffmpeg -i rainbow.bmp -video_size 700x700 -pix_fmt yuv420p rainbow-yuv420p.yuv
查看 YUV 文件
ffplay -f rawvideo -pixel_format yuv420p -video_size 700x700 rainbow-yuv420p.yuv
libyuv 操作 YUV
YUV 裁剪

[rainbow-yuv420p.yuv] -> [rainbow-yuv420p-clip-x-y.yuv]
#include <stdio.h>
#include <stdint.h>
#include "libyuv.h"
void clip(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height, int cropX, int cropY, int cropWidth, int cropHeight) {
ConvertToI420(
srcYuvData,
width*height*3/2,
dstYuvData,
cropWidth,
dstYuvData+cropWidth*cropHeight,
(cropWidth+1)/2,
dstYuvData+cropWidth*cropHeight+((cropWidth+1)/2)*((cropHeight+1)/2),
(cropWidth+1)/2,
cropX,
cropY,
width,
height,
cropWidth,
cropHeight,
kRotate0,
FOURCC_YU12);
}
int main() {
uint32_t width = 700, height = 700;
uint32_t clipWidth = 200, clipHeight = 200;
uint8_t YUV[width*height*3/2];
uint8_t YUV_CLIP[clipWidth*clipHeight*3/2];
FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p.yuv", "rb");
fread(YUV, sizeof(YUV), 1, yuv420pFile);
clip(YUV, YUV_CLIP, width, height, 0, 0, clipWidth, clipHeight);
FILE *yuvClipFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-clip-0-0.yuv", "wb");
fwrite(YUV_CLIP, sizeof(YUV_CLIP), 1, yuvClipFile);
fclose(yuvClipFile);
fclose(yuv420pFile);
return 0;
}
YUV 缩放

[rainbow-yuv420p.yuv] -> [rainbow-yuv420p-scale-X.yuv]
#include <stdio.h>
#include <stdint.h>
#include "libyuv.h"
void scale(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height, int dstWidth, int dstHeight) {
I420Scale(
srcYuvData,
width,
srcYuvData+width*height,
(width+1)/2,
srcYuvData+width*height+((width+1)/2)*((height+1)/2),
(width+1)/2,
width,
height,
dstYuvData,
dstWidth,
dstYuvData+dstWidth*dstWidth,
(dstWidth+1)/2,
dstYuvData+dstWidth*dstHeight+((dstWidth+1)/2)*((dstHeight+1)/2),
(dstWidth+1)/2,
dstWidth,
dstHeight,
kFilterNone
);
}
int main() {
uint32_t width = 700, height = 700;
uint32_t dstWidth = 100, dstHeight = 100;
uint8_t YUV[width*height*3/2];
uint8_t YUV_SCALE[dstWidth*dstHeight*3/2];
FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p.yuv", "rb");
fread(YUV, sizeof(YUV), 1, yuv420pFile);
scale(YUV, YUV_SCALE, width, height, dstWidth, dstHeight);
FILE *yuvScaleFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-scale-6.yuv", "wb");
fwrite(YUV_SCALE, sizeof(YUV_SCALE), 1, yuvScaleFile);
fclose(yuvScaleFile);
fclose(yuv420pFile);
return 0;
}
YUV 旋转

[rainbow-yuv420p.yuv] -> [rainbow-yuv420p-rotation-90.yuv]
#include <stdio.h>
#include <stdint.h>
#include "libyuv.h"
void rotation(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height) {
I420Rotate(
srcYuvData,
width,
srcYuvData+width*height,
(width+1)/2,
srcYuvData+width*height+((width+1)/2)*((height+1)/2),
(width+1)/2,
dstYuvData,
width,
dstYuvData+width*height,
(width+1)/2,
dstYuvData+width*height+((width+1)/2)*((height+1)/2),
(width+1)/2,
width,
height,
kRotate90
);
}
int main() {
uint32_t width = 700, height = 700;
uint8_t YUV[width*height*3/2];
uint8_t YUV_ROTATION[width*height*3/2];
FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p.yuv", "rb");
fread(YUV, sizeof(YUV), 1, yuv420pFile);
rotation(YUV, YUV_ROTATION, width, height);
FILE *yuvRotationFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-rotation-90.yuv", "wb");
fwrite(YUV_ROTATION, sizeof(YUV_ROTATION), 1, yuvRotationFile);
fclose(yuvRotationFile);
fclose(yuv420pFile);
return 0;
}
YUV 镜像

[rainbow-yuv420p-rotation-90.yuv] -> [rainbow-yuv420p-rotation-90-mirror.yuv]
#include <stdio.h>
#include <stdint.h>
#include "libyuv.h"
void mirror(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height) {
I420Mirror(
srcYuvData,
width,
srcYuvData+width*height,
(width+1)/2,
srcYuvData+width*height+((width+1)/2)*((height+1)/2),
(width+1)/2,
dstYuvData,
width,
dstYuvData+width*height,
(width+1)/2,
dstYuvData+width*height+((width+1)/2)*((height+1)/2),
(width+1)/2,
width,
height
);
}
int main() {
uint32_t width = 700, height = 700;
uint8_t YUV[width*height*3/2];
uint8_t YUV_MIRROR[width*height*3/2];
FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-rotation-90.yuv", "rb");
fread(YUV, sizeof(YUV), 1, yuv420pFile);
mirror(YUV, YUV_MIRROR, width, height);
FILE *yuvMirrorFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-rotation-90-mirror.yuv", "wb");
fwrite(YUV_MIRROR, sizeof(YUV_MIRROR), 1, yuvMirrorFile);
fclose(yuvMirrorFile);
fclose(yuv420pFile);
return 0;
}
YUV 混合

[rainbow-yuv420p.yuv] -> [rainbow-yuv420p-blend.yuv]
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "libyuv.h"
void blend(uint8_t *srcYuvData, uint8_t *dstYuvData, int width, int height) {
uint8_t YUV_ROTATION[width*height*3/2];
I420Rotate(
srcYuvData,
width,
srcYuvData+width*height,
(width+1)/2,
srcYuvData+width*height+((width+1)/2)*((height+1)/2),
(width+1)/2,
YUV_ROTATION,
width,
YUV_ROTATION+width*height,
(width+1)/2,
YUV_ROTATION+width*height+((width+1)/2)*((height+1)/2),
(width+1)/2,
width,
height,
kRotate90
);
// 透明度
uint8_t alpha[width*height];
memset(alpha, 0X88, width*height);
I420Blend(
srcYuvData,
width,
srcYuvData+width*height,
(width+1)/2,
srcYuvData+width*height+((width+1)/2)*((height+1)/2),
(width+1)/2,
YUV_ROTATION,
width,
YUV_ROTATION+width*height,
(width+1)/2,
YUV_ROTATION+width*height+((width+1)/2)*((height+1)/2),
(width+1)/2,
alpha,
width,
dstYuvData,
width,
dstYuvData+width*height,
(width+1)/2,
dstYuvData+width*height+((width+1)/2)*((height+1)/2),
(width+1)/2,
width,
height
);
}
int main() {
uint32_t width = 700, height = 700;
uint8_t YUV[width*height*3/2];
uint8_t YUV_BLEND[width*height*3/2];
FILE *yuv420pFile = fopen("/Users/staff/Desktop/rainbow-yuv420p.yuv", "rb");
fread(YUV, sizeof(YUV), 1, yuv420pFile);
blend(YUV, YUV_BLEND, width, height);
FILE *yuvBlendFile = fopen("/Users/staff/Desktop/rainbow-yuv420p-blend.yuv", "wb");
fwrite(YUV_BLEND, sizeof(YUV_BLEND), 1, yuvBlendFile);
fclose(yuvBlendFile);
fclose(yuv420pFile);
return 0;
}
参考资料:
内容有误?联系作者:

音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合的更多相关文章
- 音视频入门-09-RGB&YUV互转-使用开源库
* 音视频入门文章目录 * 介绍开源库 使用第三方开源库来简化开发,屏蔽一些底层的复杂度,节省大量编写代码的时间. libyuv: Google 开源的实现各种 YUV 与 RGB 之间相互转换.旋转 ...
- 音视频入门-08-RGB&YUV
* 音视频入门文章目录 * YUV & RGB 相互转换公式 YCbCr 的 Y 与 YUV 中的 Y 含义一致,Cb 和 Cr 与 UV 同样都指色彩,Cb 指蓝色色度,Cr 指红色色度,在 ...
- 音视频入门-07-认识YUV
* 音视频入门文章目录 * YUV & YCbCr 简介 YUV,是一种颜色编码方法.常使用在各个视频处理组件中. YUV 在对照片或视频编码时,考虑到人类的感知能力,允许降低色度的带宽. Y ...
- 音视频入门-01-认识RGB
* 音视频入门文章目录 * RGB 简介 RGB 色彩模式是工业界的一种颜色标准,是通过对红(R).绿(G).蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB 即是代表红 ...
- 音视频入门-02-RGB拼图
* 音视频入门文章目录 * 图片 & 像素点 & RGB 平时浏览的图片看不出像素点: 图片放大时,可以看出图片是一个个像素点组成的: 每个像素点的颜色可以用 RGB 表示: RGB ...
- 音视频入门-18-手动生成一张GIF图片
* 音视频入门文章目录 * GIF 编码知识 GIF 包含的数据块: 文件头(Header) 逻辑屏幕标识符(Logical Screen Descriptor) 全局颜色表(Global Color ...
- 堪称教科书级别的Android音视频入门进阶学习手册,开源分享!
概述 随着整个互联网的崛起,数据传递的形式也在不断升级变化,总的流行趋势如下: 纯文本的短信,QQ -> 空间,微博,朋友圈的图片文字结合 -> 微信语音 -> 各大直播软件 -&g ...
- 音视频入门-11-PNG文件格式详解
* 音视频入门文章目录 * PNG 文件格式解析 PNG 图像格式文件由一个 8 字节的 PNG 文件署名域和 3 个以上的后续数据块(IHDR.IDAT.IEND)组成. PNG 文件包括 8 字节 ...
- 音视频入门-12-手动生成一张PNG图片
* 音视频入门文章目录 * 预热 上一篇 [PNG文件格式详解]详细介绍了 PNG 文件的格式. PNG 图像格式文件由一个 8 字节的 PNG 文件署名域和 3 个以上的后续数据块(IHDR.IDA ...
随机推荐
- MySQL两地三中心方案初步设计【转】
整体内容会按照如下的方式来进行设计: 首先说下方案的背景,我参考了一些资料(参见附件). 方案背景 随着互联网业务快速发展,多IDC的业务支撑能力和要求也逐步提升,行业内的“两地三中心”方案较为流行. ...
- F12找到页面某一元素所绑定的点击事件
比如我要查看银行账号这个标签所绑定的事件. 操作过程中使用的是谷歌浏览器 第一步:在该元素上右键→检查 第二步:点击Event Listeners 这样就能看到该元素绑定的所有事件了 第三步:展开cl ...
- layui表格工具条,如何动态控制按钮的展示?
<script type="text/html" id="toolTpl"> {{# if(d.agrgrtsts == 'A'){ }} < ...
- [转]地理投影,常用坐标系详解、WGS84、WGS84 Web墨卡托、WGS84 UTM、北京54坐标系、西安80坐标系、CGCS2000坐标系
转自:http://www.rivermap.cn/docs/show-1829.html 常用坐标系详解 (一)WGS84坐标系 WGS-84坐标系(World Geodetic System一19 ...
- 【Java】Spring之控制反转(IoC)(二)
控制反转(IoC) IoC:Inverse of Control(控制反转) 读作“反转控制”,更好理解,不是什么技术,而是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由Spring框架来 ...
- 一种计算hash的思路
/*** * 转换请求hash,根据转换模式计算hash,防止重复发送请求,浪费服务器资源(内存.cpu.文件系统等) * @param mode * @param data * @return */ ...
- jenkins升级完后一直显示升级中
这个时候是已经升级成功了的,刷新界面,从新登录即可
- ASP.NET全球化与本地化 c#多国语言的支持 (项目支持多国语言的开发)
ASP.NET 2.0及以上的开发平台,为全球化本地化应用程序提供了工具,而且实现起来非常简单.以下内容是使用c#,按照帮助一步步做的,将为初学者提供详细的实现步骤. 一 几个必要概念 (一) 支持全 ...
- Python爬虫-爬取豆瓣图书Top250
豆瓣网站很人性化,对于新手爬虫比较友好,没有如果调低爬取频率,不用担心会被封 IP.但也不要太频繁爬取. 涉及知识点:requests.html.xpath.csv 一.准备工作 需要安装reques ...
- Teaset-React Native UI 组件库
GitHub地址 https://github.com/rilyu/teaset/blob/master/docs/cn/README.md React Native UI 组件库, 超过 20 个纯 ...