将标题重写为:“将YUV数据格式从NV12转换为I420并进行90度旋转”
最编程
2024-08-15 15:27:18
...
1、几种常见格式的YUV数据
I420(YU12):先存Y,然后U,最后V。YYYYYYYYUUVV
YV12:先存Y,然后V,最后U。YYYYYYYYVVUU
NV12:先存Y,然后UV交错存储,iOS下这种模式。YYYYYYYYUVUV
NV21:先存Y,然后VU交错存储,Android下这种格式。YYYYYYYYVUVU
2、NV12转I420
因为NV12的YUV数据UV是交错存储的,I420的UV是单独存储的,所有NV12转I420的时候,只需要将UV数据分开
void NV12ToI420(uint8_t* src_y, uint8_t* src_uv,
uint8_t* dst_y, uint8_t* dst_u, uint8_t* dst_v,
uint32_t width,uint32_t height) {
// src_y --> dst_y memcpy
for (int i = 0; i < (width* height); ++i) {
dst_y[i] = src_y[i];
}
// src_uv --> dst_u,dst_v
int index = 0;
for (int i = 0; i < (width* height/2); ++i) {
dst_u[index] = src_uv[i++];
dst_v[index] = src_uv[i];
index++;
}
}
3、旋转I420数据,旋转90度
首先我们先看这样一张图,代表的是4*8的YUV420数据,每一个Y代表一个像素点,长度为1个字节,每四个Y对应一个U,一个V(相同颜色),也就是每一个2*2的小正方形对应一个U和V。下来我们将图片旋转90度,可以得到下面这张图片
首先我们旋转的是Y,然后旋转U,最后旋转V,因为每一个2*2的小正方形对应一个U和V,所以就是每两个宽和每两个高取一个U和V,所以只要写出Y的旋转,然后U和V的旋转就是将Y旋转的宽和高都变为原来的一半就可以了,具体代码如下
enum Degree { kRotate90, kRotate180, kRotate270 };
// 旋转
void RotateI420(uint8_t* src_y, uint8_t* src_u, uint8_t* src_v,
uint8_t* dst_y, uint8_t* dst_u, uint8_t* dst_v,
uint32_t width,uint32_t height,int degree) {
if (degree != kRotate90) {
return;
}
// 第一步我们只转Y
// 旋转90度
int index = 0;
for (int i = 0; i < width; ++i) {
for (int j = height- 1; j >= 0; --j) {
dst_y[index++] = src_y[j*width+ i];
}
}
int uv_index = 0;
for (int i = 0; i<width/ 2; i++) {
for (int j = height/2-1; j>=0; j--)
{
dst_u[uv_index] = src_u[width/ 2 * j + i];
dst_v[uv_index] = src_v[width/ 2 * j + i];
uv_index++;
}
}
}
3、当然上面的格式转换和旋转都可以使用libyuv取完成,写好的库,很方便