| /* 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, 0); |
| 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; |
| } |
| |
| |