NvBufSurface保存了图像信息,是硬件内存,怎么将硬件内存保存到本地文件?NvBufSurface的memorytype有很多种,类型不一样,获取的方式也不一样,今天主要说的是DGPU上的NVBUF_MEM_CUDA_DEVICE类型。如下是nvidia支持的内存类型。
typedef enum
{
/** Specifies the default memory type, i.e. \ref NVBUF_MEM_CUDA_DEVICE
for dGPU, \ref NVBUF_MEM_SURFACE_ARRAY for Jetson. Use \ref NVBUF_MEM_DEFAULT
to allocate whichever type of memory is appropriate for the platform. */
NVBUF_MEM_DEFAULT,
/** Specifies CUDA Host memory type. */
NVBUF_MEM_CUDA_PINNED,
/** Specifies CUDA Device memory type. */
NVBUF_MEM_CUDA_DEVICE,
/** Specifies CUDA Unified memory type. */
NVBUF_MEM_CUDA_UNIFIED,
/** Specifies NVRM Surface Array type. Valid only for Jetson. */
NVBUF_MEM_SURFACE_ARRAY,
/** Specifies NVRM Handle type. Valid only for Jetson. */
NVBUF_MEM_HANDLE,
/** Specifies memory allocated by malloc(). */
NVBUF_MEM_SYSTEM,
} NvBufSurfaceMemType;
保存图片的流程主要是用cudaMemcpy将Device内存拷贝到CPU内存,再根据颜色格式,保存到本地文件。代码如下,支持nv12/rgba/rgb格式的保存。
void
save_nv12(char* src, int width, int height, int pitch, FILE* fp)
{
for (int i = 0;i < height;i++)
{
fwrite(src, 1, width, fp);
src += pitch;
}
for (int i = 0;i < height / 2;i++)
{
fwrite(src, 1, width, fp);
src += pitch;
}
}
void
save_rgba(char* src, int width, int height, int pitch, FILE* fp)
{
int datalen = width * 4;
for (int i = 0;i < height;i++) {
fwrite(src, 1, datalen, fp);
src += pitch;
}
}
void
save_rgb(char* src, int width, int height, int pitch, FILE* fp)
{
int datalen = width * 3;
for (int i = 0;i < height;i++) {
fwrite(src, 1, datalen, fp);
src += pitch;
}
}
int
save_NvBufSurface(NvBufSurface * surface, char* filename)
{
int nRst = 0;
char* src_data = NULL;
NvBufSurfaceColorFormat colorFormat;
int width, height, dataSize, pitch;
char full_filename[256] = {0};
for (uint32_t i = 0; i < surface->batchSize; i++) {
colorFormat = surface->surfaceList[i].colorFormat;
width = surface->surfaceList[i].width;
height = surface->surfaceList[i].height;
dataSize = surface->surfaceList[i].dataSize;
pitch = surface->surfaceList[i].pitch;
//printf("colorFormat:%d, w:%d,h:%d,size:%d, pitch:%d\n", colorFormat, width, height, dataSize, pitch);
if(colorFormat == NVBUF_COLOR_FORMAT_NV12){
sprintf(full_filename,"%s_%d.yuv", filename, i);
} else if (colorFormat == NVBUF_COLOR_FORMAT_RGBA){
sprintf(full_filename,"%s_%d.rgb", filename, i);
} else if (colorFormat == NVBUF_COLOR_FORMAT_RGB){
sprintf(full_filename,"%s_%d.rgb", filename, i);
}
//save data to file.
FILE* fp = fopen(full_filename, "wb");
if(!fp) {
printf("fopen %s failed\n", full_filename);
return -1;
}
src_data = (char*) malloc(dataSize);
if(!src_data){
fclose(fp);
fp = NULL;
printf("mallloc failed\n");
return -1;
}
cudaMemcpy((void*)src_data, (void*)surface->surfaceList[i].dataPtr, dataSize, cudaMemcpyDeviceToHost);
if(colorFormat == NVBUF_COLOR_FORMAT_NV12){
save_nv12(src_data, width, height, pitch, fp);
} else if (colorFormat == NVBUF_COLOR_FORMAT_RGBA){
save_rgba(src_data, width, height, pitch, fp);
} else if (colorFormat == NVBUF_COLOR_FORMAT_RGB){
save_rgb(src_data, width, height, pitch, fp);
}
fclose(fp);
fp = NULL;
free(src_data);
src_data = NULL;
}
return nRst;
}
sample:
static int n = 0;
char sbuf[32] = {0};
sprintf(sbuf, "%d", n);
if(n++ % 300 == 0)
save_NvBufSurface(surface, sbuf);
保存的数据是原始数据,可以用ffplay进行预览。命令如下:
ffplay -pixel_format nv12 -s 1920x1080 1.yuv
ffplay -pixel_format rgba -s 1920x1080 1.rgb
存成一个文件
int
save_NvBufSurface(NvBufSurface * surface, char* filename)
{
int nRst = 0;
char* src_data = NULL;
NvBufSurfaceColorFormat colorFormat;
int width, height, dataSize, pitch;
char full_filename[256] = {0};
for (uint32_t i = 0; i < surface->batchSize; i++) {
colorFormat = surface->surfaceList[i].colorFormat;
width = surface->surfaceList[i].width;
height = surface->surfaceList[i].height;
dataSize = surface->surfaceList[i].dataSize;
pitch = surface->surfaceList[i].pitch;
//printf("colorFormat:%d, w:%d,h:%d,size:%d, pitch:%d\n", colorFormat, width, height, dataSize, pitch);
if(colorFormat == NVBUF_COLOR_FORMAT_NV12){
sprintf(full_filename,"%s.yuv", filename);
} else if (colorFormat == NVBUF_COLOR_FORMAT_RGBA){
sprintf(full_filename,"%s.rgb", filename);
} else if (colorFormat == NVBUF_COLOR_FORMAT_RGB){
sprintf(full_filename,"%s.rgb", filename);
}
//save data to file.
FILE* fp = fopen(full_filename, "ab+");
if(!fp) {
printf("fopen %s failed\n", full_filename);
return -1;
}
src_data = (char*) malloc(dataSize);
if(!src_data){
fclose(fp);
fp = NULL;
printf("mallloc failed\n");
return -1;
}
cudaMemcpy((void*)src_data, (void*)surface->surfaceList[i].dataPtr, dataSize, cudaMemcpyDeviceToHost);
if(colorFormat == NVBUF_COLOR_FORMAT_NV12){
save_nv12(src_data, width, height, pitch, fp);
} else if (colorFormat == NVBUF_COLOR_FORMAT_RGBA){
save_rgba(src_data, width, height, pitch, fp);
} else if (colorFormat == NVBUF_COLOR_FORMAT_RGB){
save_rgb(src_data, width, height, pitch, fp);
}
fclose(fp);
fp = NULL;
free(src_data);
src_data = NULL;
}
return nRst;
}
用法:
static int n = 0;
char sbuf[32] = {0};
sprintf(sbuf, "%d", n);
save_NvBufSurface(&nvdspreprocess->batch_outsurf, sbuf);