libyuv实现通用的cvt,resize,crop功能
作者:互联网
我实现的思路是所有的格式先转成i420,然后进行crop resize 以及cvt的操作。
Get Fourcc code
uint32_t Scaler::GetFOURCC(const Scaler::Buffer *src) {
uint32_t fourcc = 0;
switch (src->color) {
case Scaler::ColorFormat::YUV_I420:
fourcc = libyuv::FourCC::FOURCC_I420;
break;
case Scaler::ColorFormat::YUV_NV21:
fourcc = libyuv::FourCC::FOURCC_NV21;
break;
case Scaler::ColorFormat::YUV_NV12:
fourcc = libyuv::FourCC::FOURCC_NV12;
break;
case Scaler::ColorFormat::BGR:
fourcc = libyuv::FourCC::FOURCC_24BG;
break;
case Scaler::ColorFormat::RGB:
fourcc = libyuv::FourCC::FOURCC_RAW;
break;
case Scaler::ColorFormat::BGRA:
fourcc = libyuv::FourCC::FOURCC_ARGB;
break;
case Scaler::ColorFormat::ARGB:
fourcc = libyuv::FourCC::FOURCC_BGRA;
break;
case Scaler::ColorFormat::RGBA:
fourcc = libyuv::FourCC::FOURCC_ABGR;
break;
case Scaler::ColorFormat::ABGR:
fourcc = libyuv::FourCC::FOURCC_RGBA;
break;
default:
LOG(ERROR) << "libyuv not support this color cvt I420";
break;
}
return fourcc;
}
Process
bool LibyuvProcess(const Scaler::Buffer *src, Scaler::Buffer *dst, const Scaler::Rect *crop) {
if (!src || !dst) return false;
if (!crop && src->width == dst->width && src->height == dst->height && src->color == dst->color) {
// copy src to dst directly
bool src_continus = IsBufferContinus_(src);
bool dst_continus = IsBufferContinus_(dst);
if (src->color <= Scaler::ColorFormat::YUV_I420) {
if (src_continus && dst_continus) {
memcpy(dst->data[0], src->data[0], src->width * src->height * 3 / 2);
} else {
memcpy(dst->data[0], src->data[0], src->width * src->height);
memcpy(dst->data[1], src->data[1], src->width * src->height / 4);
memcpy(dst->data[2], src->data[2], src->width * src->height / 4);
}
} else if (src->color <= Scaler::ColorFormat::YUV_NV12) {
if (src_continus && dst_continus) {
memcpy(dst->data[0], src->data[0], src->width * src->height * 3 / 2);
} else {
memcpy(dst->data[0], src->data[0], src->width * src->height);
memcpy(dst->data[1], src->data[1], src->width * src->height / 2);
}
} else if (src->color <= Scaler::ColorFormat::RGB) {
memcpy(dst->data[0], src->data[0], src->width * src->height * 3);
dst->data[1] = dst->data[2] = nullptr;
} else if (src->color <= Scaler::ColorFormat::ARGB) {
memcpy(dst->data[0], src->data[0], src->width * src->height * 4);
dst->data[1] = dst->data[2] = nullptr;
} else {
LOG(ERROR) << "scaler, we not realize this color space" << src->color;
return false;
}
for (size_t i = 0; i < 3; i++) {
dst->stride[i] = src->stride[i];
}
return true;
}
/*
// TODO after firist, "else if" is test , will be move future
if (src->color == Scaler::ColorFormat::BGR && dst->color == Scaler::ColorFormat::YUV_NV21) {
Scaler::LibyuvCvtBGRToNV21_Process(src, dst, crop);
} else if (src->color == ColorFormat::YUV_NV21 && dst->color == ColorFormat::YUV_NV21) {
Scaler::LibyuvResize_NV21(src, dst);
} else if (src->color == ColorFormat::BGR && dst->color == ColorFormat::YUV_I420) {
Scaler::LibyuvCvtBGRtoI420(src, dst);
} else if (src->color == ColorFormat::YUV_I420 && dst->color == ColorFormat::YUV_I420) {
Scaler::LibyuvResize_I420(src, dst);
}
*/
uint32_t width = src->width;
uint32_t height = src->height;
Scaler::Buffer *src_crop = nullptr;
Scaler::Buffer *resize_buf = nullptr;
if (crop != nullptr) {
width = crop->w;
height = crop->h;
if (width == dst->width && height == dst->height && src->color == dst->color) {
if (src->color == Scaler::ColorFormat::YUV_I420) {
dst->stride[0] = src->width;
dst->stride[1] = dst->stride[2] = src->width >> 1;
memcpy(dst->data[0], src->data[0], src->stride[0] * src->height);
memcpy(dst->data[1], src->data[1], dst->stride[1] * dst->height / 2);
memcpy(dst->data[1], src->data[1], dst->stride[1] * dst->height / 2);
} else if (src->color <= ColorFormat::YUV_NV12) {
dst->stride[0] = dst->stride[1] = src->width;
memcpy(dst->data[0], src->data[0], src->stride[0] * src->height);
memcpy(dst->data[1], src->data[1], src->stride[1] * src->height);
} else if (src->color <= ColorFormat::ARGB) {
dst->stride[0] = src->stride[0];
memcpy(dst->data[0], src->data[0], dst->stride[0] * src->height);
} else {
LOG(ERROR) << "scaler not support this color space";
}
return true;
} else {
src_crop = new Scaler::Buffer();
src_crop->color = Scaler::ColorFormat::YUV_I420;
src_crop->width = crop->w;
src_crop->height = crop->h;
src_crop->stride[0] = src_crop->width;
src_crop->stride[1] = src_crop->stride[2] = src_crop->width >> 1;
src_crop->data[0] = new uint8_t[src_crop->width * src_crop->height * 3 / 2];
src_crop->data[1] = src_crop->data[0] + src_crop->width * src_crop->height;
src_crop->data[2] = src_crop->data[1] + src_crop->width * src_crop->height / 4;
Scaler::LibyuvToI420(src, src_crop, crop);
}
}
if (width != dst->width || height != dst->height) {
resize_buf = new Scaler::Buffer();
memset(resize_buf, 0, sizeof(Scaler::Buffer));
resize_buf->color= Scaler::ColorFormat::YUV_I420;
resize_buf->width = dst->width;
resize_buf->height = dst->height;
resize_buf->stride[0] = resize_buf->width;
resize_buf->stride[1] = resize_buf->stride[2] = resize_buf->width >> 1;
resize_buf->data[0] = new uint8_t[resize_buf->width * resize_buf->height * 3 / 2];
resize_buf->data[1] = resize_buf->data[0] + resize_buf->width * resize_buf->height;
resize_buf->data[2] = resize_buf->data[1] + resize_buf->width * resize_buf->height / 4;
if (src_crop == nullptr) {
src_crop = new Scaler::Buffer();
src_crop->color = Scaler::ColorFormat::YUV_I420;
src_crop->width = src->width;
src_crop->height = src->height;
src_crop->stride[0] = src_crop->width;
src_crop->stride[1] = src_crop->stride[2] = src_crop->width >> 1;
src_crop->data[0] = new uint8_t[src_crop->width * src_crop->height * 3 / 2];
src_crop->data[1] = src_crop->data[0] + src_crop->width * src_crop->height;
src_crop->data[2] = src_crop->data[1] + src_crop->width * src_crop->height / 4;
Scaler::LibyuvToI420(src, src_crop, nullptr);
}
libyuv::I420Scale(src_crop->data[0], src_crop->stride[0],
src_crop->data[1], src_crop->stride[1],
src_crop->data[2], src_crop->stride[2],
src_crop->width, src_crop->height,
resize_buf->data[0], resize_buf->stride[0],
resize_buf->data[1], resize_buf->stride[1],
resize_buf->data[2], resize_buf->stride[2],
resize_buf->width, resize_buf->height,
libyuv::FilterMode::kFilterNone);
}
if (dst->color != Scaler::ColorFormat::YUV_I420) {
// i420 covert to dst->color, output to dst->data
if (resize_buf != nullptr) {
Scaler::LibyuvConvertFromI420(resize_buf, dst);
if (src_crop != nullptr) {
delete[] src_crop->data[0];
src_crop->data[0] = nullptr;
delete src_crop;
src_crop = nullptr;
}
delete[] resize_buf->data[0];
delete resize_buf;
resize_buf->data[0] = resize_buf->data[1] = resize_buf->data[2] = nullptr;
resize_buf = nullptr;
return true;
}
if (src_crop == nullptr) {
src_crop = new Scaler::Buffer();
src_crop->color = Scaler::ColorFormat::YUV_I420;
src_crop->width = src->width;
src_crop->height = src->height;
src_crop->stride[0] = src_crop->width;
src_crop->stride[1] = src_crop->stride[2] = src_crop->width >> 1;
src_crop->data[0] = new uint8_t[src_crop->width * src_crop->height * 3 / 2];
src_crop->data[1] = src_crop->data[0] + src_crop->width * src_crop->height;
src_crop->data[2] = src_crop->data[1] + src_crop->width * src_crop->height / 4;
Scaler::LibyuvToI420(src, src_crop, nullptr);
}
Scaler::LibyuvConvertFromI420(src_crop, dst);
if (src_crop != nullptr) {
delete[] src_crop->data[0];
delete src_crop;
src_crop->data[0] = src_crop->data[1] = src_crop->data[2] = nullptr;
src_crop = nullptr;
}
return true;
} else {
if (resize_buf != nullptr) {
memcpy(dst->data[0], resize_buf->data[0], dst->width * dst->height * 3 / 2);
} else {
Scaler::LibyuvToI420(src, dst, nullptr);
}
}
if (src_crop != nullptr) {
delete[] src_crop->data[0];
src_crop->data[0] = src_crop->data[1] = src_crop->data[2] = nullptr;
delete src_crop;
src_crop = nullptr;
}
if (resize_buf != nullptr) {
delete[] resize_buf->data[0];
resize_buf->data[0] = resize_buf->data[1] = resize_buf->data[2] = nullptr;
delete resize_buf;
resize_buf = nullptr;
}
return true;
}
转换成I420
void Scaler::LibyuvToI420(const Buffer *src,
Buffer *dst,
const Rect *crop) {
size_t frame_size = 0;
if (src->color <= Scaler::ColorFormat::YUV_NV12) {
frame_size = src->stride[0] * src->height * 3 / 2;
} else if (src->color <= Scaler::ColorFormat::ARGB) {
frame_size = src->stride[0] * src->height;
}
uint32_t fourcc = Scaler::GetFOURCC(src);
if (crop != nullptr) {
libyuv::ConvertToI420(src->data[0], frame_size,
dst->data[0], dst->stride[0],
dst->data[1], dst->stride[1],
dst->data[2], dst->stride[2],
crop->x, crop->y,
src->width, src->height,
crop->w, crop->h,
libyuv::RotationMode::kRotate0,
fourcc);
} else {
libyuv::ConvertToI420(src->data[0], frame_size,
dst->data[0], dst->stride[0],
dst->data[1], dst->stride[1],
dst->data[2], dst->stride[2],
0, 0,
src->width, src->height,
dst->width, dst->height,
libyuv::RotationMode::kRotate0,
fourcc);
}
}
由I420转成输出格式
void Scaler::LibyuvConvertFromI420(const Buffer *src,
Buffer *dst) {
/*
size_t frame_size = 0;
if (src->color <= Scaler::ColorFormat::YUV_NV12) {
frame_size = src->stride[0] * src->height * 3 / 2;
} else if (src->color <= Scaler::ColorFormat::ARGB) {
frame_size = src->stride[0] * src->height;
}
*/
uint32_t fourcc = Scaler::GetFOURCC(dst);
libyuv::ConvertFromI420(src->data[0], src->stride[0],
src->data[1], src->stride[1],
src->data[2], src->stride[2],
dst->data[0],dst->stride[0],
dst->width, dst->height,
fourcc);
}
因为转成i420中间格式,所以要求图片长宽必须是偶数
标签:src,cvt,crop,height,width,libyuv,data,dst 来源: https://www.cnblogs.com/cyssmile/p/13786225.html