NV12图像存储格式:
YUV转RGBA
typedef struct
{
int width;
int height;
unsigned char *pY;
unsigned char *pUv;
char *pRgb;
}t_workThreadData;
void ConvertYuv420SPToRgbV6ForThread(unsigned char* pYuvBuff, unsigned char* pUv, char* pRgbBuff, int imgWidth, int imgHeight)
{
int r,g,b;
int y,u,v;
int rowIdx = 0, colIdx = 0;
if (imgWidth < 1 || imgHeight < 1 || pYuvBuff == NULL || pRgbBuff == NULL)
return ;
unsigned char* yData = pYuvBuff;
unsigned char* uvData = pUv;
int rowOffset = 0;
int tmp298Y = 0;
int yIdx,uvIdx;
PRINT_VAAPI_LOG("Convert: w:%d, h:%d\n", imgWidth, imgHeight);
for (rowIdx = 0; rowIdx < imgHeight; rowIdx++){ //height
rowOffset = rowIdx * imgWidth;
for (colIdx = 0; colIdx < imgWidth; colIdx++){ //width
yIdx = rowOffset + colIdx;
uvIdx = (rowIdx>>1) * imgWidth + (colIdx>>1<<1);
y = yData[yIdx];
u = uvData[uvIdx];
v = uvData[uvIdx+1];
tmp298Y = 298*y;
r = (tmp298Y + 411*v - 57344) >> 8;
g = (tmp298Y - 101*u - 211*v + 34739) >> 8;
b = (tmp298Y + 519*u - 71117) >> 8;
if(r > 255) {
r = 255;
}
if(r < 0) {
r = 0;
}
if(g > 255) {
g = 255;
}
if(g < 0) {
g = 0;
}
if(b > 255) {
b = 255;
}
if(b < 0) {
b = 0;
}
pRgbBuff[4*yIdx] = b;
pRgbBuff[4*yIdx+1] = g;
pRgbBuff[4*yIdx+2] = r;
pRgbBuff[4*yIdx+3] = 255;
}
}
}
void* workThreadForYuvConvert(void* argv)
{
t_workThreadData* pThreadData = (t_workThreadData*)argv;
ConvertYuv420SPToRgbV6ForThread(pThreadData->pY, pThreadData->pUv, pThreadData->pRgb, pThreadData->width, pThreadData->height);
return NULL;
}
void AssignThreadForYuvConvert(int threadCount, unsigned char* pYuvBuff, char* pRgbBuff, int imgWidth, int imgHeight) {
int partHeight = 0;
int i = 0;
t_workThreadData *pThreadData = NULL;
pthread_t *pThreadId = NULL;
unsigned char* uvData = &pYuvBuff[imgWidth * imgHeight];
//Ensure threadCount is 2^n!
if ((threadCount&(threadCount - 1))) {
return;
}
pThreadData = malloc(threadCount * sizeof(t_workThreadData));
pThreadId = malloc(threadCount * sizeof(t_workThreadData));
partHeight = imgHeight / threadCount;
for (i = 0; i < threadCount; i++) {
pThreadData[i].height = partHeight;
pThreadData[i].width = imgWidth;
pThreadData[i].pY = pYuvBuff + i * partHeight * imgWidth;
pThreadData[i].pUv = uvData + i * (partHeight>>1) * imgWidth;
pThreadData[i].pRgb = pRgbBuff + ((i * partHeight * imgWidth) << 2);
pthread_create(&pThreadId[i],NULL,workThreadForYuvConvert,(void*)&pThreadData[i]);
}
for (i = 0; i < threadCount; i++) {
pthread_join(pThreadId[i], NULL);
}
free(pThreadData);
free(pThreadId);
}
RGBA转YUV
typedef struct
{
int width;
int height;
unsigned char *pY;
unsigned char *pUv;
char *pRgb;
}t_workThreadData;
void rgb_convert_yuv(unsigned char* pYuvBuff, unsigned char* pUv, char* pRgbBuff, int imgWidth, int imgHeight)
{
int r,g,b;
int y,u,v;
int rowIdx = 0, colIdx = 0;
if (imgWidth < 1 || imgHeight < 1 || pYuvBuff == NULL || pRgbBuff == NULL)
return ;
unsigned char* yData = pYuvBuff;
unsigned char* uvData = pUv;
int rowOffset = 0;
int yIdx,uvIdx = 0;
PRINT_VAAPI_LOG("Convert: w:%d, h:%d\n", imgWidth, imgHeight);
for (rowIdx = 0; rowIdx < imgHeight; rowIdx++){ //height
rowOffset = rowIdx * imgWidth;
for (colIdx = 0; colIdx < imgWidth; colIdx++){ //width
yIdx = rowOffset + colIdx;
uvIdx = (rowIdx>>1) * imgWidth + (colIdx>>1<<1);
b = pRgbBuff[4*yIdx];
g = pRgbBuff[4*yIdx+1];
r = pRgbBuff[4*yIdx+2];
y = ((66*r + 129*g + 25*b) >> 8) + 16;
u = ((-38*r - 74*g + 112*b) >> 8) + 128;
v = ((112*r - 94*g - 18*b) >> 8) + 128;
if(y < 16) {
y = 16;
}
if(y > 235) {
y = 235;
}
if(u < 16) {
u = 16;
}
if(u > 240) {
u = 240;
}
if(v < 16) {
v = 16;
}
if(v > 240) {
v = 240;
}
yData[yIdx] = y;
uvData[uvIdx] = u;
uvData[uvIdx+1] = v;
}
}
}
void* workThreadForRGBConvert(void* argv)
{
t_workThreadData* pThreadData = (t_workThreadData*)argv;
rgb_convert_yuv(pThreadData->pY, pThreadData->pUv, pThreadData->pRgb, pThreadData->width, pThreadData->height);
return NULL;
}
void AssignThreadForRGBConvert(int threadCount, unsigned char* pYuvBuff, char* pRgbBuff, int imgWidth, int imgHeight) {
int partHeight = 0;
int i = 0;
t_workThreadData *pThreadData = NULL;
pthread_t *pThreadId = NULL;
unsigned char* uvData = &pYuvBuff[imgWidth * imgHeight];
//Ensure threadCount is 2^n!
if ((threadCount&(threadCount - 1))) {
return;
}
pThreadData = malloc(threadCount * sizeof(t_workThreadData));
pThreadId = malloc(threadCount * sizeof(pthread_t));
partHeight = imgHeight / threadCount;
for (i = 0; i < threadCount; i++) {
pThreadData[i].height = partHeight;
pThreadData[i].width = imgWidth;
pThreadData[i].pY = pYuvBuff + i * partHeight * imgWidth;
pThreadData[i].pUv = uvData + i * (partHeight>>1) * imgWidth;
pThreadData[i].pRgb = pRgbBuff + ((i * partHeight * imgWidth) << 2);
pthread_create(&pThreadId[i],NULL,workThreadForRGBConvert,(void*)&pThreadData[i]);
}
for (i = 0; i < threadCount; i++) {
pthread_join(pThreadId[i], NULL);
}
free(pThreadData);
free(pThreadId);
}
RGBA缩放
理论依据:https://blog.csdn.net/qq_37756660/article/details/133874378
/* nearest neighbor interpolation */
int image_scale_v2(u8 *src_rgba, u8 * dst_rgba, int src_w, int src_h, int dst_w, int dst_h)
{
//scale up or down ratio
float ratio_w = (float)src_w / (float)dst_w;
float ratio_h = (float)src_h / (float)dst_h;
int x0, y0;
unsigned int src_pix_idx, dst_pix_idx;
for(int dst_y = 0; dst_y < dst_h; dst_y++) {
for(int dst_x = 0; dst_x < dst_w; dst_x++) {
// coordinate map from dst to src
x0 = (float)dst_x * ratio_w;
y0 = (float)dst_y * ratio_h;
/* pixel index */
dst_pix_idx = (dst_y * dst_w + dst_x) << 2;
src_pix_idx = (y0 * src_w + x0) << 2;
// compute dst rgba piexl, b g r a
// for(int i = 0; i < 4; i++) {
// /* nearest neighbor interpolation */
// dst_rgba[dst_pix_idx + i] = src_rgba[src_pix_idx + i];
// }
/* vectorized */
uint8x8_t src_vec8x8 = vld1_u8(src_rgba+src_pix_idx);
vst1_u8(dst_rgba+dst_pix_idx, src_vec8x8);
}
}
}
/* bilinear interpolation */
int image_scale_v1(u8 *src_rgba, u8 * dst_rgba, int src_w, int src_h, int dst_w, int dst_h)
{
//scale up or down ratio
float ratio_w = (float)src_w / (float)dst_w;
float ratio_h = (float)src_h / (float)dst_h;
float src_x, src_y, dealt_x, dealt_y;
int x0, y0;
float k0, k1, k2, k3;
unsigned int src_pix_idx, dst_pix_idx, src_pix_idx_y_next;
for(int dst_y = 0; dst_y < dst_h; dst_y++) {
for(int dst_x = 0; dst_x < dst_w; dst_x++) {
// coordinate map from dst to src
src_x = (float)dst_x * ratio_w;
src_y = (float)dst_y * ratio_h;
// the nearest src coordinate after map
x0 = (int)src_x;
y0 = (int)src_y;
/* pixel index */
dst_pix_idx = 4 * (dst_y * dst_w + dst_x);
src_pix_idx = 4 * (y0 * src_w + x0);
src_pix_idx_y_next = 4*((y0+1)*src_w + x0);
// the weight of around four coordinate pixel
dealt_x = (src_x - (float)x0);
dealt_y = (src_y - (float)y0);
k0 = dealt_x * dealt_y;
k1 = (1.0 - dealt_x) * dealt_y;
k2 = dealt_x * (1.0 - dealt_y);
k3 = (1.0 - dealt_x) * (1.0 - dealt_y);
// compute dst rgba piexl, b g r a
for(int i = 0; i < 4; i++) {
/* bilinear interpolation */
dst_rgba[dst_pix_idx + i] = k3 * src_rgba[src_pix_idx + i] +
k2 * src_rgba[src_pix_idx + i + 4] +
k1 * src_rgba[src_pix_idx_y_next + i] +
k0 * src_rgba[src_pix_idx_y_next + i + 4];
}
}
}
return 0;
}
void *workThreadForImageScale(void *argv)
{
pthread_data *thread_data = (pthread_data *)argv;
image_scale_v1(thread_data->pRgbBuffSrc, thread_data->pRgbBuffDst,
thread_data->src_w, thread_data->src_h,
thread_data->dst_w, thread_data->dst_h);
return NULL;
}
void AssignThreadForImageScale(char *pRgbBuffSrc, char *pRgbBuffDst,
int width, int height,
int winWidth, int winHeight)
{
if(pRgbBuffSrc == NULL || pRgbBuffDst == NULL) {
return;
}
pthread_t *thread_id = NULL;
pthread_data *thread_data = NULL;
int thread_count = 4;
int part_height_src = height / thread_count;
int part_height_dst = winHeight / thread_count;
thread_id = malloc(thread_count * sizeof(pthread_t));
thread_data = malloc(thread_count * sizeof(pthread_data));
for(int i = 0; i < thread_count; i++) {
thread_data[i].pRgbBuffSrc = pRgbBuffSrc + i * part_height_src * width * 4;
thread_data[i].pRgbBuffDst = pRgbBuffDst + i * part_height_dst * winWidth * 4;
thread_data[i].src_w = width;
thread_data[i].src_h = part_height_src;
thread_data[i].dst_w = winWidth;
thread_data[i].dst_h = part_height_dst;
pthread_create(&thread_id[i], NULL, workThreadForImageScale, (void *)&thread_data[i]);
}
for(int i = 0; i < thread_count; i++) {
pthread_join(thread_id[i], NULL);
}
free(thread_id);
free(thread_data);
return;
}