/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of The Linux Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ // System dependencies #include <dlfcn.h> #include <stdbool.h> #include <stdlib.h> #include <sys/time.h> // Camera dependencies #include "img_buffer.h" #include "mm_lib2d.h" #define ENABLE_OUTPUT_DUMP 1 #define ALIGN4K 4032 #define ALIGN(a, b) (((a) + (b)) & ~(b)) /** DUMP_TO_FILE: * @filename: file name * @p_addr: address of the buffer * @len: buffer length * * dump the image to the file **/ #define DUMP_TO_FILE(filename, p_addr, len) ({ \ size_t rc = 0; \ FILE *fp = fopen(filename, "w+"); \ if (fp) { \ rc = fwrite(p_addr, 1, len, fp); \ printf(" ] written size %zu \n", __LINE__, len); \ fclose(fp); \ } else { \ printf(" ] open %s failed \n", __LINE__, filename); \ } \ }) /** DUMP_TO_FILE2: * @filename: file name * @p_addr: address of the buffer * @len: buffer length * * dump the image to the file if the memory is non-contiguous **/ #define DUMP_TO_FILE2(filename, p_addr1, len1, p_addr2, len2) ({ \ size_t rc = 0; \ FILE *fp = fopen(filename, "w+"); \ if (fp) { \ rc = fwrite(p_addr1, 1, len1, fp); \ rc = fwrite(p_addr2, 1, len2, fp); \ printf(" ] written %zu %zu \n", __LINE__, len1, len2); \ fclose(fp); \ } else { \ printf(" ] open %s failed \n", __LINE__, filename); \ } \ }) /** img_lib_buffert * @ptr: handle to the imglib library * @img_buffer_get: function pointer to img_buffer_get * @img_buffer_release: function pointer to img_buffer_release * @img_buffer_cacheops: function pointer to img_buffer_cacheops **/ typedef struct { void *ptr; int (*img_buffer_get)(img_buf_type_t type, int heapid, int8_t cached, int length, img_mem_handle_t *p_handle); int (*img_buffer_release)(img_mem_handle_t *p_handle); int (*img_buffer_cacheops)(img_mem_handle_t *p_handle, img_cache_ops_t ops, img_mem_alloc_type_t mem_alloc_type); } img_lib_buffert; /** input_yuv_data * @filename: input test filename * @format: format of the input yuv frame * @wdith: wdith of the input yuv frame * @height: height of the input yuv frame * @stride: stride of the input yuv frame * @offset: offset to the yuv data in the input file **/ typedef struct input_yuv_data_t { char filename[512]; cam_format_t format; int32_t wdith; int32_t height; int32_t stride; int32_t offset; } input_yuv_data; input_yuv_data input_nv21[] = { {"sample0_768x512.yuv", CAM_FORMAT_YUV_420_NV21, 768, 512, 768, 0}, {"sample1_3200x2400.yuv", CAM_FORMAT_YUV_420_NV21, 3200, 2400, 3200, 0}, {"sample2_1920x1080.yuv", CAM_FORMAT_YUV_420_NV21, 1920, 1080, 1920, 0}, {"sample3_3200x2400.yuv", CAM_FORMAT_YUV_420_NV21, 3200, 2400, 3200, 0}, {"sample4_4208x3120.yuv", CAM_FORMAT_YUV_420_NV21, 4208, 3120, 4208, 0}, {"sample5_1984x2592.yuv", CAM_FORMAT_YUV_420_NV21, 1984, 2592, 1984, 0}, {"sample6_4000_3000.yuv", CAM_FORMAT_YUV_420_NV21, 4000, 3000, 4000, 0}, {"sample7_3200_2400.yuv", CAM_FORMAT_YUV_420_NV21, 3200, 2400, 3200, 0}, {"sample8_3008_4000.yuv", CAM_FORMAT_YUV_420_NV21, 3008, 4000, 3008, 0}, {"sample9_5312x2988.yuv", CAM_FORMAT_YUV_420_NV21, 5312, 2988, 5312, 0}, {"sample10_4128x3096.yuv", CAM_FORMAT_YUV_420_NV21, 4128, 3096, 4128, 0}, {"sample11_4208x3120.yuv", CAM_FORMAT_YUV_420_NV21, 4208, 3120, 4208, 0}, {"sample12_3200x2400.yuv", CAM_FORMAT_YUV_420_NV21, 3200, 2400, 3200, 0}, {"sample13_width_1080_height_1440_stride_1088.yuv", CAM_FORMAT_YUV_420_NV21, 1080, 1440, 1088, 0}, {"sample14_width_1080_height_1920_stride_1088.yuv", CAM_FORMAT_YUV_420_NV21, 1080, 1920, 1088, 0}, {"sample15_width_1944_height_2592_stride_1984.yuv", CAM_FORMAT_YUV_420_NV21, 1944, 2592, 1984, 0}, {"sample16_width_3000_height_4000_stride_3008.yuv", CAM_FORMAT_YUV_420_NV21, 3000, 4000, 3008, 0}, {"sample17_width_3120_height_4208_stride_3136.yuv", CAM_FORMAT_YUV_420_NV21, 3120, 4208, 3136, 0}, {"sample18_width_3200_height_2400_stride_3200.yuv", CAM_FORMAT_YUV_420_NV21, 3200, 2400, 3200, 0}, {"sample19_width_1944_height_2592_stride_1984.yuv", CAM_FORMAT_YUV_420_NV21, 1944, 2592, 1984, 0}, }; // assuming buffer format is always ARGB void lib2d_dump_tga(void *addr, cam_format_t format, int width, int height, int stride, char *fname) { int i, j; FILE *f; unsigned char *pb = (unsigned char *)addr; uint32_t *pd = (uint32_t *)addr; int bpp = 32; f = fopen(fname, "wb"); if (f) { // header fprintf(f, "%c%c%c%c", 0, 0, 2, 0); fprintf(f, "%c%c%c%c", 0, 0, 0, 0); fprintf(f, "%c%c%c%c", 0, 0, 0, 0); fprintf(f, "%c%c%c%c", width & 0xff, width >> 8, height & 0xff, height >> 8); fprintf(f, "%c%c", bpp, 32); for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { fprintf(f, "%c%c%c%c", pd[(i*stride>>2)+j] & 0xff, // b (pd[(i*stride>>2)+j] >> 8) & 0xff, // g (pd[(i*stride>>2)+j] >> 16) & 0xff, // r (pd[(i*stride>>2)+j] >> 24) & 0xff); // a } } fclose(f); } } /** * Function: lib2d_test_client_cb * * Description: Callback that is called on completion of requested job. * * Input parameters: * userdata - App userdata * jobid - job id that is finished execution * * Return values: * MM_LIB2D_SUCCESS * MM_LIB2D_ERR_GENERAL * * Notes: none **/ lib2d_error lib2d_test_client_cb(void *userdata, int jobid) { printf("%s %d, jobid=%d \n", __LINE__, jobid); return MM_LIB2D_SUCCESS; } /** * Function: lib2d_test_load_input_yuv_data * * Description: Loads yuv data from input file. * * Input parameters: * fileName - input yuv filename * offset - offset to the yuv data in the input file * y_size - y plane size in input yuv file * crcb_size - crcb plane size in input yuv file * crcb_offset - crcb offset in the memory at * which crcb data need to be loaded * addr - y plane memory address where y plane * data need to be loaded. * * Return values: * MM_LIB2D_SUCCESS * MM_LIB2D_ERR_GENERAL * * Notes: none **/ lib2d_error lib2d_test_load_input_yuv_data(char *fileName, int offset, int32_t y_size, int32_t crcb_size, int32_t crcb_offset, void *addr) { size_t i; FILE *fp = 0; void *y_ptr = addr; void *crcb_ptr = (uint8_t *)addr + crcb_offset; printf("y_ptr=%p, crcb_ptr=%p \n", y_ptr, crcb_ptr); fp = fopen(fileName, "rb"); if(fp) { if(offset) { fseek(fp, offset, SEEK_SET); } i = fread(y_ptr, 1, y_size, fp); i = fread(crcb_ptr, 1, crcb_size, fp); fclose( fp ); } else { printf("failed to open file %s \n", fileName); return MM_LIB2D_ERR_GENERAL; } return MM_LIB2D_SUCCESS; } /** * Function: lib2d_test_load_input_yuv_data * * Description: Loads yuv data from input file. * * Input parameters: * fileName - input yuv filename * offset - offset to the yuv data in the input file * input_yuv_stride - y plane stride in input yuv file * y_plane_stride - y plane stride in buffer memory * height - height of yuv image * crcb_offset - crcb offset in the memory at * which crcb data need to be loaded * addr - y plane memory address where y plane * data need to be loaded. * * Return values: * MM_LIB2D_SUCCESS * MM_LIB2D_ERR_GENERAL * * Notes: none **/ lib2d_error lib2d_test_load_input_yuv_data_linebyline(char *fileName, int offset, int32_t input_yuv_stride, int32_t y_plane_stride, int32_t height, int32_t crcb_offset, void *addr) { size_t i; FILE *fp = 0; void *y_ptr = addr; void *crcb_ptr = (uint8_t *)addr + crcb_offset; printf("y_ptr=%p, crcb_ptr=%p \n", y_ptr, crcb_ptr); fp = fopen(fileName, "rb"); if(fp) { if(offset) { fseek(fp, offset, SEEK_SET); } if (input_yuv_stride == y_plane_stride) { //load y plane i = fread(y_ptr, 1, (input_yuv_stride * height), fp); // load UV plane i = fread(crcb_ptr, 1, (input_yuv_stride * height / 2), fp); } else { int line = 0; // load Y plane for (line = 0;line < height; line++) { i = fread(y_ptr, 1, input_yuv_stride, fp); y_ptr = (void *)((uint8_t *)y_ptr + y_plane_stride); } for (line = 0;line < height; line++) { i = fread(crcb_ptr, 1, input_yuv_stride, fp); crcb_ptr = (void *)((uint8_t *)crcb_ptr + y_plane_stride); } } fclose( fp ); } else { printf("failed to open file %s \n", fileName); return MM_LIB2D_ERR_GENERAL; } return MM_LIB2D_SUCCESS; } /** * Function: main * * Description: main function for execution * * Input parameters: * argc - no.of input arguments * argv - list of arguments * * Return values: * 0 on success * -1 on failure * * Notes: none **/ int main(int32_t argc, const char * argv[]) { void *lib2d_handle = NULL; lib2d_error lib2d_err = MM_LIB2D_SUCCESS; mm_lib2d_buffer src_buffer = {0}; mm_lib2d_buffer dst_buffer = {0}; int8_t ret = IMG_SUCCESS; int32_t width = 0; int32_t height = 0; int32_t input_yuv_stride = 0; int32_t stride = 0; int32_t y_plane_stride = 0; int32_t crcb_plane_stride = 0; int32_t y_plane_size = 0; int32_t y_plane_size_align = 0; int32_t crcb_plane_size = 0; int32_t yuv_size = 0; int32_t rgb_size = 0; img_mem_handle_t m_yuv_memHandle = { 0 }; img_mem_handle_t m_rgb_memHandle = { 0 }; char filename_in[512] = { 0 }; char filename_out[512] = { 0 }; char filename_raw[512] = { 0 }; int32_t offset = 0; unsigned int total_tests = 1; cam_format_t format = CAM_FORMAT_YUV_420_NV21; unsigned int index; const char *filename; // Open Imglib library and get the function pointers for // buffer allocation, free, cacheops img_lib_buffert img_lib; img_lib.ptr = dlopen("libmmcamera_imglib.so", RTLD_NOW); if (!img_lib.ptr) { printf("%s ERROR: couldn't dlopen libmmcamera_imglib.so: %s", dlerror()); return -1; } /* Get function pointer for functions to allocate ion memory */ *(void **)&img_lib.img_buffer_get = dlsym(img_lib.ptr, "img_buffer_get"); *(void **)&img_lib.img_buffer_release = dlsym(img_lib.ptr, "img_buffer_release"); *(void **)&img_lib.img_buffer_cacheops = dlsym(img_lib.ptr, "img_buffer_cacheops"); /* Validate function pointers */ if ((img_lib.img_buffer_get == NULL) || (img_lib.img_buffer_release == NULL) || (img_lib.img_buffer_cacheops == NULL)) { printf(" ERROR mapping symbols from libmmcamera_imglib.so"); dlclose(img_lib.ptr); return -1; } lib2d_err = mm_lib2d_init(MM_LIB2D_SYNC_MODE, CAM_FORMAT_YUV_420_NV21, CAM_FORMAT_8888_ARGB, &lib2d_handle); if ((lib2d_err != MM_LIB2D_SUCCESS) || (lib2d_handle == NULL)) { return -1; } bool run_default = FALSE; if ( argc == 7) { filename = argv[1]; width = (uint32_t)atoi(argv[2]); height = (uint32_t)atoi(argv[3]); input_yuv_stride = (uint32_t)atoi(argv[4]); offset = (uint32_t)atoi(argv[5]); format = (uint32_t)atoi(argv[6]); run_default = TRUE; printf("Running user provided conversion \n"); } else { total_tests = sizeof(input_nv21)/sizeof(input_yuv_data); printf("usage: <binary> <filname> <width> <height> " "<stride> <offset> <format> \n"); } for (index = 0; index < total_tests; index++) { if(run_default == FALSE) { filename = input_nv21[index].filename; width = input_nv21[index].wdith; height = input_nv21[index].height; input_yuv_stride = input_nv21[index].stride; offset = input_nv21[index].offset; format = input_nv21[index].format; } snprintf(filename_in, 512, "/data/lib2d/input/%s", filename); snprintf(filename_out, 512, "/data/lib2d/output/%s.tga", filename); snprintf(filename_raw, 512, "/data/lib2d/output/%s.rgba", filename); printf("-----------------Running test=%d/%d------------------------- \n", index+1, total_tests); printf("filename=%s, full path=%s, width=%d, height=%d, stride=%d \n", filename, filename_in, width, height, stride); // Allocate NV12 buffer y_plane_stride = ALIGN(width, 32); y_plane_size = y_plane_stride * height; y_plane_size_align = ALIGN(y_plane_size, ALIGN4K); crcb_plane_stride = y_plane_stride; crcb_plane_size = crcb_plane_stride * height / 2; yuv_size = y_plane_size_align + crcb_plane_size; ret = img_lib.img_buffer_get(IMG_BUFFER_ION_IOMMU, -1, TRUE, yuv_size, &m_yuv_memHandle); if (ret != IMG_SUCCESS) { printf(" ] Error, img buf get failed \n"); goto deinit; } printf("%s %d yuv buffer properties : w=%d, h=%d, y_stride=%d, " "crcb_stride=%d, y_size=%d, crcb_size=%d, yuv_size=%d, " "crcb_offset=%d \n", __LINE__, width, height, y_plane_stride, crcb_plane_stride, y_plane_size, crcb_plane_size, yuv_size, y_plane_size_align); printf("%s %d yuv buffer properties : fd=%d, ptr=%p, size=%d \n", __LINE__, m_yuv_memHandle.fd, m_yuv_memHandle.vaddr, m_yuv_memHandle.length); // Allocate ARGB buffer stride = width * 4; stride = ALIGN(stride, 32); rgb_size = stride * height; ret = img_lib.img_buffer_get(IMG_BUFFER_ION_IOMMU, -1, TRUE, rgb_size, &m_rgb_memHandle); if (ret != IMG_SUCCESS) { printf(" ] Error, img buf get failed"); img_lib.img_buffer_release(&m_yuv_memHandle); goto deinit; } printf("%s %d rgb buffer properties : w=%d, h=%d, stride=%d, size=%d \n", __LINE__, width, height, stride, rgb_size); printf("%s %d rgb buffer properties : fd=%d, ptr=%p, size=%d \n", __LINE__, m_rgb_memHandle.fd, m_rgb_memHandle.vaddr, m_rgb_memHandle.length); #if 0 lib2d_err = lib2d_test_load_input_yuv_data(filename_in, offset, (input_yuv_stride * height), (input_yuv_stride * height / 2), y_plane_size_align, m_yuv_memHandle.vaddr); if (lib2d_err != MM_LIB2D_SUCCESS) { printf(" ] Error loading the input buffer \n"); goto release; } #else lib2d_err = lib2d_test_load_input_yuv_data_linebyline(filename_in, offset, input_yuv_stride, y_plane_stride,height, y_plane_size_align, m_yuv_memHandle.vaddr); if (lib2d_err != MM_LIB2D_SUCCESS) { printf(" ] Error loading the input buffer \n"); goto release; } #endif // Setup source buffer src_buffer.buffer_type = MM_LIB2D_BUFFER_TYPE_YUV; src_buffer.yuv_buffer.fd = m_yuv_memHandle.fd; src_buffer.yuv_buffer.format = format; src_buffer.yuv_buffer.width = width; src_buffer.yuv_buffer.height = height; src_buffer.yuv_buffer.plane0 = m_yuv_memHandle.vaddr; src_buffer.yuv_buffer.stride0 = y_plane_stride; src_buffer.yuv_buffer.plane1 = (int8_t *)m_yuv_memHandle.vaddr + y_plane_size_align; src_buffer.yuv_buffer.stride1 = crcb_plane_stride; // Setup dst buffer dst_buffer.buffer_type = MM_LIB2D_BUFFER_TYPE_RGB; dst_buffer.rgb_buffer.fd = m_rgb_memHandle.fd; dst_buffer.rgb_buffer.format = CAM_FORMAT_8888_ARGB; dst_buffer.rgb_buffer.width = width; dst_buffer.rgb_buffer.height = height; dst_buffer.rgb_buffer.buffer = m_rgb_memHandle.vaddr; dst_buffer.rgb_buffer.stride = stride; img_lib.img_buffer_cacheops(&m_yuv_memHandle, IMG_CACHE_CLEAN_INV, IMG_INTERNAL); lib2d_err = mm_lib2d_start_job(lib2d_handle, &src_buffer, &dst_buffer, index, NULL, lib2d_test_client_cb); if (lib2d_err != MM_LIB2D_SUCCESS) { printf(" ] Error in mm_lib2d_start_job \n"); goto release; } img_lib.img_buffer_cacheops(&m_rgb_memHandle, IMG_CACHE_CLEAN_INV, IMG_INTERNAL); #ifdef ENABLE_OUTPUT_DUMP // Dump output files // snprintf(filename_in, 512, "/data/lib2d/output/%s", filename); // DUMP_TO_FILE2(filename_in, src_buffer.yuv_buffer.plane0, y_plane_size, src_buffer.yuv_buffer.plane1, crcb_plane_size); // DUMP_TO_FILE(filename_raw, dst_buffer.rgb_buffer.buffer, rgb_size); printf("Dumping output file %s \n", filename_out); lib2d_dump_tga(dst_buffer.rgb_buffer.buffer, 1, width, height, stride, filename_out); #endif img_lib.img_buffer_release(&m_rgb_memHandle); img_lib.img_buffer_release(&m_yuv_memHandle); } mm_lib2d_deinit(lib2d_handle); return 0; release: img_lib.img_buffer_release(&m_rgb_memHandle); img_lib.img_buffer_release(&m_yuv_memHandle); deinit: mm_lib2d_deinit(lib2d_handle); printf("%s %d some error happened, tests completed = %d/%d \n", __LINE__, index - 1, total_tests); return -1; }