音视频入门-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 ...
随机推荐
- java查询数据库数据时报错antlr/ANTLRException
在集成SH项目时,写hql 语句总是查不出东西,而且报 java.lang.NoClassDefFoundError: antlr/ANTLRException,郁闷了很久在网上终于找到了答案,原来是 ...
- 字节码(.class)文件的加载过程
类加载 在Java代码中,类型的加载.连接与初始化过程都是在程序运行期间完成的. 类型可以是Class,Interface, 枚举等. Java虚拟机与程序的生命周期 在如下几种情况下,Java虚拟机 ...
- pip安装报错Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-e_k8hq6a/pynacl/
Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build-e_k8hq6a/pyn ...
- nginx: [emerg] open() "/var/run/nginx.pid" failed (13: Permission denied)
现象 1.centos6.9 用rpm包安装nginx 2.修改Nginx的多个配置文件和配置项 3.service nginx restart 报错: nginx: [emerg] open() & ...
- linux内核中i2c驱动中slave模式接口的调用
1. 关注unreg_slave接口 1.1 这个接口在哪里被调用呢? 在drivers/i2c/i2c-core-slave.c中 int i2c_slave_unregister(struct i ...
- [转]linux 下 使用 c / c++ 调用curl库 做通信开发
example: 1. http://curl.haxx.se/libcurl/c/example.html 2. http://www.libcurl.org/book: 1. http:/ ...
- [转]arcgis for server 10.2 下载及安装
转自:https://blog.csdn.net/nominior/article/details/80211963 https://blog.csdn.net/mrib/article/detail ...
- 【BIGEMAP一键离线地图服务】
地址:http://www.bigemap.com/offlinemaps/ 首页 离线地图 代码示例 项目案例 开发文档 关于我们 [BIGEMAP一键离线服务] 1.快速搭建离线地图服务2 ...
- invalid application of ‘sizeof’ to incomplete type
sizeof 后面所跟的数据类型没有定义,或者找不到定义的地方 eg: 头文件中定义结构体如下: struct PersonaL{ char name[]; int age; }; 但是在cpp中使 ...
- 转 mysql 存储过程初探
https://www.cnblogs.com/qmfsun/p/4838032.htmlMySQL命令执行sql文件的两种方法 https://www.cnblogs.com/mark-chan/p ...