| /* |
| * test-image-blend.cpp - test cl image |
| * |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| * |
| * Author: Wind Yuan <[email protected]> |
| */ |
| |
| #include "test_common.h" |
| #include "test_inline.h" |
| #include <unistd.h> |
| #include <getopt.h> |
| #include <ocl/cl_device.h> |
| #include <ocl/cl_context.h> |
| #include <ocl/cl_blender.h> |
| #include <image_file_handle.h> |
| #include <ocl/cl_geo_map_handler.h> |
| #if HAVE_LIBDRM |
| #include <drm_display.h> |
| #endif |
| #include <dma_video_buffer.h> |
| |
| using namespace XCam; |
| |
| #define ENABLE_DMA_TEST 0 |
| |
| static uint32_t input_format = V4L2_PIX_FMT_NV12; |
| //static uint32_t output_format = V4L2_PIX_FMT_NV12; |
| static uint32_t input_width0 = 1280, input_width1 = 1280; |
| static uint32_t input_height = 960; |
| static uint32_t output_width = 1920; |
| static uint32_t output_height; |
| static bool need_save_output = true; |
| static bool enable_geo = false; |
| static bool enable_seam = false; |
| |
| static int loop = 0; |
| static uint32_t map_width = 51, map_height = 43; |
| static const char *map0 = "fisheye0.csv"; |
| static const char *map1 = "fisheye1.csv"; |
| static char file_in0_name[XCAM_MAX_STR_SIZE], file_in1_name[XCAM_MAX_STR_SIZE], file_out_name[XCAM_MAX_STR_SIZE]; |
| |
| static int read_map_data (const char* file, GeoPos *map, int width, int height); |
| |
| static void |
| usage(const char* arg0) |
| { |
| printf ("Usage:\n" |
| "%s --input0 file --input1 file --output file" |
| " [--input-w0 width] [--input-w1 width] [--input-h height] [--output-w width] \n" |
| "\t--input0, first image(NV12)\n" |
| "\t--input1, second image(NV12)\n" |
| "\t--output, output image(NV12) PREFIX\n" |
| "\t--input-w0, optional, input width; default:1280\n" |
| "\t--input-w1, optional, input width; default:1280\n" |
| "\t--input-h, optional, input height; default:960\n" |
| "\t--output-w, optional, output width; default:1920, output height is same as input height.\n" |
| "\t--loop, optional, how many loops need to run for performance test, default 0; \n" |
| "\t--save, optional, save file or not, default true; select from [true/false]\n" |
| "\t--enable-geo, optional, enable geo map image frist. default: no\n" |
| "\t--enable-seam, optional, enable seam finder in blending area. default: no\n" |
| "\t--help, usage\n", |
| arg0); |
| } |
| |
| static int |
| geo_correct_image ( |
| SmartPtr<CLGeoMapHandler> geo_map_handler, SmartPtr<VideoBuffer> &in_out, |
| GeoPos *geo_map0, uint32_t map_width, uint32_t map_height, |
| char *file_name, bool need_save_output) |
| { |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| SmartPtr<VideoBuffer> geo_out; |
| geo_map_handler->set_map_data (geo_map0, map_width, map_height); |
| ret = geo_map_handler->execute (in_out, geo_out); |
| CHECK (ret, "geo map handler execute inpu0 failed"); |
| XCAM_ASSERT (geo_out.ptr ()); |
| in_out = geo_out; |
| |
| if (need_save_output) { |
| char gdc_dump_name[1024]; |
| snprintf (gdc_dump_name, 1024, "gdc-%s", file_name); |
| ImageFileHandle file_out; |
| file_out.open (gdc_dump_name, "wb"); |
| file_out.write_buf (geo_out); |
| file_out.close (); |
| printf ("write gdc output buffer to: %s done\n", gdc_dump_name); |
| } |
| return 0; |
| } |
| |
| #if (ENABLE_DMA_TEST) && (HAVE_LIBDRM) |
| static SmartPtr<VideoBuffer> |
| dma_buf_to_xcam_buf ( |
| SmartPtr<DrmDisplay> display, int dma_fd, |
| uint32_t width, uint32_t height, uint32_t size, |
| uint32_t aligned_width = 0, uint32_t aligned_height = 0) |
| { |
| /* |
| * |
| * XCAM_ASSERT (native_handle_t.numFds == 1); |
| * XCAM_ASSERT (native_handle_t.data[0] > 0); |
| * dma_fd = native_handle_t.data[0] ; |
| */; |
| VideoBufferInfo info; |
| SmartPtr<VideoBuffer> dma_buf; |
| SmartPtr<VideoBuffer> output; |
| |
| XCAM_ASSERT (dma_fd > 0); |
| |
| if (aligned_width == 0) |
| aligned_width = XCAM_ALIGN_UP(width, 16); |
| if (aligned_height == 0) |
| aligned_height = XCAM_ALIGN_UP(height, 16); |
| |
| info.init (V4L2_PIX_FMT_NV12, width, height, aligned_width, aligned_height, size); |
| dma_buf = new DmaVideoBuffer (info, dma_fd); |
| output = display->convert_to_drm_bo_buf (display, dma_buf); |
| if (!output.ptr ()) { |
| XCAM_LOG_ERROR ("dma_buf(%d) convert to xcam_buf failed", dma_fd); |
| } |
| |
| return output; |
| } |
| |
| static SmartPtr<VideoBuffer> |
| create_dma_buffer (SmartPtr<DrmDisplay> &display, const VideoBufferInfo &info) |
| { |
| SmartPtr<BufferPool> buf_pool = new DrmBoBufferPool (display); |
| buf_pool->set_video_info (info); |
| buf_pool->reserve (1); |
| return buf_pool->get_buffer (buf_pool); |
| } |
| #endif |
| |
| static XCamReturn |
| blend_images ( |
| SmartPtr<VideoBuffer> input0, SmartPtr<VideoBuffer> input1, |
| SmartPtr<VideoBuffer> &output_buf, |
| SmartPtr<CLBlender> blender) |
| { |
| blender->set_output_size (output_width, output_height); |
| input0->attach_buffer (input1); |
| return blender->execute (input0, output_buf); |
| } |
| |
| int main (int argc, char *argv[]) |
| { |
| GeoPos *geo_map0 = NULL, *geo_map1 = NULL; |
| XCamReturn ret = XCAM_RETURN_NO_ERROR; |
| SmartPtr<CLImageHandler> image_handler; |
| SmartPtr<CLGeoMapHandler> geo_map_handler; |
| SmartPtr<CLBlender> blender; |
| VideoBufferInfo input_buf_info0, input_buf_info1, output_buf_info; |
| SmartPtr<CLContext> context; |
| SmartPtr<BufferPool> buf_pool0, buf_pool1; |
| ImageFileHandle file_in0, file_in1, file_out; |
| SmartPtr<VideoBuffer> input0, input1; |
| SmartPtr<VideoBuffer> output_buf; |
| SmartPtr<VideoBuffer> read_buf; |
| |
| #define FAILED_GEO_FREE { delete [] geo_map0; delete [] geo_map1; return -1; } |
| |
| const struct option long_opts[] = { |
| {"input0", required_argument, NULL, 'i'}, |
| {"input1", required_argument, NULL, 'I'}, |
| {"output", required_argument, NULL, 'o'}, |
| {"input-w0", required_argument, NULL, 'w'}, |
| {"input-w1", required_argument, NULL, 'W'}, |
| {"input-h", required_argument, NULL, 'H'}, |
| {"output-w", required_argument, NULL, 'x'}, |
| {"loop", required_argument, NULL, 'l'}, |
| {"save", required_argument, NULL, 's'}, |
| {"enable-geo", no_argument, NULL, 'g'}, |
| {"enable-seam", no_argument, NULL, 'm'}, |
| {"help", no_argument, NULL, 'h'}, |
| {0, 0, 0, 0}, |
| }; |
| |
| int opt = -1; |
| while ((opt = getopt_long(argc, argv, "", long_opts, NULL)) != -1) { |
| switch (opt) { |
| case 'i': |
| strncpy (file_in0_name, optarg, XCAM_MAX_STR_SIZE); |
| break; |
| case 'I': |
| strncpy (file_in1_name, optarg, XCAM_MAX_STR_SIZE); |
| break; |
| case 'o': |
| strncpy (file_out_name, optarg, XCAM_MAX_STR_SIZE); |
| break; |
| case 'w': |
| input_width0 = atoi(optarg); |
| break; |
| case 'W': |
| input_width1 = atoi(optarg); |
| break; |
| case 'H': |
| input_height = atoi(optarg); |
| break; |
| case 'x': |
| output_width = atoi(optarg); |
| break; |
| case 'l': |
| loop = atoi(optarg); |
| break; |
| case 's': |
| need_save_output = (strcasecmp (optarg, "false") == 0 ? false : true); |
| break; |
| case 'g': |
| enable_geo = true; |
| break; |
| case 'm': |
| enable_seam = true; |
| break; |
| case 'h': |
| usage (argv[0]); |
| return -1; |
| default: |
| printf ("getopt_long return unknown value:%c\n", opt); |
| usage (argv[0]); |
| return -1; |
| |
| } |
| } |
| |
| if (optind < argc || argc < 2) { |
| printf("unknown option %s\n", argv[optind]); |
| usage (argv[0]); |
| return -1; |
| } |
| |
| printf ("Description-----------\n"); |
| printf ("input0 file:%s\n", file_in0_name); |
| printf ("input1 file:%s\n", file_in1_name); |
| printf ("output file PREFIX:%s\n", file_out_name); |
| printf ("input0 width:%d\n", input_width0); |
| printf ("input1 width:%d\n", input_width1); |
| printf ("input/output height:%d\n", input_height); |
| printf ("output width:%d\n", output_width); |
| printf ("loop count:%d\n", loop); |
| printf ("need save file:%s\n", need_save_output ? "true" : "false"); |
| printf ("enable seam mask:%s\n", (enable_seam ? "true" : "false")); |
| printf ("----------------------\n"); |
| |
| output_height = input_height; |
| input_buf_info0.init (input_format, input_width0, input_height); |
| input_buf_info1.init (input_format, input_width1, input_height); |
| output_buf_info.init (input_format, output_width, output_height); |
| #if (ENABLE_DMA_TEST) && (HAVE_LIBDRM) |
| SmartPtr<DrmDisplay> display = DrmDisplay::instance (); |
| buf_pool0 = new DrmBoBufferPool (display); |
| buf_pool1 = new DrmBoBufferPool (display); |
| #else |
| buf_pool0 = new CLVideoBufferPool (); |
| buf_pool1 = new CLVideoBufferPool (); |
| #endif |
| XCAM_ASSERT (buf_pool0.ptr () && buf_pool1.ptr ()); |
| buf_pool0->set_video_info (input_buf_info0); |
| buf_pool1->set_video_info (input_buf_info1); |
| if (!buf_pool0->reserve (2)) { |
| XCAM_LOG_ERROR ("init buffer pool failed"); |
| return -1; |
| } |
| if (!buf_pool1->reserve (2)) { |
| XCAM_LOG_ERROR ("init buffer pool failed"); |
| return -1; |
| } |
| |
| context = CLDevice::instance ()->get_context (); |
| blender = create_pyramid_blender (context, 2, true, enable_seam).dynamic_cast_ptr<CLBlender> (); |
| XCAM_ASSERT (blender.ptr ()); |
| |
| #if (ENABLE_DMA_TEST) && (HAVE_LIBDRM) |
| int dma_fd0 = 30, dma_fd1 = 31, dma_fd_out = 32; |
| input_buf_info0.init ( |
| input_format, input_width0, input_height, XCAM_ALIGN_UP (input_width0, 16), XCAM_ALIGN_UP(input_height, 16)); |
| input_buf_info1.init ( |
| input_format, input_width1, input_height, XCAM_ALIGN_UP (input_width1, 16), XCAM_ALIGN_UP(input_height, 16)); |
| output_buf_info.init ( |
| input_format, output_width, output_height, XCAM_ALIGN_UP (output_width, 16), XCAM_ALIGN_UP(output_height, 16)); |
| uint32_t in_size = input_buf_info0.aligned_width * input_buf_info0.aligned_height * 3 / 2; |
| uint32_t out_size = output_buf_info.aligned_width * output_buf_info.aligned_height * 3 / 2; |
| /* create dma fd, for buffer_handle_t just skip this segment, directly goto dma_buf_to_xcam_buf */ |
| SmartPtr<VideoBuffer> dma_buf0, dma_buf1, dma_buf_out; |
| dma_buf0 = create_dma_buffer (display, input_buf_info0); //unit test |
| dma_buf1 = create_dma_buffer (display, input_buf_info1); //unit test |
| dma_buf_out = create_dma_buffer (display, output_buf_info); //unit test |
| dma_fd0 = dma_buf0->get_fd (); //unit test |
| dma_fd1 = dma_buf1->get_fd (); //unit test |
| dma_fd_out = dma_buf_out->get_fd (); //unit test |
| /* |
| buffer_handle_t just go to here, |
| dma_fd0 = native_handle_t.data[0]; |
| dma_fd1 = native_handle_t.data[0]; |
| dma_fd_out = native_handle_t.data[0]; |
| */ |
| printf ("DMA handles, buf0:%d, buf1:%d, buf_out:%d\n", dma_fd0, dma_fd1, dma_fd_out); |
| input0 = dma_buf_to_xcam_buf ( |
| display, dma_fd0, input_width0, input_height, in_size, |
| input_buf_info0.aligned_width, input_buf_info0.aligned_height); |
| input1 = dma_buf_to_xcam_buf ( |
| display, dma_fd1, input_width0, input_height, in_size, |
| input_buf_info1.aligned_width, input_buf_info1.aligned_height); |
| output_buf = dma_buf_to_xcam_buf ( |
| display, dma_fd_out, output_width, output_height, out_size, |
| output_buf_info.aligned_width, output_buf_info.aligned_height); |
| blender->disable_buf_pool (true); |
| #else |
| input0 = buf_pool0->get_buffer (buf_pool0); |
| input1 = buf_pool1->get_buffer (buf_pool1); |
| XCAM_ASSERT (input0.ptr () && input1.ptr ()); |
| #endif |
| // |
| ret = file_in0.open (file_in0_name, "rb"); |
| CHECK_STATEMENT (ret, FAILED_GEO_FREE, "open input file(%s) failed", file_in0_name); |
| read_buf = input0; |
| ret = file_in0.read_buf (read_buf); |
| CHECK_STATEMENT (ret, FAILED_GEO_FREE, "read buffer0 from (%s) failed", file_in0_name); |
| |
| ret = file_in1.open (file_in1_name, "rb"); |
| CHECK_STATEMENT (ret, FAILED_GEO_FREE, "open input file(%s) failed", file_in1_name); |
| read_buf = input1; |
| ret = file_in1.read_buf (read_buf); |
| CHECK_STATEMENT (ret, FAILED_GEO_FREE, "read buffer1 from (%s) failed", file_in1_name); |
| |
| if (enable_geo) { |
| geo_map_handler = create_geo_map_handler (context).dynamic_cast_ptr<CLGeoMapHandler> (); |
| XCAM_ASSERT (geo_map_handler.ptr ()); |
| |
| geo_map0 = new GeoPos[map_width * map_height]; |
| geo_map1 = new GeoPos[map_width * map_height]; |
| XCAM_ASSERT (geo_map0 && geo_map1); |
| if (read_map_data (map0, geo_map0, map_width, map_height) <= 0 || |
| read_map_data (map1, geo_map1, map_width, map_height) <= 0) { |
| delete [] geo_map0; |
| delete [] geo_map1; |
| return -1; |
| } |
| |
| geo_map_handler->set_map_uint (28.0f, 28.0f); |
| } |
| |
| int i = 0; |
| do { |
| input0->clear_attached_buffers (); |
| input1->clear_attached_buffers (); |
| |
| if (enable_geo) { |
| geo_correct_image (geo_map_handler, input0, geo_map0, map_width, map_height, file_in0_name, need_save_output); |
| geo_correct_image (geo_map_handler, input1, geo_map1, map_width, map_height, file_in1_name, need_save_output); |
| } |
| |
| ret = blend_images (input0, input1, output_buf, blender); |
| CHECK_STATEMENT (ret, FAILED_GEO_FREE, "blend_images execute failed"); |
| //printf ("DMA handles, output_buf:%d\n", output_buf->get_fd ()); |
| |
| if (need_save_output) { |
| char out_name[1024]; |
| snprintf (out_name, 1023, "%s.%02d", file_out_name, i); |
| |
| ret = file_out.open (out_name, "wb"); |
| CHECK_STATEMENT (ret, FAILED_GEO_FREE, "open output file(%s) failed", out_name); |
| ret = file_out.write_buf (output_buf); |
| CHECK_STATEMENT (ret, FAILED_GEO_FREE, "write buffer to (%s) failed", out_name); |
| printf ("write output buffer to: %s done\n", out_name); |
| } else { |
| // check info |
| ensure_gpu_buffer_done (output_buf); |
| } |
| |
| FPS_CALCULATION (image_blend, XCAM_OBJ_DUR_FRAME_NUM); |
| ++i; |
| } while (i < loop); |
| |
| delete [] geo_map0; |
| delete [] geo_map1; |
| |
| return ret; |
| } |
| |
| //return count |
| int read_map_data (const char* file, GeoPos *map, int width, int height) |
| { |
| char *ptr = NULL; |
| FILE *p_f = fopen (file, "rb"); |
| CHECK_EXP (p_f, "open geo-map file(%s) failed", file); |
| |
| #define FAILED_READ_MAP { if (p_f) fclose(p_f); if (ptr) xcam_free (ptr); return -1; } |
| |
| CHECK_DECLARE (ERROR, fseek(p_f, 0L, SEEK_END) == 0, FAILED_READ_MAP, "seek to file(%s) end failed", file); |
| size_t size = ftell (p_f); |
| XCAM_ASSERT ((int)size != -1); |
| fseek (p_f, 0L, SEEK_SET); |
| |
| ptr = (char*)xcam_malloc (size + 1); |
| XCAM_ASSERT (ptr); |
| CHECK_DECLARE (ERROR, fread (ptr, 1, size, p_f) == size, FAILED_READ_MAP, "read map file(%s)failed", file); |
| ptr[size] = 0; |
| fclose (p_f); |
| p_f = NULL; |
| |
| char *str_num = NULL; |
| char tokens[] = "\t ,\r\n"; |
| str_num = strtok (ptr, tokens); |
| int count = 0; |
| int x = 0, y = 0; |
| while (str_num != NULL) { |
| float num = strtof (str_num, NULL); |
| //printf ("%.3f\n", num); |
| |
| x = count % width; |
| y = count / (width * 2); // x,y |
| if (y >= height) |
| break; |
| |
| if (count % (width * 2) >= width) |
| map[y * width + x].y = num; |
| else |
| map[y * width + x].x = num; |
| |
| ++count; |
| str_num = strtok (NULL, tokens); |
| } |
| xcam_free (ptr); |
| ptr = NULL; |
| CHECK_EXP (y < height, "map data(%s) count larger than expected(%dx%dx2)", file, width, height); |
| CHECK_EXP (count >= width * height * 2, "map data(%s) count less than expected(%dx%dx2)", file, width, height); |
| |
| printf ("read map(%s) x/y data count:%d\n", file, count); |
| return count; |
| } |
| |