* 音视频入门文章目录 *

libyuv

libyuv 是 Google 开源的实现各种 YUV 与 RGB 之间相互转换、旋转、缩放等的库。它是跨平台的,可在 Windows、Linux、Mac、Android 等操作系统,x86、x64、arm 架构上进行编译运行,支持 SSE、AVX、NEON 等 SIMD 指令加速。

准备工作

一张图片

下载 rainbow-700x700.bmp BMP 图片 或者 自己准备一张图片(知道分辨率,如:700x700)

FFmpeg 工具包

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-yuv-conversion-libyuv

参考资料:

libyuv/libyuv

内容有误?联系作者:


音视频入门-10-使用libyuv对YUV数据进行缩放、旋转、镜像、裁剪、混合的更多相关文章

  1. 音视频入门-09-RGB&YUV互转-使用开源库

    * 音视频入门文章目录 * 介绍开源库 使用第三方开源库来简化开发,屏蔽一些底层的复杂度,节省大量编写代码的时间. libyuv: Google 开源的实现各种 YUV 与 RGB 之间相互转换.旋转 ...

  2. 音视频入门-08-RGB&YUV

    * 音视频入门文章目录 * YUV & RGB 相互转换公式 YCbCr 的 Y 与 YUV 中的 Y 含义一致,Cb 和 Cr 与 UV 同样都指色彩,Cb 指蓝色色度,Cr 指红色色度,在 ...

  3. 音视频入门-07-认识YUV

    * 音视频入门文章目录 * YUV & YCbCr 简介 YUV,是一种颜色编码方法.常使用在各个视频处理组件中. YUV 在对照片或视频编码时,考虑到人类的感知能力,允许降低色度的带宽. Y ...

  4. 音视频入门-01-认识RGB

    * 音视频入门文章目录 * RGB 简介 RGB 色彩模式是工业界的一种颜色标准,是通过对红(R).绿(G).蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB 即是代表红 ...

  5. 音视频入门-02-RGB拼图

    * 音视频入门文章目录 * 图片 & 像素点 & RGB 平时浏览的图片看不出像素点: 图片放大时,可以看出图片是一个个像素点组成的: 每个像素点的颜色可以用 RGB 表示: RGB ...

  6. 音视频入门-18-手动生成一张GIF图片

    * 音视频入门文章目录 * GIF 编码知识 GIF 包含的数据块: 文件头(Header) 逻辑屏幕标识符(Logical Screen Descriptor) 全局颜色表(Global Color ...

  7. 堪称教科书级别的Android音视频入门进阶学习手册,开源分享!

    概述 随着整个互联网的崛起,数据传递的形式也在不断升级变化,总的流行趋势如下: 纯文本的短信,QQ -> 空间,微博,朋友圈的图片文字结合 -> 微信语音 -> 各大直播软件 -&g ...

  8. 音视频入门-11-PNG文件格式详解

    * 音视频入门文章目录 * PNG 文件格式解析 PNG 图像格式文件由一个 8 字节的 PNG 文件署名域和 3 个以上的后续数据块(IHDR.IDAT.IEND)组成. PNG 文件包括 8 字节 ...

  9. 音视频入门-12-手动生成一张PNG图片

    * 音视频入门文章目录 * 预热 上一篇 [PNG文件格式详解]详细介绍了 PNG 文件的格式. PNG 图像格式文件由一个 8 字节的 PNG 文件署名域和 3 个以上的后续数据块(IHDR.IDA ...

随机推荐

  1. ubuntu12.04下安装Python3.5.2 1

    下载源码包 (https://www.python.org/downloads/release/python-352/) 2  解压Python-3.5.2.tar.xz 3  sudo ./conf ...

  2. Js-事件分发与DOM事件流

    原文地址:https://www.jianshu.com/p/dc1520327022 Js事件分发与DOM事件流 对JavaScript分发事件不熟悉,网上查阅相关资料整理后,记录一下对Javasc ...

  3. Oracle列信息表 all_tab_columns中的data_length和data_precision字段区别

    Oracle列信息表 all_tab_columns中的data_length和data_precision字段区别 区别: 这两个属性都属于user_tab_columns视图,他们的含义:1,da ...

  4. Python脚本实现Linux/MAC中Xmind Zen去水印等其他功能的过程(V0.1)

    说明本脚本仅作为学习使用,请勿用于任何商业用途.本文为原创,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明.功能简介 去除软件右上角激活按钮 去除导出时激活弹窗 去除导出PDF文 ...

  5. 禁止select标签选择,禁止select组件change值

    大家知道, 对于HTML控件select, 是没有readOnly属性的,所以设置它并不起作用,如: 如果用disabled的话,提交时又取不到值. 那有什么方法可以实现?可以有一个折中的方法,如下: ...

  6. Linux 在 TOP 命令中切换内存的显示单位

    顶部的内存信息可以在top运行时按E切换,每次切换转换率为1000,只是没有单位,切换的单位为 k,m,g,t,p: 1. 2. 3., 4. 底下的进程信息按e切换,每次切换转换率为1000,切换的 ...

  7. Spring cloud微服务安全实战-5-4请求转发及退出

    步骤1234已经完成 下面处理 5678这几步.zuul在转发的时候 把请求头加上 获取订单信息 加一个按钮,登陆成功后,去拿订单的信息. 展示获取到的订单信息 ts代码 ts内定义order对象 定 ...

  8. Python - Django - Cookie 简单用法

    home.html: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...

  9. LeetCode_342. Power of Four

    342. Power of Four Easy Given an integer (signed 32 bits), write a function to check whether it is a ...

  10. LeetCode_219. Contains Duplicate II

    219. Contains Duplicate II Easy Given an array of integers and an integer k, find out whether there ...