Is there a C example for saving images to disk instead of Cpp ? I tried modifying the deepstream_app.c to save JPEG, but I get an image with white pixels(see attached). What am I doing wrong here ?
I am running this on NVIDIA Xavier with a CSI Camera
int write_jpeg_file( char *filename, unsigned char* rgb_image , int width, int height, int bytes_per_pixel, J_COLOR_SPACE color_space )
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW row_pointer[1];
FILE *outfile = fopen( filename, "wb" );
if ( !outfile )
{
printf("Error opening output jpeg file %s\n!", filename );
return -1;
}
cinfo.err = jpeg_std_error( &jerr );
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = bytes_per_pixel;
cinfo.in_color_space = color_space; //JCS_RGB
jpeg_set_defaults( &cinfo );
jpeg_start_compress( &cinfo, TRUE );
while( cinfo.next_scanline < cinfo.image_height )
{
row_pointer[0] = &rgb_image[ cinfo.next_scanline * cinfo.image_width * cinfo.input_components];
jpeg_write_scanlines( &cinfo, row_pointer, 1 );
}
jpeg_finish_compress( &cinfo );
jpeg_destroy_compress( &cinfo );
fclose( outfile );
return 1;
}
/**
* Function which processes the inferred buffer and its metadata.
* It also gives opportunity to attach application specific
* metadata (e.g. clock, analytics output etc.).
*/
static void
process_buffer (GstBuffer * buf, AppCtx * appCtx, guint index)
{
NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta (buf);
NvDsMetaList *l_frame = NULL;
NvDsMetaList *l_obj = NULL;
NvDsMetaList * l_user_meta = NULL;
NvDsDisplayMeta *display_meta = NULL;
NvDsObjectMeta *obj_meta = NULL;
//g_print("getting original raw data");
// Get original raw data
GstMapInfo in_map_info;
char* src_data = NULL;
memset (&in_map_info, 0, sizeof (in_map_info));
if (!gst_buffer_map (buf, &in_map_info, GST_MAP_READ)) {
g_print ("Error: Failed to map gst buffer\n");
gst_buffer_unmap (buf, &in_map_info);
return;
}
NvBufSurface *surface = (NvBufSurface *)in_map_info.data;
int imgpix=0;
int txtstep;
unsigned char *totalpix;
char *totalpix1;
unsigned int *totalpix2;
long unsigned int *totalpix3;
//g_print("loaded surface");
if (!batch_meta) {
NVGSTDS_WARN_MSG_V ("Batch meta not found for buffer %p", buf);
return;
}
process_meta (appCtx, batch_meta);
NvDsInstanceData *data = &appCtx->instance_data[index];
guint i;
data->frame_num++;
for (l_frame = batch_meta->frame_meta_list; l_frame != NULL;
l_frame = l_frame->next)
{
NvDsFrameMeta *frame_meta = (NvDsFrameMeta *)(l_frame->data);
NvDsUserMeta *user_meta = NULL;
//call this every X frames
if(data->frame_num % 90 == 0) {
g_print("saving JPEG now.");
src_data = (char*) malloc(surface->surfaceList[frame_meta->batch_id].dataSize);
if(src_data == NULL) {
g_print("Error: failed to malloc src_data \n");
continue;
}
#ifdef PLATFORM_TEGRA
NvBufSurfaceMap (surface, -1, -1, NVBUF_MAP_READ);
NvBufSurfacePlaneParams *pParams = &surface->surfaceList[frame_meta->batch_id].planeParams;
unsigned int offset = 0;
for(unsigned int num_planes=0; num_planes < pParams->num_planes; num_planes++){
if(num_planes>0)
offset += pParams->height[num_planes-1]*(pParams->bytesPerPix[num_planes-1]*pParams->width[num_planes-1]);
for (unsigned int h = 0; h < pParams->height[num_planes]; h++) {
memcpy((void *)(src_data+offset+h*pParams->bytesPerPix[num_planes]*pParams->width[num_planes]),
(void *)((char *)surface->surfaceList[frame_meta->batch_id].mappedAddr.addr[num_planes]+h*pParams->pitch[num_planes]),
pParams->bytesPerPix[num_planes]*pParams->width[num_planes]
);
}
}
NvBufSurfaceSyncForDevice (surface, -1, -1);
NvBufSurfaceUnMap (surface, -1, -1);
#else
cudaMemcpy((void*)src_data,
(void*)surface->surfaceList[frame_meta->batch_id].dataPtr,
surface->surfaceList[frame_meta->batch_id].dataSize,
cudaMemcpyDeviceToHost);
#endif
char filename[200];
uint32_t frame_width = surface->surfaceList[frame_meta->batch_id].width;
uint32_t frame_height = surface->surfaceList[frame_meta->batch_id].height;
uint32_t Y_stride = surface->surfaceList[frame_meta->batch_id].pitch;
uint32_t buffer_size = surface->surfaceList[frame_meta->batch_id].dataSize;
uint32_t est_size = frame_width*frame_height;
sprintf(filename,"file_y_%dx%d_%ld.jpg",frame_width,frame_height, data->frame_num);
printf("Buffer size : %d,%d\n", buffer_size,Y_stride);
printf("Estimated size : %d\n", est_size);
printf("frame_width : %d\n", frame_width);
printf("frame_height : %d\n", frame_height);
printf("dataPtr : %p\n", surface->surfaceList[frame_meta->batch_id].dataPtr);
printf("src_size:%ld\n",sizeof(char));
printf("totalpix1:%ld\n",sizeof(unsigned char));
printf("totalpix2:%ld\n",sizeof(unsigned int));
printf("totalpix3:%ld\n",sizeof(long unsigned int));
totalpix=src_data;
printf("!%ln!",(long unsigned int*) src_data);
printf("-%ln-",(long unsigned int*) src_data);
printf("=%s=",(char*) src_data);
sprintf(filename,"file_y_%dx%d_%d.jpg",frame_width,frame_height,outnumber);
write_jpeg_file( filename, src_data , frame_width, frame_height, 1, JCS_GRAYSCALE );
if(src_data != NULL) {
free(src_data);
src_data = NULL;
}
}
}
gst_buffer_unmap (buf, &in_map_info);
/* Opportunity to modify the processed metadata or do analytics based on
* type of object e.g. maintaining count of particular type of car.
*/
if (appCtx->all_bbox_generated_cb) {
appCtx->all_bbox_generated_cb (appCtx, buf, batch_meta, index);
}
//data->bbox_list_size = 0;
/*
* callback to attach application specific additional metadata.
*/
if (appCtx->overlay_graphics_cb) {
appCtx->overlay_graphics_cb (appCtx, buf, batch_meta, index);
}
}