音视频入门-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 ...
随机推荐
- python-pptx
python-pptx的使用首先需要了解几个基本概念: 1.引入python-pptx frompptximportpresentation # 实例化Presentation prs= ...
- cv2.imread()
cv2.imread() 使用opencv和caffe的伙伴们,可能会有一个疑问,那就是对于同时读取图片的cv2.imread()和caffe.io.loadimage两个函数,有什么差别? 1.cv ...
- Chrome与chromedriver.exe的版本对应
Chrome与chromedriver.exe的版本对应 分类专栏: pyhton3.7+selenium3 转:https://blog.csdn.net/weixin_44545954/art ...
- typeScript模块<四>
/* 功能:定义一个操作数据库的库 支持 Mysql Mssql MongoDb 要求1:Mysql MsSql MongoDb功能一样 都有 add update delete get方法 注意:约 ...
- AS的常见问题
版本问题 a.Gradle的版本 用于将代码和资源打包生成apk的编译脚本.此版本号究竟是啥得去studio的安装目录下查看b.Gradle插件的版本 com.android.tools.build: ...
- openresty开发系列10--openresty的简单介绍及安装
openresty开发系列10--openresty的简单介绍及安装 一.Nginx优点 十几年前,互联网没有这么火,软件外包开发,信息化建设,帮助企业做无纸化办公,收银系统,工厂erp,c/s架构偏 ...
- 【Mybatis】MyBatis之缓存(七)
MyBatis缓存介绍 Mybatis 使用到了两种缓存:一级缓存(本地缓存.local cache)和二级缓存(second level cache). 一级缓存:基于PerpetualCache ...
- 【440】Tweet 元素意义
参考:Tweet Object 参考:Geo Objects 参考:User Object Ref: Place data dictionary Tweet Object Attribut ...
- 123457123456#2#----com.MC.ShiZi365--前拼后广--儿童识字Game-mc22222222222222222
com.MC.ShiZi365--前拼后广--儿童识字Game-mc
- POJ Corn Fields 状态压缩DP基础题
题目链接:http://poj.org/problem?id=3254 题目大意(名称什么的可能不一样,不过表达的意思还是一样的): 种玉米 王小二从小学一年级到现在每次考试都是班级倒数第一名,他的爸 ...