NV12
一個6*4的nv12格式的圖檔的三個分量YUV的記憶體形式:
雖然nv12的像素大小是width*height,但是必須為nv12圖檔配置設定width*height*3/2的記憶體空間,因為Y分量所占的記憶體為width*height,而U,V分量各占width*height/4,見上圖即一目了然。
nv12分量YUV分量記憶體操作:可以用雙重for循環周遊nv12各個分量的記憶體分布,進而實作給nv12圖檔賦予不同的顔色。
由記憶體YUV分量記憶體分布圖可以知道:
0 ~ width*height 為Y分量存儲的記憶體範圍。
width*height ~ width*height*3/2 為UV交叉存儲的記憶體範圍。
操作Y分量:
buf[j * width + k]
操作U分量 :
buf[j / 2 * width + k - k % 2 + width * height]
操作V分量 :
buf[j / 2 * width + k - k % 2 + width * height + 1]
在nv12格式的圖檔上畫一個鎖定某個目标的矩形方框圖
#include <stdio.h>
#include <stdlib.h>
int nv12_border(char *pic, int pic_w, int pic_h, int rect_x, int rect_y, int rect_w, int rect_h, int R, int G, int B);
int main()
{
/* Set up the nv12's pixel size */
const int pic_w = ;
const int pic_h = ;
/* Set up test data's path and output data's path */
char *inputPathname = "/home/flypei/work/nv12-marked-rect/data/videotestsrc_1920x1080.nv12";
char *outputPathname = "./outputFile.nv12";
FILE *fin = fopen(inputPathname , "rb+");
FILE *fout = fopen(outputPathname, "wb+");
/* Allocate memory for nv12 */
unsigned char *buf = (unsigned char *)malloc(pic_w * pic_h * / );
/* Read file data to buffer */
fread(buf, , pic_w * pic_h * / , fin);
/* Draw rectangle border to nv12 */
nv12_border(buf, pic_w, pic_h, , , , , , , );
/* Write data of buf to fout */
fwrite(buf, , pic_w * pic_h * / , fout);
/* Free the allocation memory */
free(buf);
/* Close the file */
fclose(fin);
fclose(fout);
return ;
}
int nv12_border(char *pic, int pic_w, int pic_h, int rect_x, int rect_y, int rect_w, int rect_h, int R, int G, int B)
{
/* Set up the rectangle border size */
const int border = ;
/* RGB convert YUV */
int Y, U, V;
Y = * R + * G + * B;
U = - * R + * G + * B + ;
V = * R - * G - * B + ;
/* Locking the scope of rectangle border range */
int j, k;
for(j = rect_y; j < rect_y + rect_h; j++){
for(k = rect_x; k < rect_x + rect_w; k++){
if (k < (rect_x + border) || k > (rect_x + rect_w - border) ||\
j < (rect_y + border) || j > (rect_y + rect_h - border)){
/* Components of YUV's storage address index */
int y_index = j * pic_w + k;
int u_index = (y_index / - pic_w / * ((j + ) / )) * + pic_w * pic_h;
int v_index = u_index + ;
/* set up YUV's conponents value of rectangle border */
pic[y_index] = Y ;
pic[u_index] = U ;
pic[v_index] = V ;
}
}
}
return ;
}
原nv12圖檔(用yuvplayer檢視):
加上方框的nv12圖檔(用yuvplayer檢視):
demo優化版
#include <stdio.h>
#include <stdlib.h>
#define uchar unsigned char
typedef struct rectangle{
int x;
int y;
int w;
int h;
uchar thin;
uchar YUV[];
}RECT;
void RgbToYuv(uchar RGB[], uchar YUV[]);
void FindAxis(RECT rect[], int n, int rect_all_axis[]);
void DrawWidthLine(uchar* pic, int pic_w, int pic_h, RECT rect[], int n, int axis[]);
void DrawHeightLine(uchar* pic, int pic_w, int pic_h, RECT rect[], int n, int axis[]);
void DrawPoint(uchar* pic, int pic_w, int pic_h, int point_axis[], int count, uchar YUV[]);
void NV12MarkRect(uchar* pic, int pic_w, int pic_h, RECT rect[], int n, int point_axis[], int count);
int main()
{
/*****************************************************/
/**** ****/
/**** Configure Parameter ****/
/**** ****/
/*****************************************************/
/* Config the nv12's pixel size */
const int pict_w = ;
const int pict_h = ;
int picSize = pict_w * pict_h * ;
/* Allocate memory for nv12 */
uchar* picBuf = (unsigned char *)malloc(picSize);
/* RGB convert to YUV */
uchar RGBblue[] = {, , };
uchar YUVblue[];
RgbToYuv(RGBblue, YUVblue);
/* Config rectangle's quanlity and parameter */
int n = ;
uchar t = ;
RECT Rect[] = {
{
.x = ,
.y = ,
.w = ,
.h = ,
.thin = t,
.YUV[] = YUVblue[],
.YUV[] = YUVblue[],
.YUV[] = YUVblue[] },
{
.x = ,
.y = ,
.w = ,
.h = ,
.thin = t,
.YUV[] = YUVblue[],
.YUV[] = YUVblue[],
.YUV[] = YUVblue[] }
};
/* Config point axis's count and draw the point at NV12 */
int c = ;
int point[] = { ,, ,, ,, ,, ,, ,, ,, ,, ,, ,,
,, ,, ,, ,, ,, ,, ,, ,, ,, ,,
,, ,, ,, ,, ,, ,, ,, ,, ,, , };
/* Config input and output path */
char input[] = "videotestsrc_1920x1080.nv12";
char output[] = "outputFile.nv12";
/******************************************************/
FILE *fin = fopen(input, "rb");
FILE *fout = fopen(output, "wb+");
/* Read file data to buffer */
fread(picBuf, , picSize, fin);
/* Draw rectangle and point to nv12 */
NV12MarkRect(picBuf, pict_w, pict_h, Rect, n, point, c);
/* Write data of buf to fout */
fwrite(picBuf, , picSize, fout);
/* Free the allocation memory */
free(picBuf);
/* Close the file */
fclose(fin);
fclose(fout);
return ;
}
void RgbToYuv(uchar RGB[], uchar YUV[])
{
/* RGB convert YUV */
YUV[] = * RGB[] + * RGB[] + * RGB[];
YUV[] = - * RGB[] + * RGB[] + * RGB[] + ;
YUV[] = * RGB[] - * RGB[] - * RGB[] + ;
}
void FindAxis(RECT rect[], int n, int axis[])
{
axis[] = axis[] = axis[] = rect[n].x;
axis[] = rect[n].x + rect[n].w - rect[n].thin;
axis[] = rect[n].y;
axis[] = rect[n].y + rect[n].h - rect[n].thin;
axis[] = axis[] = rect[n].y + rect[n].thin;
}
void DrawWidthLine(uchar* pic, int pic_w, int pic_h, RECT rect[], int n, int axis[])
{
int i, j, k;
int y_index, u_index, v_index;
for (i = ; i < ; i += ){
for (j = axis[i+]+rect[n].thin-; j >= axis[i+]; j--){
for (k = axis[i]+rect[n].w-; k >= axis[i]; k--){
y_index = j * pic_w + k;
u_index = ((j >> ) + pic_h) * pic_w + k - (k & );
//u_index = (((y_index >> 1) - (pic_w >> 1) * ((j + 1) >> 1)) << 1) + pic_w * pic_h;
v_index = u_index + ;
pic[y_index] = rect[n].YUV[];
pic[u_index] = rect[n].YUV[];
pic[v_index] = rect[n].YUV[];
}
}
}
}
void DrawHeightLine(uchar* pic, int pic_w, int pic_h, RECT rect[], int n, int axis[])
{
int i, j, k;
int y_index, u_index, v_index;
for (i = ; i < ; i += ){
for (k = axis[i]+rect[n].thin-; k >= axis[i]; k--){
for (j = axis[i+]+rect[n].h-(*rect[n].thin)-; j >= axis[i+]; j--){
y_index = j * pic_w + k;
u_index = ((j >> ) + pic_h) * pic_w + k - (k & );
//u_index = (((y_index >> 1) - (pic_w >> 1) * ((j + 1) >> 1)) << 1) + pic_w * pic_h;
v_index = u_index + ;
pic[y_index] = rect[n].YUV[];
pic[u_index] = rect[n].YUV[];
pic[v_index] = rect[n].YUV[];
}
}
}
}
void DrawPoint(uchar* pic, int pic_w, int pic_h, int point_axis[], int count, uchar YUV[])
{
/* Draw points at NV12 */
int a, y_point, u_point, v_point;
for (a = (count-)*; a >= ; a -= ){
y_point = point_axis[a+] * pic_w + point_axis[a];
u_point = ((point_axis[a+] >> ) + pic_h) * pic_w + point_axis[a] - (point_axis[a] & );
//u_point = (((y_point >> 1) - (pic_w >> 1) * ((point_axis[a+1] + 1) >> 1)) << 1) + pic_w * pic_h;
v_point = u_point + ;
pic[y_point] = YUV[];
pic[u_point] = YUV[];
pic[v_point] = YUV[];
}
}
void NV12MarkRect(uchar* pic, int pic_w, int pic_h, RECT rect[], int num, int point_axis[], int count)
{
int i;
int axis[];
for (i = num-; i >= ; i--){
FindAxis(rect, i, axis);
DrawWidthLine(pic, pic_w, pic_h, rect, i, axis);
DrawHeightLine(pic, pic_w, pic_h, rect, i, axis);
}
DrawPoint(pic, pic_w, pic_h, point_axis, count, rect[].YUV);
}