libyuv是Google开源的实现各种YUV与RGB之间相互转换、旋转、缩放的库。
https://github.com/lemenkov/libyuv
下载,cmaker Project.sln工程,重新编译,即可生成libyuv.lib 静态库;
编译好的库:https://download.csdn.net/download/shuilan0066/10665172
导入这个库
在linker->General->Additional Library Directiories 添加libyuv.lib的目录
linker->Input->Additonal Dependencies 添加libyuv_d.lib (debug环境下)
如果是在一个工程中使用
在c/C++->General->Additional Include Directories 添加libyuv的include目录
如果是一个模块工程,比如静态库模块工程中使用
则同样在主工程中添加lib目录、添加.lib
在静态库模块中添加添加libyuv的include目录,在静态库模块中调用
使用这个库
#include "libyuv.h"
1)ARGBToYUV420
ARGBToYUV420(char* src, char* dst, int width, int height)
{
int byte_width = width * 4;
width -= width % 2;
height -= height % 2;
int wxh = width * height;
uint8_t* des_y = (uint8_t*)dst;
uint8_t* des_u = des_y + wxh;
uint8_t* des_v = des_u + wxh / 4;
// libyuv::RGB24ToI420((const uint8*)src, byte_width,
// des_y, width,
// des_u, width / 2,
// des_v, width / 2,
// width, height);
libyuv::ARGBToI420((const uint8_t*)src, byte_width,
des_y, width,
des_u, width / 2,
des_v, width / 2,
width, height);
}
2)YUV420ToARGB
YUV420ToARGB(char* src, char* dst, int width, int height)
{
uint8_t* src_y = (uint8_t*)src;
uint8_t* src_u = src_y + width * height;
uint8_t* src_v = src_u + width * height / 4;
// libyuv::I420ToRGB24(
// src_y, width,
// src_u, width / 2,
// src_v, width / 2,
// (uint8_t*)dst, width * 3,
// width, height);
libyuv::I420ToARGB(
src_y, width,
src_u, width / 2,
src_v, width / 2,
(uint8_t*)dst, width * 4,
width, height);
}
示例:
std::string argbData;
argbData.resize(width*height * 4);
YUV420ToARGB((char*)data, (char*)argbData.c_str(), width, height);
ARGBToYUV420((char*)argbData.c_str(), (char*)yuvData, width, height);
3) I420CopyEx
CopyI420Data(int type, std::string& dest, const std::string& src, int width, int height, ImageYuvDataType image_type, POINT pt)
{
int left = (width_ - width) / 2;
left -= left % 2;
int top = (height_ - height) / 2;
top -= top % 2;
switch (type)
{
case SIZENW:
{
left = pt.x;
top = pt.y;
break;
}
case SIZENE:
{
left = width_ - width - pt.x;
left -= left % 2;
top = pt.y;
break;
}
case SIZESW:
{
left = pt.x;
top = height_ - height - pt.y;
top -= top % 2;
break;
}
case SIZESE:
{
left = width_ - width - pt.x;
left -= left % 2;
top = height_ - height - pt.y;
top -= top % 2;
break;
}
default:
break;
}
if (left < 0)
left = 0;
if (top < 0)
top = 0;
int stride_y = width;
int stride_u = width / 2;
int stride_v = width / 2;
int stride_ya = 0;
int stride_ua = 0;
int stride_va = 0;
if (image_type == kYuvDataTypeImage || image_type == kYuvDataTypeImageAlpha)
{
stride_y *= 2;
stride_u *= 2;
stride_v *= 2;
if (image_type == kYuvDataTypeImageAlpha)
{
stride_ya = stride_y;
stride_ua = stride_u;
stride_va = stride_v;
}
}
uint8_t* src_y = (uint8_t*)src.c_str();
uint8_t* src_u = src_y + stride_y * height;
uint8_t* src_v = src_u + stride_u * height / 2;
uint8_t* des_y = (uint8_t*)dest.c_str();
uint8_t* des_u = des_y + width_ * height_;
uint8_t* des_v = des_u + width_ * height_ / 4;
des_y += left + top * width_;
des_u += left / 2 + top * width_ / 4;
des_v += left / 2 + top * width_ / 4;
I420CopyEx(src_y, stride_y, src_y + width, stride_ya,
src_u, stride_u, src_u + width / 2, stride_ua,
src_v, stride_v, src_v + width / 2, stride_va,
des_y, width_,
des_u, width_ / 2,
des_v, width_ / 2,
width, height);
}
示例:
static char clr_temp = 0x80;
nbase::NAutoLock auto_lock(&lock_);
int size = width_ * height_ * 3 / 2;
std::string data_ret; //要生成的视频帧数据
data_ret.append(size, (char)clr_temp); //默认黑色 1000 0000 不透明
在此视频帧上拷贝其它I420数据
std::string data_temp; //临时数据
data_temp.append(size, (char)clr_temp);
//得到采集的数据,并将其拷贝到背景画布数据中
if (capture_.GetFrame()->GetVideoFrame("", time, (char*)data_temp.c_str(), width, height, false, false))
{
CopyI420Data(SIZEALL, data_ret, data_temp, width, height);
frame_show = true;
}