YUV420有很多种格式,此脚本是将 YUV420SP (也可以称为 NV21)格式转换成BMP格式并储存。
最好将脚本与文件路径放在一个盘下,比如我这都在D盘,当文件在C盘,脚本在D盘运行时,会出现无法获取文件名的情况
已经在windows10编译通过
#include
#include
#include
#include
#include
#include
#include
//使用到vector库,下载后添加到环境变量中
//实现yuv420sp(NV21)格式转bmp格式
//可以实现多级文件夹内.yuv文件转同名.bmp文件
//脚本最好与代转换文件夹位于同一级文件目录,跨盘(脚本在C盘,文件夹在D盘)可能会无法搜寻到文件
//此脚本中yuv分辨率为1080p
using namespace std;
#define XSIZE 1920
#define YSIZE 1080
#define RGB_SIZE XSIZE * YSIZE * 3
typedef unsigned char byte;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef int LONG;
#define BITS_PER_PIXCEL 24
#define FORMAT_RGBA 4
#define FORMAT_RGB 3
/** must needed. pack */
#pragma pack(1)
typedef struct
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BMP_FILE_HEADER;
typedef struct{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BMP_INFO_HEADER;
#pragma pack()
//可以实现rgb/rgba转bitmap文件并储存,通过format切换
int rgbaToBmpFile(const char *pFileName, const char* pRgbaData, const int nWidth, const int nHeight, const int format)
{
BMP_FILE_HEADER bmpHeader;
BMP_INFO_HEADER bmpInfo;
FILE* fp = NULL;
char* pBmpSource = NULL;
char* pBmpData = NULL;
int i = 0, j=0;
//4 bytes pack. must be 4 times per line。
int bytesPerLine = (nWidth*BITS_PER_PIXCEL+31)/32*4;
int pixcelBytes = bytesPerLine*nHeight;
bmpHeader.bfType = 0x4D42;
bmpHeader.bfReserved1 = 0;
bmpHeader.bfReserved2 = 0;
bmpHeader.bfOffBits = sizeof(BMP_FILE_HEADER) + sizeof(BMP_INFO_HEADER);
bmpHeader.bfSize = bmpHeader.bfOffBits + pixcelBytes;
bmpInfo.biSize = sizeof(BMP_INFO_HEADER);
bmpInfo.biWidth = nWidth;
/** 这样图片才不会倒置 */
bmpInfo.biHeight = -nHeight;
bmpInfo.biPlanes = 1;
bmpInfo.biBitCount = BITS_PER_PIXCEL;
bmpInfo.biCompression = 0;
bmpInfo.biSizeImage = pixcelBytes;
bmpInfo.biXPelsPerMeter = 100;
bmpInfo.biYPelsPerMeter = 100;
bmpInfo.biClrUsed = 0;
bmpInfo.biClrImportant = 0;
/** convert in memort, then write to file. */
pBmpSource = (char*)malloc(pixcelBytes);
if (!pBmpSource)
{
return -1;
}
/** open file */
fp = fopen(pFileName,"wb+");
if (!fp)
{
return -1;
}
fwrite(&bmpHeader, sizeof(BMP_FILE_HEADER), 1, fp);
fwrite(&bmpInfo, sizeof(BMP_INFO_HEADER), 1, fp);
/** Here you should consider color format. RGBA ? RGB? BGR?
Param format is RGBA, format for file is BGR */
pBmpData = pBmpSource;
for (i=0; i<nHeight; i++)
{
for (j=0; j<nWidth; j++)
{
pBmpData[0] = pRgbaData[2];
pBmpData[1] = pRgbaData[1];
pBmpData[2] = pRgbaData[0];
pRgbaData += format;
pBmpData += FORMAT_RGB;
}
//pack for 4 bytes
pBmpData +=(bytesPerLine - nWidth*FORMAT_RGB);
}
fwrite(pBmpSource, pixcelBytes, 1, fp);
/** close and release。 */
fclose(fp);
free(pBmpSource);
return 0;
}
//isRGB=true时,转换成rgb,false 转换成bgr
void NV212RGBorBGR(const uint8_t *input, int width, int height, uint8_t *output,bool isRGB)
{
int nv_off = width * height;
int i, j, y_index = 0;
int y, u, v;
int r, g, b, nv_index = 0;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++,++y_index) {
nv_index = i / 2 * width + j - j % 2;
y = input[y_index];
u = input[nv_off + nv_index];
v = input[nv_off + nv_index + 1];
r = y + ((351 * (v - 128)) >> 8); //r
g = y - ((179 * (v - 128) + 86 * (u - 128)) >> 8); //g
b = y + ((443 * (u - 128)) >> 8); //b
r = ((r>255) ? 255 : (r<0) ? 0 : r);
g = ((g>255) ? 255 : (g<0) ? 0 : g);
b = ((b>255) ? 255 : (b<0) ? 0 : b);
if (isRGB) {
output[y_index * 3 + 0] = (uint8_t)b;
output[y_index * 3 + 1] = (uint8_t)g;
output[y_index * 3 + 2] = (uint8_t)r;
}
else {
output[y_index * 3 + 0] = (uint8_t)r;
output[y_index * 3 + 1] = (uint8_t)g;
output[y_index * 3 + 2] = (uint8_t)b;
}
}
}
}
int endsWith(string s, string sub) {
return s.rfind(sub) == (s.length() - sub.length()) ? 1 : 0;
}
// 该函数有两个参数,第一个为路径字符串(string类型,最好为绝对路径);
// 第二个参数为文件夹与文件名称存储变量(vector类型,引用传递)。
// 第三个参数 筛选后缀名
bool TraverseDirectory(string path, vector<string>& vec_path, string postfix)
{
__int64 Handle;
struct __finddata64_t FileInfo;
string strFind = path + "\\*";
if ((Handle = _findfirst64(strFind.c_str(), &FileInfo)) == -1L)
{
printf("没有找到匹配的项目\n");
return false;
}
do
{
//判断是否有子目录
if (FileInfo.attrib & _A_SUBDIR)
{
//cout << "有子目录" << endl;
//判断是子文件夹
//下面的判断条件很重要,过滤 . 和 ..
if ((strcmp(FileInfo.name, ".") != 0) && (strcmp(FileInfo.name, "..") != 0))
{
string newPath = path + "\\" + FileInfo.name;
TraverseDirectory(newPath, vec_path, postfix);
}
}
else //判断是文件
{
// cout << "是文件" << endl;
string newPath = path + "\\" + FileInfo.name;
//自定义操作
if (postfix.size() == 0 || (postfix.size() > 0 && endsWith(newPath, postfix) && (postfix.c_str(), strchr(newPath.c_str(), '.'))))
vec_path.push_back(newPath);
}
} while (_findnext64(Handle, &FileInfo) == 0);
_findclose(Handle);
return true;
}
int main(){
int i, j, y, x;
int idx = 0;
long width, height;
unsigned char *image; //用于存放读取的yuv数据
unsigned char *image_rgb;
width = XSIZE;
height = YSIZE;
long int bytePerLine = width * 3;
string bmp_filename;
string filename;
//申请空间
image = (unsigned char *)malloc(width * height * 3 / 2);
image_rgb = (unsigned char *)malloc(width * height * 3);
if ((NULL == image) || (image_rgb == NULL))
{
printf("faied to malloc the image\n");
return -1;
}
//获取文件名,获取路径下下所有后缀名为.yuv的文件名
string filePath = "D:\\Code\\c\\imatest";
vector<string> files;
TraverseDirectory(filePath, files, ".yuv");
//循环打开所有.yuv文件并在同级目录下转换成.bmp
for ( ; idx < files.size(); idx++)
{
FILE *fp_r;
//读取yuv 文件
fp_r = fopen(files[idx].c_str(), "rb"); //打开yuv 文件
if (NULL == fp_r)
{
printf("failed to open the fp_r\n");
return -1;
}
//将文件数据读到image buffer中
fread(image, sizeof(unsigned char), XSIZE * YSIZE * 3 / 2, fp_r);
fclose(fp_r);
//提取文件名并修改成.bmp后缀
filename = strtok((char *)files[idx].c_str(),(char *)".yuv") ;
bmp_filename = filename + ".bmp";
//将NV21转换成RGB
NV212RGBorBGR(image,width,height,image_rgb,true);
//将RGB转换成bmp
int result = rgbaToBmpFile(bmp_filename.c_str(),(const char*)image_rgb,width,height , FORMAT_RGB);
if(result == 0){
cout << filename + ".yuv" << "==============>" + bmp_filename <<endl;
}else{
cout << "文件: "<< filename + ".yuv" << "转换失败" <<endl;
}
}
//释放空间
free(image);
free(image_rgb);
return(0);
}
编译 :
g++ yuvsp2bmp.cpp -o yuvsp2bmp