#include
// nv21 --> i420
void nv21ToI420(unsigned char* src_nv21_data, int width, int height, unsigned char* src_i420_data)
{
int src_y_size = width * height;
int src_u_size = (width >> 1) * (height >> 1);
unsigned char* src_nv21_y_data = src_nv21_data;
unsigned char* src_nv21_vu_data = src_nv21_data + src_y_size;
unsigned char* src_i420_y_data = src_i420_data;
unsigned char* src_i420_u_data = src_i420_data + src_y_size;
unsigned char* src_i420_v_data = src_i420_data + src_y_size + src_u_size;
libyuv::NV21ToI420((const uint8_t*)src_nv21_y_data, width,
(const uint8_t*)src_nv21_vu_data, width,
(uint8_t*)src_i420_y_data, width,
(uint8_t*)src_i420_u_data, width >> 1,
(uint8_t*)src_i420_v_data, width >> 1,
width, height);
}
// i420 --> nv21
void i420ToNv21(unsigned char* src_i420_data, int width, int height, unsigned char* src_nv21_data)
{
int src_y_size = width * height;
int src_u_size = (width >> 1) * (height >> 1);
unsigned char* src_nv21_y_data = src_nv21_data;
unsigned char* src_nv21_uv_data = src_nv21_data + src_y_size;
unsigned char* src_i420_y_data = src_i420_data;
unsigned char* src_i420_u_data = src_i420_data + src_y_size;
unsigned char* src_i420_v_data = src_i420_data + src_y_size + src_u_size;
libyuv::I420ToNV21(
(const uint8_t*)src_i420_y_data, width,
(const uint8_t*)src_i420_u_data, width >> 1,
(const uint8_t*)src_i420_v_data, width >> 1,
(uint8_t*)src_nv21_y_data, width,
(uint8_t*)src_nv21_uv_data, width,
width, height);
}
// nv12 --> i420
void nv12ToI420(unsigned char* Src_data, int src_width, int src_height, unsigned char* Dst_data)
{
// NV12 video size
int NV12_Size = src_width * src_height * 3 / 2;
int NV12_Y_Size = src_width * src_height;
// YUV420 video size
int I420_Size = src_width * src_height * 3 / 2;
int I420_Y_Size = src_width * src_height;
int I420_U_Size = (src_width >> 1) * (src_height >> 1);
int I420_V_Size = I420_U_Size;
// src: buffer address of Y channel and UV channel
unsigned char* Y_data_Src = Src_data;
unsigned char* UV_data_Src = Src_data + NV12_Y_Size;
int src_stride_y = src_width;
int src_stride_uv = src_width;
//dst: buffer address of Y channel、U channel and V channel
unsigned char* Y_data_Dst = Dst_data;
unsigned char* U_data_Dst = Dst_data + I420_Y_Size;
unsigned char* V_data_Dst = Dst_data + I420_Y_Size + I420_U_Size;
int Dst_Stride_Y = src_width;
int Dst_Stride_U = src_width >> 1;
int Dst_Stride_V = Dst_Stride_U;
libyuv::NV12ToI420((const uint8_t*)Y_data_Src, src_stride_y,
(const uint8_t*)UV_data_Src, src_stride_uv,
(uint8_t*)Y_data_Dst, Dst_Stride_Y,
(uint8_t*)U_data_Dst, Dst_Stride_U,
(uint8_t*)V_data_Dst, Dst_Stride_V,
src_width, src_height);
}
// i420 --> nv12
void i420ToNv12(unsigned char* src_i420_data, int width, int height, unsigned char* src_nv12_data)
{
int src_y_size = width * height;
int src_u_size = (width >> 1) * (height >> 1);
unsigned char* src_nv12_y_data = src_nv12_data;
unsigned char* src_nv12_uv_data = src_nv12_data + src_y_size;
unsigned char* src_i420_y_data = src_i420_data;
unsigned char* src_i420_u_data = src_i420_data + src_y_size;
unsigned char* src_i420_v_data = src_i420_data + src_y_size + src_u_size;
libyuv::I420ToNV12(
(const uint8_t*)src_i420_y_data, width,
(const uint8_t*)src_i420_u_data, width >> 1,
(const uint8_t*)src_i420_v_data, width >> 1,
(uint8_t*)src_nv12_y_data, width,
(uint8_t*)src_nv12_uv_data, width,
width, height);
}
// 镜像
void mirrorI420(unsigned char* src_i420_data, int width, int height, unsigned char* dst_i420_data)
{
int src_i420_y_size = width * height;
// int src_i420_u_size = (width >> 1) * (height >> 1);
int src_i420_u_size = src_i420_y_size >> 2;
unsigned char* src_i420_y_data = src_i420_data;
unsigned char* src_i420_u_data = src_i420_data + src_i420_y_size;
unsigned char* src_i420_v_data = src_i420_data + src_i420_y_size + src_i420_u_size;
unsigned char* dst_i420_y_data = dst_i420_data;
unsigned char* dst_i420_u_data = dst_i420_data + src_i420_y_size;
unsigned char* dst_i420_v_data = dst_i420_data + src_i420_y_size + src_i420_u_size;
libyuv::I420Mirror((const uint8_t*)src_i420_y_data, width,
(const uint8_t*)src_i420_u_data, width >> 1,
(const uint8_t*)src_i420_v_data, width >> 1,
(uint8_t*)dst_i420_y_data, width,
(uint8_t*)dst_i420_u_data, width >> 1,
(uint8_t*)dst_i420_v_data, width >> 1,
width, height);
}
// 旋转
void rotateI420(unsigned char* src_i420_data, int width, int height, unsigned char* dst_i420_data, int degree)
{
int src_i420_y_size = width * height;
int src_i420_u_size = (width >> 1) * (height >> 1);
unsigned char* src_i420_y_data = src_i420_data;
unsigned char* src_i420_u_data = src_i420_data + src_i420_y_size;
unsigned char* src_i420_v_data = src_i420_data + src_i420_y_size + src_i420_u_size;
unsigned char* dst_i420_y_data = dst_i420_data;
unsigned char* dst_i420_u_data = dst_i420_data + src_i420_y_size;
unsigned char* dst_i420_v_data = dst_i420_data + src_i420_y_size + src_i420_u_size;
//要注意这里的width和height在旋转之后是相反的
if (degree == libyuv::kRotate90 || degree == libyuv::kRotate270)
{
libyuv::I420Rotate((const uint8_t*)src_i420_y_data, width,
(const uint8_t*)src_i420_u_data, width >> 1,
(const uint8_t*)src_i420_v_data, width >> 1,
(uint8_t*)dst_i420_y_data, height,
(uint8_t*)dst_i420_u_data, height >> 1,
(uint8_t*)dst_i420_v_data, height >> 1,
width, height,
(libyuv::RotationMode)degree);
}
else
{
libyuv::I420Rotate((const uint8_t*)src_i420_y_data, width,
(const uint8_t*)src_i420_u_data, width >> 1,
(const uint8_t*)src_i420_v_data, width >> 1,
(uint8_t*)dst_i420_y_data, width,
(uint8_t*)dst_i420_u_data, width >> 1,
(uint8_t*)dst_i420_v_data, width >> 1,
width, height,
(libyuv::RotationMode)degree);
}
}
// 缩放
void scaleI420(unsigned char* src_i420_data, int width, int height, unsigned char* dst_i420_data, int dst_width,
int dst_height, int mode)
{
int src_i420_y_size = width * height;
int src_i420_u_size = (width >> 1) * (height >> 1);
unsigned char* src_i420_y_data = src_i420_data;
unsigned char* src_i420_u_data = src_i420_data + src_i420_y_size;
unsigned char* src_i420_v_data = src_i420_data + src_i420_y_size + src_i420_u_size;
int dst_i420_y_size = dst_width * dst_height;
int dst_i420_u_size = (dst_width >> 1) * (dst_height >> 1);
unsigned char* dst_i420_y_data = dst_i420_data;
unsigned char* dst_i420_u_data = dst_i420_data + dst_i420_y_size;
unsigned char* dst_i420_v_data = dst_i420_data + dst_i420_y_size + dst_i420_u_size;
libyuv::I420Scale((const uint8_t*)src_i420_y_data, width,
(const uint8_t*)src_i420_u_data, width >> 1,
(const uint8_t*)src_i420_v_data, width >> 1,
width, height,
(uint8_t*)dst_i420_y_data, dst_width,
(uint8_t*)dst_i420_u_data, dst_width >> 1,
(uint8_t*)dst_i420_v_data, dst_width >> 1,
dst_width, dst_height,
(libyuv::FilterMode)mode);
}
// 裁剪
void cropI420(unsigned char* src_i420_data, int src_length, int width, int height,
unsigned char* dst_i420_data, int dst_width, int dst_height, int left, int top)
{
int dst_i420_y_size = dst_width * dst_height;
int dst_i420_u_size = (dst_width >> 1) * (dst_height >> 1);
unsigned char* dst_i420_y_data = dst_i420_data;
unsigned char* dst_i420_u_data = dst_i420_data + dst_i420_y_size;
unsigned char* dst_i420_v_data = dst_i420_data + dst_i420_y_size + dst_i420_u_size;
libyuv::ConvertToI420((const uint8_t*)src_i420_data, src_length,
(uint8_t*)dst_i420_y_data, dst_width,
(uint8_t*)dst_i420_u_data, dst_width >> 1,
(uint8_t*)dst_i420_v_data, dst_width >> 1,
left, top,
width, height,
dst_width, dst_height,
libyuv::kRotate0, libyuv::FOURCC_I420);
}
https://www.jianshu.com/p/bd0feaf4c0f9