diff --git a/package/Config.in b/package/Config.in old mode 100755 new mode 100644 index b21ffd99..eb0be3bf --- a/package/Config.in +++ b/package/Config.in @@ -2573,9 +2573,7 @@ menu "Text editors and viewers" endmenu - -menu "v4l2 test" - source "package/v4l2_test/Config.in" - source "package/v4lutils/Config.in" +menu "starfive packages" + source "package/starfive/Config.in" endmenu endmenu diff --git a/package/Config.in.host b/package/Config.in.host old mode 100755 new mode 100644 index 05cf2fd6..10e8c9e8 --- a/package/Config.in.host +++ b/package/Config.in.host @@ -94,6 +94,6 @@ menu "Host utilities" source "package/xorriso/Config.in.host" source "package/zip/Config.in.host" source "package/zstd/Config.in.host" - source "package/stfisp_setfile/Config.in.host" + source "package/starfive/stfisp_setfile/Config.in.host" endmenu diff --git a/package/starfive/Config.in b/package/starfive/Config.in new file mode 100644 index 00000000..6198f736 --- /dev/null +++ b/package/starfive/Config.in @@ -0,0 +1,3 @@ +# starfive packages +source "package/starfive/v4l2_test/Config.in" +source "package/starfive/stfisp_setfile/Config.in.host" diff --git a/package/starfive/starfive.mk b/package/starfive/starfive.mk new file mode 100644 index 00000000..32d2f407 --- /dev/null +++ b/package/starfive/starfive.mk @@ -0,0 +1 @@ +include $(sort $(wildcard package/starfive/*/*.mk)) diff --git a/package/stfisp_setfile/Config.in.host b/package/starfive/stfisp_setfile/Config.in.host old mode 100755 new mode 100644 similarity index 100% rename from package/stfisp_setfile/Config.in.host rename to package/starfive/stfisp_setfile/Config.in.host diff --git a/package/stfisp_setfile/stfisp_setfile.c b/package/starfive/stfisp_setfile/stfisp_setfile.c old mode 100755 new mode 100644 similarity index 100% rename from package/stfisp_setfile/stfisp_setfile.c rename to package/starfive/stfisp_setfile/stfisp_setfile.c diff --git a/package/stfisp_setfile/stfisp_setfile.mk b/package/starfive/stfisp_setfile/stfisp_setfile.mk old mode 100755 new mode 100644 similarity index 92% rename from package/stfisp_setfile/stfisp_setfile.mk rename to package/starfive/stfisp_setfile/stfisp_setfile.mk index ac7c5d58..dfb453a1 --- a/package/stfisp_setfile/stfisp_setfile.mk +++ b/package/starfive/stfisp_setfile/stfisp_setfile.mk @@ -7,7 +7,7 @@ STFISP_SETFILE_LICENSE = GPL-2.0+ define HOST_STFISP_SETFILE_BUILD_CMDS - cp package/stfisp_setfile/stfisp_setfile.c $(@D)/ + cp package/starfive/stfisp_setfile/stfisp_setfile.c $(@D)/ (cd $(@D); $(HOSTCC) -Wall -O2 stfisp_setfile.c -o stfisp_setfile; ./stfisp_setfile) install -m 0755 -D $(@D)/ov4689_stf_isp_fw.bin $(TARGET_DIR)/lib/firmware/stf_isp0_fw.bin install -m 0755 -D $(@D)/ov4689_stf_isp_fw_dump.bin $(TARGET_DIR)/lib/firmware/stf_isp0_fw_dump.bin diff --git a/package/v4l2_test/Config.in b/package/starfive/v4l2_test/Config.in old mode 100755 new mode 100644 similarity index 100% rename from package/v4l2_test/Config.in rename to package/starfive/v4l2_test/Config.in diff --git a/package/starfive/v4l2_test/common.c b/package/starfive/v4l2_test/common.c new file mode 100644 index 00000000..a10a8ddd --- /dev/null +++ b/package/starfive/v4l2_test/common.c @@ -0,0 +1,303 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ +#include "common.h" +#include +#include +#include +#include "convert.h" +#include "stf_log.h" + +/** + Print error message and terminate programm with EXIT_FAILURE return code. + \param s error message to print +*/ +void errno_exit(const char* s) +{ + LOG(STF_LEVEL_ERR, "%s error %d, %s\n", s, errno, strerror(errno)); + exit(EXIT_FAILURE); +} + +void errno_print(const char *s) +{ + LOG(STF_LEVEL_ERR, "%s error %d, %s\n", s, errno, strerror(errno)); +} + +void dump_fourcc(uint32_t fourcc) +{ + LOG(STF_LEVEL_LOG, " %c%c%c%c \n", + fourcc, + fourcc >> 8, + fourcc >> 16, + fourcc >> 24); +} + +// convert v4l2 format to fb format +int v4l2fmt_to_fbfmt(uint32_t format) +{ + int pixformat = COLOR_RGB565; + + switch (format) { + case V4L2_PIX_FMT_RGB565: + pixformat = COLOR_RGB565; + break; + case V4L2_PIX_FMT_RGB24: + pixformat = COLOR_RGB888_ARGB; + break; + case V4L2_PIX_FMT_YUV420: + pixformat = COLOR_YUV420P; + break; + case V4L2_PIX_FMT_YUYV: + pixformat = COLOR_YUV422_YUYV; + break; + case V4L2_PIX_FMT_NV21: + pixformat = COLOR_YUV420_NV21; + break; + case V4L2_PIX_FMT_NV12: + pixformat = COLOR_YUV420_NV12; + break; + case V4L2_PIX_FMT_YVYU: + pixformat = COLOR_YUV422_YVYU; + break; + default: + pixformat = COLOR_RGB565; + break; + } + + return pixformat; +} + +// convert v4l2 format to drm format +uint32_t v4l2fmt_to_drmfmt(uint32_t v4l2_fmt) +{ + uint32_t drm_fmt; + // dump_fourcc(v4l2_fmt); + + switch (v4l2_fmt) { + case V4L2_PIX_FMT_RGB565: + drm_fmt = DRM_FORMAT_RGB565; + break; + case V4L2_PIX_FMT_RGB24: + drm_fmt = DRM_FORMAT_ARGB8888; + break; + case V4L2_PIX_FMT_YUV420: + drm_fmt = DRM_FORMAT_YUV420; + break; + case V4L2_PIX_FMT_YUYV: + drm_fmt = DRM_FORMAT_YUYV; + break; + case V4L2_PIX_FMT_YVYU: + drm_fmt = DRM_FORMAT_YVYU; + break; + case V4L2_PIX_FMT_NV21: + drm_fmt = DRM_FORMAT_NV21; + break; + case V4L2_PIX_FMT_NV12: + drm_fmt = DRM_FORMAT_NV12; + break; + default: + drm_fmt = DRM_FORMAT_NV21; + LOG(STF_LEVEL_WARN, "drm not support the V4L2_format\n"); + break; + } + return drm_fmt; +} + +void test_performance() +{ + int count = 1920 * 1080 * 2; + float r, g, b; + float y = 10, u = 20, v = 30; + int int_r, int_g, int_b; + int int_y = 10, int_u = 20, int_v = 30; + struct timeval tv1, tv2, tv3; + long long elapse = 0; + int i; + + gettimeofday(&tv1, NULL); + while (count--) { + b = 1.164 * (y - 16) + 2.018 * (u - 128); + g = 1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128); + r = 1.164 * (y - 16) + 1.596 * (v - 128); + y ++; + u ++; + v ++; + } + gettimeofday(&tv2, NULL); + elapse = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000; + LOG(STF_LEVEL_INFO, "elapse: %lldms, out: r=%f, g=%f, b=%f\n", + elapse ,r, g, b); + + count = 1920 * 1080 * 2; + gettimeofday(&tv1, NULL); + while (count--) { + int_b = 1164 * (y - 16) + 2018 * (u - 128); + int_g = 1164 * (y - 16) - 813 * (v - 128) - 391 * (u - 128); + int_r = 1164 * (y - 16) + 1596 * (v - 128); + int_y ++; + int_u ++; + int_v ++; + } + gettimeofday(&tv2, NULL); + elapse = (tv2.tv_sec - tv1.tv_sec) + (tv2.tv_usec - tv1.tv_usec); + LOG(STF_LEVEL_INFO, "elapse: %lldus, out: r=%d, g=%d, b=%d\n", + elapse , int_r, int_g, int_b); + + count = 1920 * 1080 * 2; + unsigned char* arraybuf = NULL; + arraybuf = (unsigned char*)malloc(count); + if (!arraybuf) { + LOG(STF_LEVEL_ERR, "arraybuf malloc error\n"); + return; + } + + unsigned char* arraybuf2 = NULL; + arraybuf2 = (unsigned char*)malloc(count); + if (!arraybuf2) { + LOG(STF_LEVEL_ERR, "arraybuf2 malloc error\n"); + return; + } + + gettimeofday(&tv1, NULL); + + for (i = 0; i < count; i++) { + arraybuf[i] = i + 1; + } + + gettimeofday(&tv2, NULL); + + memcpy(arraybuf2, arraybuf, count); + + gettimeofday(&tv3, NULL); + + elapse = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000; + LOG(STF_LEVEL_INFO, "for() elapse: %lldms\n", elapse); + + elapse = (tv3.tv_sec - tv2.tv_sec) * 1000000 + (tv3.tv_usec - tv2.tv_usec); + LOG(STF_LEVEL_INFO, "memcpy() run elapse: %lldus\n", elapse); + + convert_nv21_to_rgb((const uint8_t*)arraybuf, arraybuf2, 1920, 1080, 1); + + free(arraybuf); + free(arraybuf2); +} + +int write_file(char * filename, const uint8_t *image_buffer, int size) +{ + /* More stuff */ + FILE * outfile; /* target file */ + if ((outfile = fopen(filename, "w+")) == NULL) { + LOG(STF_LEVEL_ERR, "can't open %s\n", filename); + return -1; + } + fwrite(image_buffer, size, 1, outfile); + fclose(outfile); + return 0 ; +} + +int write_JPEG_file(char * filename, uint8_t *image_buffer, + int image_width, int image_height, int quality) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + + /* More stuff */ + FILE * outfile; /* target file */ + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + int row_stride; /* physical row width in image buffer */ + + /* Step 1: allocate and initialize JPEG compression object */ + cinfo.err = jpeg_std_error(&jerr); + /* Now we can initialize the JPEG compression object. */ + jpeg_create_compress(&cinfo); + + /* Step 2: specify data destination (eg, a file) */ + /* Note: steps 2 and 3 can be done in either order. */ + if ((outfile = fopen(filename, "w+")) == NULL) { + LOG(STF_LEVEL_ERR, "can't open %s\n", filename); + return -1; + } + jpeg_stdio_dest(&cinfo, outfile); + + /* Step 3: set parameters for compression */ + cinfo.image_width = image_width; /* image width and height, in pixels */ + cinfo.image_height = image_height; + cinfo.input_components = 3; /* # of color components per pixel */ + cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ + jpeg_set_defaults(&cinfo); + jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); + + /* Step 4: Start compressor */ + jpeg_start_compress(&cinfo, TRUE); + + /* Step 5: while (scan lines remain to be written) */ + row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; + (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + /* Step 6: Finish compression */ + jpeg_finish_compress(&cinfo); + /* After finish_compress, we can close the output file. */ + fclose(outfile); + + /* Step 7: release JPEG compression object */ + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_compress(&cinfo); + + /* And we're done! */ + return 0; +} + +void jpegWrite(uint8_t* img, char* jpegFilename, + uint32_t width, uint32_t height, int jpegQuality) +{ + struct jpeg_compress_struct cinfo; + struct jpeg_error_mgr jerr; + + JSAMPROW row_pointer[1]; + FILE *outfile = fopen( jpegFilename, "wb" ); + + // try to open file for saving + if (!outfile) { + errno_exit("jpeg"); + } + + // create jpeg data + cinfo.err = jpeg_std_error( &jerr ); + jpeg_create_compress(&cinfo); + jpeg_stdio_dest(&cinfo, outfile); + + // set image parameters + cinfo.image_width = width; + cinfo.image_height = height; + cinfo.input_components = 3; + cinfo.in_color_space = JCS_YCbCr; + + // set jpeg compression parameters to default + jpeg_set_defaults(&cinfo); + // and then adjust quality setting + jpeg_set_quality(&cinfo, jpegQuality, TRUE); + + // start compress + jpeg_start_compress(&cinfo, TRUE); + + // feed data + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = &img[cinfo.next_scanline * cinfo.image_width * cinfo.input_components]; + jpeg_write_scanlines(&cinfo, row_pointer, 1); + } + + // finish compression + jpeg_finish_compress(&cinfo); + + // destroy jpeg data + jpeg_destroy_compress(&cinfo); + + // close output file + fclose(outfile); +} + + diff --git a/package/starfive/v4l2_test/common.h b/package/starfive/v4l2_test/common.h new file mode 100644 index 00000000..e2892186 --- /dev/null +++ b/package/starfive/v4l2_test/common.h @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef TEST_VERSION +#define TEST_VERSION "v0.0.1" +#endif + +#define BUFCOUNT 4 + +#define CLEAR(x) memset (&(x), 0, sizeof (x)) +#define PCLEAR(x) memset ((x), 0, sizeof (*x)) + +struct buffer { + void* start; + size_t length; + int dmabuf_fd; + int index; +}; + +enum COLOR_FORMAT{ + COLOR_YUV422_UYVY = 0, // 00={Y1,V0,Y0,U0} + COLOR_YUV422_VYUY = 1, // 01={Y1,U0,Y0,V0} + COLOR_YUV422_YUYV = 2, // 10={V0,Y1,U0,Y0} + COLOR_YUV422_YVYU = 3, // 11={U0,Y1,V0,Y0} + + COLOR_YUV420P, // 4 + COLOR_YUV420_NV21, // 5 + COLOR_YUV420_NV12, // 6 + + COLOR_RGB888_ARGB, // 7 + COLOR_RGB888_ABGR, // 8 + COLOR_RGB888_RGBA, // 9 + COLOR_RGB888_BGRA, // 10 + COLOR_RGB565, // 11 +}; + +typedef enum IOMethod { + IO_METHOD_MMAP, + IO_METHOD_USERPTR, + IO_METHOD_DMABUF, + IO_METHOD_READ +} IOMethod; + +typedef enum STF_DISP_TYPE { + STF_DISP_NONE = 0, // Not display + STF_DISP_FB, // Use framebuffer framework display + STF_DISP_DRM // Use drm framework display +} STF_DISP_TYPE; + +extern void dump_fourcc(uint32_t fourcc); +extern int v4l2fmt_to_fbfmt(uint32_t format); +extern uint32_t v4l2fmt_to_drmfmt(uint32_t v4l2_fmt); +extern void test_performance(); +extern void errno_exit(const char* s); +extern void errno_print(const char *s); +extern int write_file(char * filename, const unsigned char *image_buffer, int size); +// extern void jpegWrite(unsigned char* img, char* jpegFilename); +extern void jpegWrite(unsigned char* img, char* jpegFilename, + uint32_t width, uint32_t height, int jpegQuality); +extern int write_JPEG_file(char * filename,unsigned char *image_buffer, + int image_width, int image_height, int quality); + +// inline int clip(int value, int min, int max) { +// return (value > max ? max : value < min ? min : value); +// } + + +#endif // __COMMON_H__ diff --git a/package/v4l2_test/config.h b/package/starfive/v4l2_test/config.h old mode 100755 new mode 100644 similarity index 100% rename from package/v4l2_test/config.h rename to package/starfive/v4l2_test/config.h diff --git a/package/v4l2_test/convert.c b/package/starfive/v4l2_test/convert.c old mode 100755 new mode 100644 similarity index 56% rename from package/v4l2_test/convert.c rename to package/starfive/v4l2_test/convert.c index 89bdc88e..4231ffa4 --- a/package/v4l2_test/convert.c +++ b/package/starfive/v4l2_test/convert.c @@ -1,56 +1,73 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ +#include "common.h" -extern struct fb_var_screeninfo vinfo; -extern struct fb_fix_screeninfo finfo; -extern int screensize; +static int g_screen_width = 0; +static int g_screen_height = 0; +static int g_screen_bpp = 0; +static int g_screen_size = 0; +static int g_screen_distype = 0; // STF_DISP_FB or STF_DISP_DRM -int yuyv_resize(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight) +void update_videocvt_param(int distype, int scr_width, int scr_height, + int scr_bpp, int scr_size) { - int rows ,cols; /* 行列标志 */ - unsigned char *YUVindata, *YUVoutdata; /* YUV和RGB数据指针 */ - int YUVinpos; /* Y U V在数据缓存中的偏移 */ - unsigned int i = 0; + g_screen_distype = distype; + g_screen_width = scr_width; + g_screen_height = scr_height; + g_screen_bpp = scr_bpp; + g_screen_size = scr_size; +} + +int yuyv_resize(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight) +{ + int rows; + const uint8_t *YUVindata; + uint8_t *YUVoutdata; /* YUV and RGB pointer */ + int YUVinpos; /* Y U V offset */ int width, height; int x_offset, y_offset; - unsigned char *tmp = malloc(screensize); - unsigned int start_timems; - unsigned int end_timems; + uint32_t start_timems; + uint32_t end_timems; struct timeval ts_start, ts_end; + static uint8_t *tmp = NULL; if (!tmp) - return -1; + { + tmp = malloc(g_screen_size); + if (tmp) + { + // for YUYV buffer, set it to black + for ( rows = 0; rows < g_screen_size; rows++) + { + if (rows == 0 || rows % 2 == 0) + { + //even is Y + tmp[rows] = 0; + } + else + { + //odd is U or V + tmp[rows] = 128; + } + } + } + } + assert(tmp); gettimeofday(&ts_start, NULL); - width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth; - height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight; - x_offset = (vinfo.xres - width) / 2; - y_offset = (vinfo.yres - height) / 2; + width = imgWidth > g_screen_width ? g_screen_width : imgWidth; + height = imgHeight > g_screen_height ? g_screen_height : imgHeight; + x_offset = (g_screen_width - width) / 2; + y_offset = (g_screen_height - height) / 2; YUVindata = inBuf; YUVoutdata = tmp; - if (imgWidth == vinfo.xres) { - YUVinpos = (y_offset * vinfo.xres + x_offset) * 2; + if (imgWidth == g_screen_width) { + YUVinpos = (y_offset * g_screen_width + x_offset) * 2; memcpy(&tmp[YUVinpos], inBuf, imgWidth * height * 2); memcpy(&outBuf[YUVinpos], &tmp[YUVinpos], imgWidth * height * 2); // memcpy(&outBuf[YUVinpos], inBuf, imgWidth * height * 2); @@ -58,15 +75,15 @@ int yuyv_resize(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int i start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000; end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000; // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int)); - free(tmp); + //free(tmp); return 0; } - /* 每个像素两个字节 */ + /* two bytes for one pixels */ for(rows = 0; rows < height; rows++) { - // vinfo.xres, vinfo.yres vinfo.bits_per_pixel - YUVoutdata = tmp + ((rows + y_offset) * vinfo.xres + x_offset) * 2; + // g_screen_width, g_screen_height g_screen_bpp + YUVoutdata = tmp + ((rows + y_offset) * g_screen_width + x_offset) * 2; YUVinpos = rows * imgWidth * 2; memcpy(YUVoutdata, &YUVindata[YUVinpos], imgWidth * 2); @@ -79,53 +96,61 @@ int yuyv_resize(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int i gettimeofday(&ts_start, NULL); - memcpy(outBuf, tmp, screensize); + memcpy(outBuf, tmp, g_screen_size); gettimeofday(&ts_end, NULL); start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000; end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000; // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int)); - free(tmp); + //free(tmp); return 0; } -int convert_yuyv_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_yuyv) +int convert_yuyv_to_nv12(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int is_yuyv) { - int rows ,cols; /* 行列标志 */ - int y, u, v, r, g, b; /* yuv rgb 相关分量 */ - unsigned char *nv12data, *YUVdata; /* YUV和RGB数据指针 */ - int Ypos, Upos, Vpos; /* Y U V在数据缓存中的偏移 */ - int fb_Ypos, fb_Upos, fb_Vpos; /* Y U V在数据缓存中的偏移 */ - unsigned int i = 0; + int rows, cols; + const uint8_t *YUVdata; + uint8_t *nv12data; + int Ypos; + int fb_Ypos, fb_Upos, fb_Vpos; int width, height; int x_offset, y_offset; - unsigned char *tmp = malloc(screensize); - unsigned int start_timems; - unsigned int end_timems; + uint32_t start_timems; + uint32_t end_timems; struct timeval ts_start, ts_end; + static uint8_t *tmp = NULL; if (!tmp) - return -1; + { + tmp = malloc(g_screen_size); + if (tmp) + { + // for NV12 buffer, set it to black + memset(tmp, 0, g_screen_size / 3 * 2); + memset(tmp + g_screen_size / 3 * 2, 128, g_screen_size / 3); + } + } + assert(tmp); gettimeofday(&ts_start, NULL); - width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth; - height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight; - x_offset = (vinfo.xres - width) / 2; - y_offset = (vinfo.yres - height) / 2; + width = imgWidth > g_screen_width ? g_screen_width : imgWidth; + height = imgHeight > g_screen_height ? g_screen_height : imgHeight; + x_offset = (g_screen_width - width) / 2; + y_offset = (g_screen_height - height) / 2; YUVdata = inBuf; nv12data = tmp; - /* 每个像素两个字节 */ + /* two bytes for every pixels */ for(rows = 0; rows < height; rows++) { - // vinfo.xres, vinfo.yres vinfo.bits_per_pixel - fb_Ypos = ((rows + y_offset) * vinfo.xres + x_offset); - fb_Upos = ((rows + y_offset) / 2 * vinfo.xres / 2 + x_offset / 2) * 2; - fb_Upos = vinfo.xres * vinfo.yres + fb_Upos; + // g_screen_width, g_screen_height g_screen_bpp + fb_Ypos = ((rows + y_offset) * g_screen_width + x_offset); + fb_Upos = ((rows + y_offset) / 2 * g_screen_width / 2 + x_offset / 2) * 2; + fb_Upos = g_screen_width * g_screen_height + fb_Upos; fb_Vpos = fb_Upos + 1; Ypos = rows * imgWidth * 2; @@ -145,82 +170,101 @@ int convert_yuyv_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWid gettimeofday(&ts_start, NULL); - memcpy(outBuf, tmp, screensize); + memcpy(outBuf, tmp, g_screen_size); gettimeofday(&ts_end, NULL); start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000; end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000; // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int)); - free(tmp); + //free(tmp); return 0; } -int convert_nv21_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21) +int convert_nv21_to_nv12(const uint8_t *inBuf, uint8_t *outBuf, + int imgWidth, int imgHeight, int uv_changed) { - int rows ,cols; /* 行列标志 */ - int y, u, v, r, g, b; /* yuv rgb 相关分量 */ - unsigned char *nv12data, *nv21data; /* YUV和RGB数据指针 */ - int Ypos, Upos, Vpos; /* Y U V在数据缓存中的偏移 */ - int fb_Ypos, fb_Upos, fb_Vpos; /* Y U V在数据缓存中的偏移 */ - unsigned int i = 0; + int rows, cols; + const uint8_t *nv21data; + uint8_t *nv12data; + int Ypos, Upos, Vpos; + int fb_Ypos, fb_Upos, fb_Vpos; int width, height; int x_offset, y_offset; - unsigned char *tmp = malloc(screensize); - unsigned int start_timems; - unsigned int end_timems; + static uint8_t *tmp = NULL; + uint32_t start_timems; + uint32_t end_timems; struct timeval ts_start, ts_end; if (!tmp) - return -1; + { + tmp = malloc(g_screen_size); + if (tmp) + { + // for NV12 buffer, set it to black + memset(tmp, 0, g_screen_size / 3 * 2); + memset(tmp + g_screen_size / 3 * 2, 128, g_screen_size / 3); + } + } + assert(tmp); gettimeofday(&ts_start, NULL); - width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth; - height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight; - x_offset = (vinfo.xres - width) / 2; - y_offset = (vinfo.yres - height) / 2; + width = imgWidth > g_screen_width ? g_screen_width : imgWidth; + height = imgHeight > g_screen_height ? g_screen_height : imgHeight; + x_offset = (g_screen_width - width) / 2; + y_offset = (g_screen_height - height) / 2; nv21data = inBuf; nv12data = tmp; - if (imgWidth == vinfo.xres) { - fb_Ypos = y_offset * vinfo.xres + x_offset; - fb_Upos = (y_offset / 2 * vinfo.xres / 2 + x_offset / 2) * 2; - fb_Upos = vinfo.xres * vinfo.yres + fb_Upos; + // printf("[%s,%d]:imgWidth=%d, imgHeight=%d, g_screen_width=%d g_screen_height=%d g_screen_bpp=%d\n",__FUNCTION__,__LINE__, + // imgWidth, imgHeight, g_screen_width, g_screen_height, g_screen_bpp); + + // below for same image size and not uv changed + if (imgWidth == g_screen_width && !uv_changed) { + fb_Ypos = y_offset * g_screen_width + x_offset; + fb_Upos = (y_offset / 2 * g_screen_width / 2 + x_offset / 2) * 2; + fb_Upos = g_screen_width * g_screen_height + fb_Upos; Upos = imgWidth * imgHeight; - memcpy(&tmp[fb_Ypos], inBuf, imgWidth * height); - memcpy(&tmp[fb_Upos], &inBuf[Upos], imgWidth * height / 2); - memcpy(&outBuf[fb_Ypos], &tmp[fb_Ypos], imgWidth * height * 2); - memcpy(&outBuf[fb_Upos], &tmp[fb_Upos], imgWidth * height / 2); - // memcpy(&outBuf[fb_Ypos], inBuf, imgWidth * height); - // memcpy(&outBuf[fb_Upos], inBuf, imgWidth * height / 2); - free(tmp); + + if (STF_DISP_FB == g_screen_distype) { + // TODO: it is strange that with tmp buffer will more faster for framebuf + memcpy(&tmp[fb_Ypos], inBuf, imgWidth * height); + memcpy(&tmp[fb_Upos], &inBuf[Upos], imgWidth * height / 2); + memcpy(&outBuf[fb_Ypos], &tmp[fb_Ypos], imgWidth * height); + memcpy(&outBuf[fb_Upos], &tmp[fb_Upos], imgWidth * height / 2); + } else { + memcpy(&outBuf[fb_Ypos], inBuf, imgWidth * height); + memcpy(&outBuf[fb_Upos], &inBuf[Upos], imgWidth * height / 2); + } + //free(tmp); return 0; } - /* 每个像素两个字节 */ + /* two bytes for every pixels */ for(rows = 0; rows < height; rows+=2) { - // vinfo.xres, vinfo.yres vinfo.bits_per_pixel - fb_Ypos = ((rows + y_offset) * vinfo.xres + x_offset); - fb_Upos = ((rows + y_offset) / 2 * vinfo.xres / 2 + x_offset / 2) * 2; - fb_Upos = vinfo.xres * vinfo.yres + fb_Upos; + // g_screen_width, g_screen_height g_screen_bpp + fb_Ypos = ((rows + y_offset) * g_screen_width + x_offset); + fb_Upos = ((rows + y_offset) / 2 * g_screen_width / 2 + x_offset / 2) * 2; + fb_Upos = g_screen_width * g_screen_height + fb_Upos; fb_Vpos = fb_Upos + 1; Ypos = rows * imgWidth; Upos = imgWidth * imgHeight + Ypos / 2; Vpos = Upos + 1; memcpy(&nv12data[fb_Ypos], &nv21data[Ypos], width); - memcpy(&nv12data[fb_Ypos+vinfo.xres], &nv21data[Ypos+imgWidth], width); + memcpy(&nv12data[fb_Ypos+g_screen_width], &nv21data[Ypos+imgWidth], width); - if (is_nv21) { + if (uv_changed) { for (cols = 0; cols < width; cols += 2) { nv12data[fb_Upos+cols] = nv21data[Vpos+cols]; nv12data[fb_Vpos+cols] = nv21data[Upos+cols]; } - } else + } else { memcpy(&nv12data[fb_Upos], &nv21data[Upos], width); + } } gettimeofday(&ts_end, NULL); @@ -230,29 +274,30 @@ int convert_nv21_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWid gettimeofday(&ts_start, NULL); - memcpy(outBuf, tmp, screensize); + memcpy(outBuf, tmp, g_screen_size); gettimeofday(&ts_end, NULL); start_timems = ts_start.tv_sec * 1000 + ts_start.tv_usec/1000; end_timems = ts_end.tv_sec * 1000 + ts_end.tv_usec/1000; // printf("%s: copy use %dms, sizeof(int) = %d\n", __func__, end_timems - start_timems, sizeof(int)); - free(tmp); + //free(tmp); return 0; } -int convert_nv21_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21) +int convert_nv21_to_rgb(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int is_nv21) { - int rows ,cols; /* 行列标志 */ - int y, u, v, r, g, b; /* yuv rgb 相关分量 */ - unsigned char *YUVdata, *RGBdata; /* YUV和RGB数据指针 */ - int Ypos, Upos, Vpos; /* Y U V在数据缓存中的偏移 */ - unsigned int i = 0; + int rows ,cols; + int y, u, v, r, g, b; + const uint8_t *YUVdata; + uint8_t *RGBdata; + int Ypos, Upos, Vpos; + uint32_t i = 0; int width, height; int x_offset, y_offset; - unsigned char *tmp = malloc(screensize); - unsigned int start_timems; - unsigned int end_timems; + uint8_t *tmp = malloc(g_screen_size); + uint32_t start_timems; + uint32_t end_timems; struct timeval ts_start, ts_end; if (!tmp) @@ -260,19 +305,19 @@ int convert_nv21_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidt gettimeofday(&ts_start, NULL); - width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth; - height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight; - x_offset = (vinfo.xres - width) / 2; - y_offset = (vinfo.yres - height) / 2; + width = imgWidth > g_screen_width ? g_screen_width : imgWidth; + height = imgHeight > g_screen_height ? g_screen_height : imgHeight; + x_offset = (g_screen_width - width) / 2; + y_offset = (g_screen_height - height) / 2; YUVdata = inBuf; RGBdata = tmp; - /* 每个像素两个字节 */ + /* two bytes for every pixels */ for(rows = 0; rows < height; rows++) { - // vinfo.xres, vinfo.yres vinfo.bits_per_pixel - RGBdata = tmp + ((rows + y_offset) * vinfo.xres + x_offset) * vinfo.bits_per_pixel / 8; + // g_screen_width, g_screen_height g_screen_bpp + RGBdata = tmp + ((rows + y_offset) * g_screen_width + x_offset) * g_screen_bpp / 8; Ypos = rows * imgWidth; Vpos = Upos = imgWidth * imgHeight + Ypos / 2; @@ -282,9 +327,8 @@ int convert_nv21_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidt Upos = Vpos + 1; i = 0; - for(cols = 0; cols < width; cols++) + for (cols = 0; cols < width; cols++) { - /* 矩阵推到,百度 */ y = YUVdata[Ypos]; u = YUVdata[Upos] - 128; v = YUVdata[Vpos] - 128; @@ -297,11 +341,11 @@ int convert_nv21_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidt g = g > 255 ? 255 : (g < 0 ? 0 : g); b = b > 255 ? 255 : (b < 0 ? 0 : b); - /* 从低到高r g b */ - if (vinfo.bits_per_pixel == 16) { // RGB565 - *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3)); /* g低5位,b高5位 */ - *(RGBdata ++) = ((r & 0xf8) | (g >> 5)); /* r高5位,g高3位 */ - } else if (vinfo.bits_per_pixel == 24) { // RGB888 + /* low -> high r g b */ + if (g_screen_bpp == 16) { // RGB565 + *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3)); /* g low 5bit,b high 5bit */ + *(RGBdata ++) = ((r & 0xf8) | (g >> 5)); /* r high 5bit,g high 3bit */ + } else if (g_screen_bpp == 24) { // RGB888 *(RGBdata ++) = b; *(RGBdata ++) = g; *(RGBdata ++) = r; @@ -313,7 +357,7 @@ int convert_nv21_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidt } Ypos++; i++; - /* 每4个Y更新一次UV */ + /* every 4 time y to update 1 time uv */ if(!(i & 0x03)) { Vpos = Upos = imgWidth * imgHeight + Ypos/2; @@ -333,10 +377,10 @@ int convert_nv21_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidt gettimeofday(&ts_start, NULL); #if 1 - memcpy(outBuf, tmp, screensize); + memcpy(outBuf, tmp, g_screen_size); #else int *p_outBuf, *p_tmp; - int size = screensize/4; + int size = g_screen_size/4; p_outBuf = outBuf; p_tmp = tmp; @@ -393,13 +437,13 @@ static int Rgb2V(int r0, int g0, int b0) //Y1 -> yyyyyy //UV0 points destination rows of interleaved UV plane. //UV0 -> uvuvuv -static void Rgb2NV12TwoRows(const unsigned char I0[], - const unsigned char I1[], +static void Rgb2NV12TwoRows(const uint8_t I0[], + const uint8_t I1[], int step, const int image_width, - unsigned char Y0[], - unsigned char Y1[], - unsigned char UV0[]) + uint8_t Y0[], + uint8_t Y1[], + uint8_t UV0[]) { int x; //Column index @@ -407,48 +451,48 @@ static void Rgb2NV12TwoRows(const unsigned char I0[], for (x = 0; x < image_width; x += 2) { //Load R,G,B elements from first row (and convert to int). - unsigned char b00 = (I0[x*step + 0] & 0x1F) << 3; - unsigned char g00 = ((I0[x*step + 1] & 0x7) << 3 | I0[x*step + 0] >> 5) << 2; - unsigned char r00 = I0[x*step + 1] & (~0x7); + uint8_t b00 = (I0[x*step + 0] & 0x1F) << 3; + uint8_t g00 = ((I0[x*step + 1] & 0x7) << 3 | I0[x*step + 0] >> 5) << 2; + uint8_t r00 = I0[x*step + 1] & (~0x7); //Load next R,G,B elements from first row (and convert to int). - unsigned char b01 = (I0[x*step + step+0] & 0x1F) << 3; - unsigned char g01 = ((I0[x*step + step+1] & 0x7) << 3 | I0[x*step + step+0] >> 5) << 2; - unsigned char r01 = I0[x*step + step+1] & (~0x7); + uint8_t b01 = (I0[x*step + step+0] & 0x1F) << 3; + uint8_t g01 = ((I0[x*step + step+1] & 0x7) << 3 | I0[x*step + step+0] >> 5) << 2; + uint8_t r01 = I0[x*step + step+1] & (~0x7); //Load R,G,B elements from second row (and convert to int). - unsigned char b10 = (I1[x*step + 0] & 0x1F) << 3; - unsigned char g10 = ((I1[x*step + 1] & 0x7) << 3 | I1[x*step + 0] >> 5) << 2; - unsigned char r10 = I1[x*step + 1] & (~0x7); + uint8_t b10 = (I1[x*step + 0] & 0x1F) << 3; + uint8_t g10 = ((I1[x*step + 1] & 0x7) << 3 | I1[x*step + 0] >> 5) << 2; + uint8_t r10 = I1[x*step + 1] & (~0x7); //Load next R,G,B elements from second row (and convert to int). - unsigned char b11 = (I1[x*step + step+0] & 0x1F) << 3; - unsigned char g11 = ((I1[x*step + step+1] & 0x7) << 3 | I1[x*step + step+0] >> 5) << 2; - unsigned char r11 = I1[x*step + step+1] & (~0x7); + uint8_t b11 = (I1[x*step + step+0] & 0x1F) << 3; + uint8_t g11 = ((I1[x*step + step+1] & 0x7) << 3 | I1[x*step + step+0] >> 5) << 2; + uint8_t r11 = I1[x*step + step+1] & (~0x7); //Calculate 4 Y elements. - unsigned char y00 = Rgb2Y(r00, g00, b00); - unsigned char y01 = Rgb2Y(r01, g01, b01); - unsigned char y10 = Rgb2Y(r10, g10, b10); - unsigned char y11 = Rgb2Y(r11, g11, b11); + uint8_t y00 = Rgb2Y(r00, g00, b00); + uint8_t y01 = Rgb2Y(r01, g01, b01); + uint8_t y10 = Rgb2Y(r10, g10, b10); + uint8_t y11 = Rgb2Y(r11, g11, b11); //Calculate 4 U elements. - unsigned char u00 = Rgb2U(r00, g00, b00); - unsigned char u01 = Rgb2U(r01, g01, b01); - unsigned char u10 = Rgb2U(r10, g10, b10); - unsigned char u11 = Rgb2U(r11, g11, b11); + uint8_t u00 = Rgb2U(r00, g00, b00); + uint8_t u01 = Rgb2U(r01, g01, b01); + uint8_t u10 = Rgb2U(r10, g10, b10); + uint8_t u11 = Rgb2U(r11, g11, b11); //Calculate 4 V elements. - unsigned char v00 = Rgb2V(r00, g00, b00); - unsigned char v01 = Rgb2V(r01, g01, b01); - unsigned char v10 = Rgb2V(r10, g10, b10); - unsigned char v11 = Rgb2V(r11, g11, b11); + uint8_t v00 = Rgb2V(r00, g00, b00); + uint8_t v01 = Rgb2V(r01, g01, b01); + uint8_t v10 = Rgb2V(r10, g10, b10); + uint8_t v11 = Rgb2V(r11, g11, b11); //Calculate destination U element: average of 2x2 "original" U elements. - unsigned char u0 = (u00 + u01 + u10 + u11)/4; + uint8_t u0 = (u00 + u01 + u10 + u11)/4; //Calculate destination V element: average of 2x2 "original" V elements. - unsigned char v0 = (v00 + v01 + v10 + v11)/4; + uint8_t v0 = (v00 + v01 + v10 + v11)/4; //Store 4 Y elements (two in first row and two in second row). Y0[x + 0] = y00; @@ -487,34 +531,34 @@ static void Rgb2NV12TwoRows(const unsigned char I0[], //1. image_width must be a multiple of 2. //2. image_height must be a multiple of 2. //3. I and J must be two separate arrays (in place computation is not supported). -void Rgb2NV12(const unsigned char I[], int step, +void Rgb2NV12(const uint8_t I[], int step, const int image_width, const int image_height, - unsigned char J[]) + uint8_t J[]) { //In NV12 format, UV plane starts below Y plane. - // unsigned char *UV = &J[image_width*image_height]; - unsigned char *UV = J; + // uint8_t *UV = &J[image_width*image_height]; + uint8_t *UV = J; //I0 and I1 points two sequential source rows. - const unsigned char *I0; //I0 -> rgbrgbrgbrgbrgbrgb... - const unsigned char *I1; //I1 -> rgbrgbrgbrgbrgbrgb... + const uint8_t *I0; //I0 -> rgbrgbrgbrgbrgbrgb... + const uint8_t *I1; //I1 -> rgbrgbrgbrgbrgbrgb... //Y0 and Y1 points two sequential destination rows of Y plane. - unsigned char *Y0; //Y0 -> yyyyyy - unsigned char *Y1; //Y1 -> yyyyyy + uint8_t *Y0; //Y0 -> yyyyyy + uint8_t *Y1; //Y1 -> yyyyyy //UV0 points destination rows of interleaved UV plane. - unsigned char *UV0; //UV0 -> uvuvuv + uint8_t *UV0; //UV0 -> uvuvuv int y; //Row index int width, height; int x_offset, y_offset; - width = image_width > vinfo.xres ? vinfo.xres : image_width; - height = image_height > vinfo.yres ? vinfo.yres : image_height; - x_offset = (vinfo.xres - width) / 2; - y_offset = (vinfo.yres - height) / 2; + width = image_width > g_screen_width ? g_screen_width : image_width; + height = image_height > g_screen_height ? g_screen_height : image_height; + x_offset = (g_screen_width - width) / 2; + y_offset = (g_screen_height - height) / 2; //In each iteration: process two rows of Y plane, and one row of interleaved UV plane. for (y = 0; y < height; y += 2) @@ -522,10 +566,10 @@ void Rgb2NV12(const unsigned char I[], int step, I0 = &I[y*image_width*step]; //Input row width is image_width*3 bytes (each pixel is R,G,B). I1 = &I[(y+1)*image_width*step]; - Y0 = &J[(y+y_offset)*vinfo.xres+x_offset]; //Output Y row width is image_width bytes (one Y element per pixel). - Y1 = &J[(y+1+y_offset)*vinfo.xres+x_offset]; + Y0 = &J[(y+y_offset)*g_screen_width+x_offset]; //Output Y row width is image_width bytes (one Y element per pixel). + Y1 = &J[(y+1+y_offset)*g_screen_width+x_offset]; - UV0 = &UV[vinfo.xres*vinfo.yres+((y+y_offset)/2*vinfo.xres/2+x_offset/2)*2]; //Output UV row - width is same as Y row width. + UV0 = &UV[g_screen_width*g_screen_height+((y+y_offset)/2*g_screen_width/2+x_offset/2)*2]; //Output UV row - width is same as Y row width. //Process two source rows into: Two Y destination row, and one destination interleaved U,V row. Rgb2NV12TwoRows(I0, @@ -538,20 +582,14 @@ void Rgb2NV12(const unsigned char I[], int step, } } -int convert_rgb565_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21) +int convert_rgb565_to_nv12(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int is_nv21) { - int rows ,cols; /* 行列标志 */ - int y, u, v, r, g, b; /* yuv rgb 相关分量 */ - unsigned char *YUVdata, *RGBdata; /* YUV和RGB数据指针 */ - int Ypos, Upos, Vpos; /* Y U V在数据缓存中的偏移 */ - unsigned int i = 0; - unsigned char *tmp = malloc(screensize); - unsigned int start_timems; - unsigned int end_timems; + uint8_t *tmp = malloc(g_screen_size); + uint32_t start_timems; + uint32_t end_timems; struct timespec ts_start, ts_end; clock_gettime(CLOCK_MONOTONIC, &ts_start); - Rgb2NV12(inBuf, 2, imgWidth, imgHeight, tmp); clock_gettime(CLOCK_MONOTONIC, &ts_end); @@ -561,7 +599,7 @@ int convert_rgb565_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgW clock_gettime(CLOCK_MONOTONIC, &ts_start); - memcpy(outBuf, tmp, screensize); + memcpy(outBuf, tmp, g_screen_size); clock_gettime(CLOCK_MONOTONIC, &ts_end); start_timems = ts_start.tv_sec * 1000 + ts_start.tv_nsec/1000000; @@ -572,34 +610,35 @@ int convert_rgb565_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgW return 0; } -int convert_yuyv_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod) +int convert_yuyv_to_rgb(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int cvtMethod) { - int rows ,cols; /* 行列标志 */ - int y, u, v, r, g, b; /* yuv rgb 相关分量 */ - unsigned char *YUVdata, *RGBdata; /* YUV和RGB数据指针 */ - int Ypos, Upos, Vpos; /* Y U V在数据缓存中的偏移 */ - unsigned int i = 0; + int rows ,cols; + int y, u, v, r, g, b; + const uint8_t *YUVdata; + uint8_t *RGBdata; + int Ypos, Upos, Vpos; + uint32_t i = 0; int width, height; int x_offset, y_offset; - unsigned char *tmp = malloc(screensize); - unsigned int start_timems; - unsigned int end_timems; + uint8_t *tmp = malloc(g_screen_size); + uint32_t start_timems; + uint32_t end_timems; struct timespec ts_start, ts_end; clock_gettime(CLOCK_MONOTONIC, &ts_start); - width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth; - height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight; - x_offset = (vinfo.xres - width) / 2; - y_offset = (vinfo.yres - height) / 2; + width = imgWidth > g_screen_width ? g_screen_width : imgWidth; + height = imgHeight > g_screen_height ? g_screen_height : imgHeight; + x_offset = (g_screen_width - width) / 2; + y_offset = (g_screen_height - height) / 2; YUVdata = inBuf; RGBdata = tmp; - /* 每个像素两个字节 */ + /* two bytes for every pixels */ for(rows = 0; rows < height; rows++) { - // vinfo.xres, vinfo.yres vinfo.bits_per_pixel - RGBdata = tmp + ((rows + y_offset) * vinfo.xres + x_offset) * vinfo.bits_per_pixel / 8; + // g_screen_width, g_screen_height g_screen_bpp + RGBdata = tmp + ((rows + y_offset) * g_screen_width + x_offset) * g_screen_bpp / 8; Ypos = rows * imgWidth * 2; Upos = Ypos + 1; @@ -608,7 +647,6 @@ int convert_yuyv_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidt for(cols = 0; cols < width; cols++) { - /* 矩阵推到,百度 */ y = YUVdata[Ypos]; u = YUVdata[Upos] - 128; v = YUVdata[Vpos] - 128; @@ -621,11 +659,11 @@ int convert_yuyv_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidt g = g > 255 ? 255 : (g < 0 ? 0 : g); b = b > 255 ? 255 : (b < 0 ? 0 : b); - /* 从低到高r g b */ - if (vinfo.bits_per_pixel == 16) { // RGB565 - *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3)); /* g低5位,b高5位 */ - *(RGBdata ++) = ((r & 0xf8) | (g >> 5)); /* r高5位,g高3位 */ - } else if (vinfo.bits_per_pixel == 24) { // RGB888 + /* low -> high r g b */ + if (g_screen_bpp == 16) { // RGB565 + *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3)); /* g low 5bits,b high 5bits */ + *(RGBdata ++) = ((r & 0xf8) | (g >> 5)); /* r high 5bits, g high 3bits */ + } else if (g_screen_bpp == 24) { // RGB888 *(RGBdata ++) = b; *(RGBdata ++) = g; *(RGBdata ++) = r; @@ -635,11 +673,11 @@ int convert_yuyv_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidt *(RGBdata ++) = r; *(RGBdata ++) = 0xFF; } - /* 两个字节数据中包含一个Y */ + /* two bytes contain 1 y */ Ypos += 2; //Ypos++; i++; - /* 每两个Y更新一次UV */ + /* every 2 y to update 1 uv */ if(!(i & 0x01)) { Upos = Ypos + 1; @@ -655,7 +693,7 @@ int convert_yuyv_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidt clock_gettime(CLOCK_MONOTONIC, &ts_start); - memcpy(outBuf, tmp, screensize); + memcpy(outBuf, tmp, g_screen_size); clock_gettime(CLOCK_MONOTONIC, &ts_end); start_timems = ts_start.tv_sec * 1000 + ts_start.tv_nsec/1000000; @@ -666,15 +704,13 @@ int convert_yuyv_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidt return 0; } -int convert_yuv444_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod) +int convert_yuv444_to_rgb(uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int cvtMethod) { - int rows ,cols; /* 行列标志 */ - int y, u, v, r, g, b; /* yuv rgb 相关分量 */ - unsigned char *YUVdata, *RGBdata; /* YUV和RGB数据指针 */ - int Ypos, Upos, Vpos; /* Y U V在数据缓存中的偏移 */ - unsigned int i = 0; - unsigned short bar = 0; - unsigned char *tmp = malloc(screensize); + int rows ,cols; + int y, u, v, r, g, b; + uint8_t *YUVdata, *RGBdata; + int Ypos; + uint8_t *tmp = malloc(g_screen_size); YUVdata = inBuf; RGBdata = tmp; @@ -697,11 +733,11 @@ int convert_yuv444_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWi g = g > 255 ? 255 : (g < 0 ? 0 : g); b = b > 255 ? 255 : (b < 0 ? 0 : b); - /* 从低到高r g b */ - if (vinfo.bits_per_pixel == 16) { // RGB565 - *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3)); /* g低5位,b高5位 */ - *(RGBdata ++) = ((r & 0xf8) | (g >> 5)); /* r高5位,g高3位 */ - } else if (vinfo.bits_per_pixel == 24) { // RGB888 + /* low -> high r g b */ + if (g_screen_bpp == 16) { // RGB565 + *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3)); /* g low 5bits,b high 5bits */ + *(RGBdata ++) = ((r & 0xf8) | (g >> 5)); /* r high 5bits,g high 3bits */ + } else if (g_screen_bpp == 24) { // RGB888 *(RGBdata ++) = b; *(RGBdata ++) = g; *(RGBdata ++) = r; @@ -715,30 +751,31 @@ int convert_yuv444_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWi } } - memcpy(outBuf, tmp, screensize); + memcpy(outBuf, tmp, g_screen_size); free(tmp); return 0; } -int convert_rgb565_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod) +int convert_rgb565_to_rgb(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int cvtMethod) { - int rows ,cols; /* 行列标志 */ - unsigned char *RGB565data, *RGBdata; /* YUV和RGB数据指针 */ + int rows ,cols; + const uint8_t *RGB565data; + uint8_t *RGBdata; int RGBpos; int width, height; int x_offset, y_offset; - unsigned char *tmp = malloc(screensize); + uint8_t *tmp = malloc(g_screen_size); - width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth; - height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight; - x_offset = (vinfo.xres - width) / 2; - y_offset = (vinfo.yres - height) / 2; + width = imgWidth > g_screen_width ? g_screen_width : imgWidth; + height = imgHeight > g_screen_height ? g_screen_height : imgHeight; + x_offset = (g_screen_width - width) / 2; + y_offset = (g_screen_height - height) / 2; RGB565data = inBuf; RGBdata = tmp; - if (imgWidth == vinfo.xres) { - RGBpos = (y_offset * vinfo.xres + x_offset) * 2; + if (imgWidth == g_screen_width) { + RGBpos = (y_offset * g_screen_width + x_offset) * 2; memcpy(&tmp[RGBpos], inBuf, imgWidth * height * 2); memcpy(&outBuf[RGBpos], &tmp[RGBpos], imgWidth * height * 2); // memcpy(&outBuf[RGBpos], inBuf, imgWidth * height * 2); @@ -749,9 +786,9 @@ int convert_rgb565_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWi RGBpos = 0; for(rows = 0; rows < imgHeight; rows++) { - RGBdata = tmp + ((rows + y_offset) * vinfo.xres + x_offset) * vinfo.bits_per_pixel / 8; + RGBdata = tmp + ((rows + y_offset) * g_screen_width + x_offset) * g_screen_bpp / 8; RGBpos = rows * imgWidth * 2; - if (vinfo.bits_per_pixel == 16) { // RGB565 + if (g_screen_bpp == 16) { // RGB565 memcpy(RGBdata, &RGB565data[RGBpos], imgWidth * 2); } else { for(cols = 0; cols < imgWidth; cols++) @@ -759,7 +796,7 @@ int convert_rgb565_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWi *(RGBdata ++) = RGB565data[RGBpos] & 0x1F; *(RGBdata ++) = (RGB565data[RGBpos + 1] & 0x7) << 3 | RGB565data[RGBpos] >> 5; *(RGBdata ++) = RGB565data[RGBpos + 1] >> 3; - if (vinfo.bits_per_pixel == 32) { // RGB888 + if (g_screen_bpp == 32) { // RGB888 *(RGBdata ++) = 0xFF; } RGBpos += 2; @@ -767,25 +804,26 @@ int convert_rgb565_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWi } } - memcpy(outBuf, tmp, screensize); + memcpy(outBuf, tmp, g_screen_size); free(tmp); return 0; } -int convert_rgb888_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod) +int convert_rgb888_to_rgb(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int cvtMethod) { - int rows ,cols; /* 行列标志 */ - unsigned char *RGB888data, *RGBdata; /* YUV和RGB数据指针 */ + int rows ,cols; + const uint8_t *RGB888data; + uint8_t *RGBdata; int RGBpos; int width, height; int x_offset, y_offset; - unsigned char *tmp = malloc(screensize); - unsigned char r, g, b; + uint8_t *tmp = malloc(g_screen_size); + uint8_t r, g, b; - width = imgWidth > vinfo.xres ? vinfo.xres : imgWidth; - height = imgHeight > vinfo.yres ? vinfo.yres : imgHeight; - x_offset = (vinfo.xres - width) / 2; - y_offset = (vinfo.yres - height) / 2; + width = imgWidth > g_screen_width ? g_screen_width : imgWidth; + height = imgHeight > g_screen_height ? g_screen_height : imgHeight; + x_offset = (g_screen_width - width) / 2; + y_offset = (g_screen_height - height) / 2; RGB888data = inBuf; RGBdata = tmp; @@ -793,19 +831,19 @@ int convert_rgb888_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWi RGBpos = 0; for(rows = 0; rows < imgHeight; rows++) { - RGBdata = tmp + ((rows + y_offset) * vinfo.xres + x_offset) * vinfo.bits_per_pixel / 8; + RGBdata = tmp + ((rows + y_offset) * g_screen_width + x_offset) * g_screen_bpp / 8; RGBpos = rows * imgWidth * 3; - if (vinfo.bits_per_pixel == 24) { // RGB888 + if (g_screen_bpp == 24) { // RGB888 memcpy(RGBdata, &RGB888data[RGBpos], imgWidth * 3); } else { for(cols = 0; cols < imgWidth; cols++) { - if (vinfo.bits_per_pixel == 16) { // RGB565 + if (g_screen_bpp == 16) { // RGB565 b = RGB888data[RGBpos]; g = RGB888data[RGBpos + 1]; r = RGB888data[RGBpos + 2]; - *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3)); /* g低5位,b高5位 */ - *(RGBdata ++) = ((r & 0xf8) | (g >> 5)); /* r高5位,g高3位 */ + *(RGBdata ++) = (((g & 0x1c) << 3) | (b >> 3)); /* g low 5bits,b high 5bits */ + *(RGBdata ++) = ((r & 0xf8) | (g >> 5)); /* r high 5bits,g high 3bits */ } else { // RGB8888 *(RGBdata ++) = RGB888data[RGBpos]; *(RGBdata ++) = RGB888data[RGBpos + 1]; @@ -817,7 +855,7 @@ int convert_rgb888_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWi } } - memcpy(outBuf, tmp, screensize); + memcpy(outBuf, tmp, g_screen_size); free(tmp); return 0; } diff --git a/package/starfive/v4l2_test/convert.h b/package/starfive/v4l2_test/convert.h new file mode 100644 index 00000000..00907dc7 --- /dev/null +++ b/package/starfive/v4l2_test/convert.h @@ -0,0 +1,23 @@ + +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ +#ifndef _CONVERT_H_ +#define _CONVERT_H_ + +extern int yuyv_resize(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight); + +extern int convert_yuyv_to_nv12(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int is_yuyv); +extern int convert_nv21_to_nv12(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int is_nv21); +extern int convert_nv21_to_rgb(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int is_nv21); +extern int convert_rgb565_to_nv12(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int is_nv21); +extern int convert_yuyv_to_rgb(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int cvtMethod); +extern int convert_yuv444_to_rgb(uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int cvtMethod); +extern int convert_rgb565_to_rgb(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int cvtMethod); +extern int convert_rgb888_to_rgb(const uint8_t *inBuf, uint8_t *outBuf, int imgWidth, int imgHeight, int cvtMethod); + +extern void update_videocvt_param(int distype, int scr_width, int scr_height, + int scr_bpp, int scr_size); + +#endif // _CONVERT_H_ diff --git a/package/starfive/v4l2_test/media-ctl-pipeline.sh b/package/starfive/v4l2_test/media-ctl-pipeline.sh new file mode 100644 index 00000000..fcb59d65 --- /dev/null +++ b/package/starfive/v4l2_test/media-ctl-pipeline.sh @@ -0,0 +1,376 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2021 StarFive Technology Co., Ltd. +# + +USAGE="Usage: + media-ctl-pipeline.sh -d devname -i interface_type -s sensor_type -a action + devname: Media device name (default select starfive media device) + interface_type One of the following: + dvp + csiphy0 + csiphy1 + + sensor_type One of the following: + VIN + ISP0 + ISP1 + ISP0RAW + ISP1RAW + + action One of the following: + start + stop + + example: + start pipeline: + media-ctl-pipeline.sh -d /dev/media0 -i dvp -s ISP0 -a start + + stop pipeline: + media-ctl-pipeline.sh -d /dev/media0 -i dvp -s ISP0 -a stop +" + +devname="/dev/media0" +index=0 +while [ $index -le 10 ] +do + dev="/dev/media""$index" + drivername=$(media-ctl -d $dev -p | grep driver | grep stf-vin) + if [ -n "$drivername" ]; then + devname=$dev + echo "found starfive media device: $devname" + break + fi + let index++ +done + +while getopts "d:i:s:a:" arg +do + case $arg in + d) + devname=$OPTARG + echo "select dev name: $devname" + ;; + i) + interface_type=$OPTARG + echo "select interface_type: $interface_type" + ;; + s) + sensor_type=$OPTARG + echo "select sensor_type: $sensor_type" + ;; + a) + action=$OPTARG + echo "select action: $action" + ;; + ?) + echo "unknow argument" + exit 1 + ;; + esac +done + +if [ -z "$devname" ]; then + echo "unknow media device" + echo "$USAGE" + exit 1 +fi + +if [ -z "$interface_type" ]; then + echo "unknow interface type" + echo "$USAGE" + exit 1 +fi + +if [ -z "$sensor_type" ]; then + echo "unknow sensor type" + echo "$USAGE" + exit 1 +fi + +if [ -z "$action" ]; then + echo "unknow action type" + echo "$USAGE" + exit 1 +fi + +echo "media-ctl-pipeline.sh -d $devname -i $interface_type -s $sensor_type -a $action" + +case $interface_type in + dvp) + case $action in + start) + # media-ctl -d "$devname" -vl "'sc2235 1-0030':0 -> 'stf_dvp0':0 [1]" + # media-ctl -d "$devname" -vl "'ov5640 1-003c':0 -> 'stf_dvp0':0 [1]" + case $sensor_type in + VIN) + echo "DVP vin enable pipeline:" + media-ctl -d "$devname" -vl "'stf_dvp0':1 -> 'stf_vin0_wr':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_wr':1 -> 'stf_vin0_wr_video0':0 [1]" + ;; + ISP0) + echo "DVP ISP0 enable pipeline:" + media-ctl -d "$devname" -vl "'stf_dvp0':1 -> 'stf_isp0':0 [1]" + media-ctl -d "$devname" -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]" + ;; + ISP0RAW) + echo "DVP ISP0RAW enable pipeline:" + media-ctl -d "$devname" -vl "'stf_dvp0':1 -> 'stf_isp0':0 [1]" + media-ctl -d "$devname" -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]" + ;; + ISP1) + echo "DVP ISP1 enable pipeline:" + media-ctl -d "$devname" -vl "'stf_dvp0':1 -> 'stf_isp1':0 [1]" + media-ctl -d "$devname" -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]" + ;; + ISP1RAW) + echo "DVP ISP1RAW enable pipeline:" + media-ctl -d "$devname" -vl "'stf_dvp0':1 -> 'stf_isp1':0 [1]" + media-ctl -d "$devname" -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]" + ;; + *) + echo "$USAGE" + exit 1 + ;; + esac + ;; + stop) + # media-ctl -d "$devname" -vl "'sc2235 1-0030':0 -> 'stf_dvp0':0 [0]" + # media-ctl -d "$devname" -vl "'ov5640 1-003c':0 -> 'stf_dvp0':0 [0]" + case $sensor_type in + VIN) + echo "DVP vin disable pipeline:" + media-ctl -d "$devname" -vl "'stf_dvp0':1 -> 'stf_vin0_wr':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_wr':1 -> 'stf_vin0_wr_video0':0 [0]" + ;; + ISP0) + echo "DVP ISP0 disable pipeline:" + media-ctl -d "$devname" -vl "'stf_dvp0':1 -> 'stf_isp0':0 [0]" + media-ctl -d "$devname" -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]" + ;; + ISP0RAW) + echo "DVP ISP0RAW disable pipeline:" + media-ctl -d "$devname" -vl "'stf_dvp0':1 -> 'stf_isp0':0 [0]" + media-ctl -d "$devname" -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]" + ;; + ISP1) + echo "DVP ISP1 disable pipeline:" + media-ctl -d "$devname" -vl "'stf_dvp0':1 -> 'stf_isp1':0 [0]" + media-ctl -d "$devname" -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]" + ;; + ISP1RAW) + echo "DVP ISP1RAW disable pipeline:" + media-ctl -d "$devname" -vl "'stf_dvp0':1 -> 'stf_isp1':0 [0]" + media-ctl -d "$devname" -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]" + ;; + *) + echo "$USAGE" + exit 1 + ;; + esac + ;; + *) + echo "$USAGE" + exit 1 + ;; + esac + ;; + csiphy0) + case $action in + start) + # media-ctl -d "$devname" -vl "'ov4689 0-0036':0 -> 'stf_csiphy0':0 [1]" + case $sensor_type in + VIN) + echo "csiphy0 CSIRX0 vin enable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]" + media-ctl -d "$devname" -vl "'stf_csi0':1 -> 'stf_vin0_wr':0 [1]" + ;; + ISP0) + echo "csiphy0 CSIRX0 ISP0 enable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]" + media-ctl -d "$devname" -vl "'stf_csi0':1 -> 'stf_isp0':0 [1]" + media-ctl -d "$devname" -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]" + ;; + ISP0RAW) + echo "csiphy0 CSIRX0 ISP0RAW enable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]" + media-ctl -d "$devname" -vl "'stf_csi0':1 -> 'stf_isp0':0 [1]" + media-ctl -d "$devname" -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]" + ;; + ISP1) + echo "csiphy0 CSIRX0 ISP1 enable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]" + media-ctl -d "$devname" -vl "'stf_csi0':1 -> 'stf_isp1':0 [1]" + media-ctl -d "$devname" -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]" + ;; + ISP1RAW) + echo "csiphy0 CSIRX0 ISP1RAW enable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]" + media-ctl -d "$devname" -vl "'stf_csi0':1 -> 'stf_isp1':0 [1]" + media-ctl -d "$devname" -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]" + ;; + + *) + echo "$USAGE" + exit 1 + ;; + esac + ;; + stop) + # media-ctl -d "$devname" -vl "'ov4689 0-0036':0 -> 'stf_csiphy0':0 [0]" + case $sensor_type in + VIN) + echo "csiphy0 CSIRX0 vin disable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]" + media-ctl -d "$devname" -vl "'stf_csi0':1 -> 'stf_vin0_wr':0 [0]" + ;; + ISP0) + echo "csiphy0 CSIRX0 ISP0 disable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]" + media-ctl -d "$devname" -vl "'stf_csi0':1 -> 'stf_isp0':0 [0]" + media-ctl -d "$devname" -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]" + ;; + ISP0RAW) + echo "csiphy0 CSIRX0 ISP0RAW disable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]" + media-ctl -d "$devname" -vl "'stf_csi0':1 -> 'stf_isp0':0 [0]" + media-ctl -d "$devname" -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]" + ;; + ISP1) + echo "csiphy0 CSIRX0 ISP1 disable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]" + media-ctl -d "$devname" -vl "'stf_csi0':1 -> 'stf_isp1':0 [0]" + media-ctl -d "$devname" -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]" + ;; + ISP1RAW) + echo "csiphy0 CSIRX0 ISP1RAW disable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]" + media-ctl -d "$devname" -vl "'stf_csi0':1 -> 'stf_isp1':0 [0]" + media-ctl -d "$devname" -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]" + ;; + + *) + echo "$USAGE" + exit 1 + ;; + esac + ;; + *) + echo "$USAGE" + exit 1 + ;; + esac + ;; + csiphy1) + case $action in + start) + # media-ctl -d "$devname" -vl "'ov4689 2-0036':0 -> 'stf_csiphy1':0 [1]" + case $sensor_type in + VIN) + echo "csiphy1 CSIRX0 vin enable pipeline:" + ;; + ISP0) + echo "csiphy1 CSIRX1 ISP0 enable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [1]" + media-ctl -d "$devname" -vl "'stf_csi1':1 -> 'stf_isp0':0 [1]" + media-ctl -d "$devname" -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]" + ;; + ISP0RAW) + echo "csiphy1 CSIRX1 ISP0RAW enable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [1]" + media-ctl -d "$devname" -vl "'stf_csi1':1 -> 'stf_isp0':0 [1]" + media-ctl -d "$devname" -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]" + ;; + ISP1) + echo "csiphy1 CSIRX1 ISP1 enable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [1]" + media-ctl -d "$devname" -vl "'stf_csi1':1 -> 'stf_isp1':0 [1]" + media-ctl -d "$devname" -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]" + ;; + ISP1RAW) + echo "csiphy1 CSIRX1 ISP1RAW enable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [1]" + media-ctl -d "$devname" -vl "'stf_csi1':1 -> 'stf_isp1':0 [1]" + media-ctl -d "$devname" -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [1]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]" + ;; + + *) + echo "$USAGE" + exit 1 + ;; + esac + ;; + stop) + # media-ctl -d "$devname" -vl "'ov4689 0-0036':0 -> 'stf_csiphy0':0 [0]" + case $sensor_type in + VIN) + echo "csiphy1 CSIRX0 vin disable pipeline:" + ;; + ISP0) + echo "csiphy1 CSIRX1 ISP0 disable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [0]" + media-ctl -d "$devname" -vl "'stf_csi1':1 -> 'stf_isp0':0 [0]" + media-ctl -d "$devname" -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]" + ;; + ISP0RAW) + echo "csiphy1 CSIRX1 ISP0RAW disable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [0]" + media-ctl -d "$devname" -vl "'stf_csi1':1 -> 'stf_isp0':0 [0]" + media-ctl -d "$devname" -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]" + ;; + ISP1) + echo "csiphy1 CSIRX1 ISP1 disable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [0]" + media-ctl -d "$devname" -vl "'stf_csi1':1 -> 'stf_isp1':0 [0]" + media-ctl -d "$devname" -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]" + ;; + ISP1RAW) + echo "csiphy1 CSIRX1 ISP1RAW disable pipeline:" + media-ctl -d "$devname" -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [0]" + media-ctl -d "$devname" -vl "'stf_csi1':1 -> 'stf_isp1':0 [0]" + media-ctl -d "$devname" -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [0]" + # media-ctl -d "$devname" -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]" + ;; + *) + echo "$USAGE" + exit 1 + ;; + esac + ;; + *) + echo "$USAGE" + exit 1 + ;; + esac + ;; + *) + echo "$USAGE" + exit 1 + ;; +esac + +exit 0; diff --git a/package/starfive/v4l2_test/stf_drm.c b/package/starfive/v4l2_test/stf_drm.c new file mode 100644 index 00000000..789114b7 --- /dev/null +++ b/package/starfive/v4l2_test/stf_drm.c @@ -0,0 +1,490 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ +#include +#include +#include "stf_drm.h" +#include "stf_log.h" + +static int drm_open(const char *path, int need_dumb, int need_prime) +{ + int fd, flags; + uint64_t has_it; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + if ((fd = open(path, O_RDWR)) < 0) { + LOG(STF_LEVEL_ERR, "cannot open \"%s\"\n", path); + error("open"); + } + + /* set FD_CLOEXEC flag */ + if ((flags = fcntl(fd, F_GETFD)) < 0 + || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) < 0) + fatal("fcntl FD_CLOEXEC failed"); + + if (need_dumb) { + if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_it) < 0) + error("drmGetCap DRM_CAP_DUMB_BUFFER failed!"); + if (has_it == 0) + fatal("can't give us dumb buffers"); + } + + if (need_prime) { + /* check prime */ + if (drmGetCap(fd, DRM_CAP_PRIME, &has_it) < 0) + error("drmGetCap DRM_CAP_PRIME failed!"); + if (!(has_it & DRM_PRIME_CAP_EXPORT)) + fatal("can't export dmabuf"); + } + + LOG(STF_LEVEL_TRACE, "Exit\n"); + return fd; +} + +static struct drm_dev_t *drm_find_dev(int fd, uint32_t width, uint32_t height) +{ + int i, m; + struct drm_dev_t *dev = NULL, *dev_head = NULL; + drmModeRes *res; + drmModeConnector *conn; + drmModeEncoder *enc; + drmModeModeInfo *mode = NULL, *preferred = NULL; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + if ((res = drmModeGetResources(fd)) == NULL) { + fatal("drmModeGetResources() failed"); + } + + LOG(STF_LEVEL_DEBUG, "count_connectors=%d\n", res->count_connectors); + /* find all available connectors */ + for (i = 0; i < res->count_connectors; i++) { + conn = drmModeGetConnector(fd, res->connectors[i]); + if (conn != NULL && conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0) { + dev = (struct drm_dev_t *) malloc(sizeof(struct drm_dev_t)); + memset(dev, 0, sizeof(struct drm_dev_t)); + + /* find preferred mode */ + for (m = 0; m < conn->count_modes; m++) { + mode = &conn->modes[m]; + if (mode->hdisplay == width && mode->vdisplay == height) { + preferred = mode; + LOG(STF_LEVEL_INFO, "find the matched mode, modes index=%d, %dx%d\n", + m, width, height); + break; + } + if (mode->type & DRM_MODE_TYPE_PREFERRED) { + preferred = mode; + LOG(STF_LEVEL_INFO, "find perferred mode, modes index=%d\n", m); + } + LOG(STF_LEVEL_DEBUG, "mode: %dx%d %s\n", mode->hdisplay, mode->vdisplay, + mode->type & DRM_MODE_TYPE_PREFERRED ? "*" : ""); + } + + if (!preferred) + preferred = &conn->modes[0]; + + dev->conn_id = conn->connector_id; + // dev->next = NULL; + if (conn->count_encoders) { + if (conn->encoder_id) { + dev->enc_id = conn->encoder_id; + } else { + dev->enc_id = conn->encoders[0]; + } + } else { + fatal("count_encoders is 0"); + } + + memcpy(&dev->mode, preferred, sizeof(drmModeModeInfo)); + dev->width = preferred->hdisplay; + dev->height = preferred->vdisplay; + + /* FIXME: use default encoder/crtc pair */ + if ((enc = drmModeGetEncoder(fd, dev->enc_id)) == NULL) + fatal("drmModeGetEncoder() faild"); + if (enc->crtc_id) { + dev->crtc_id = enc->crtc_id; + } else { + dev->crtc_id = res->crtcs[0]; + } + drmModeFreeEncoder(enc); + + dev->saved_crtc = NULL; + + /* create dev list */ + dev->next = dev_head; + dev_head = dev; + } + drmModeFreeConnector(conn); + } + + drmModeFreeResources(res); + + LOG(STF_LEVEL_INFO, "selected connector(s)\n"); + for (dev = dev_head; dev != NULL; dev = dev->next) { + LOG(STF_LEVEL_INFO, "connector id:%d\n", dev->conn_id); + LOG(STF_LEVEL_INFO, "\tencoder id:%d crtc id:%d\n", dev->enc_id, dev->crtc_id); + LOG(STF_LEVEL_INFO, "\twidth:%d height:%d\n", dev->width, dev->height); + } + + LOG(STF_LEVEL_TRACE, "Exit\n"); + return dev_head; +} + +static void drm_setup_buffer(int fd, struct drm_dev_t *dev, + int width, int height, + struct drm_buffer_t *buffer, int map, int export) +{ + struct drm_mode_create_dumb create_req; + struct drm_mode_map_dumb map_req; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + buffer->dmabuf_fd = -1; + + memset(&create_req, 0, sizeof(struct drm_mode_create_dumb)); + create_req.width = width; + create_req.height = height; + create_req.bpp = 24; + if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_req) < 0) { + fatal("drmIoctl DRM_IOCTL_MODE_CREATE_DUMB failed"); + } + + buffer->pitch = create_req.pitch; + buffer->size = create_req.size; + /* GEM buffer handle */ + buffer->bo_handle = create_req.handle; + + if (export) { + int ret; + ret = drmPrimeHandleToFD(fd, buffer->bo_handle, + DRM_CLOEXEC | DRM_RDWR, &buffer->dmabuf_fd); + if (ret < 0) { + fatal("could not export the dump buffer"); + } + LOG(STF_LEVEL_INFO, "drm fd=%d, bo_handle=%d, dmabuf_fd=%d\n", + fd, buffer->bo_handle, buffer->dmabuf_fd); + } + + if (map) { + memset(&map_req, 0, sizeof(struct drm_mode_map_dumb)); + map_req.handle = buffer->bo_handle; + if (drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map_req)) { + fatal("drmIoctl DRM_IOCTL_MODE_MAP_DUMB failed"); + } + buffer->buf = (uint8_t *)mmap(0, buffer->size, + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, map_req.offset); + if (buffer->buf == MAP_FAILED) { + error("mmap"); + } + } + + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +static uint32_t drm_get_bpp_from_drm(uint32_t drmfmt) +{ + uint32_t bpp; + + switch (drmfmt) { + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_NV16: + bpp = 8; + break; + case DRM_FORMAT_P010: + bpp = 10; + break; + case DRM_FORMAT_UYVY: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_P016: + bpp = 16; + break; + case DRM_FORMAT_BGR888: + case DRM_FORMAT_RGB888: + bpp = 24; + break; + default: + bpp = 32; + break; + } + + return bpp; +} + +static uint32_t drm_get_height_from_drm (uint32_t drmfmt, uint32_t height) +{ + uint32_t ret; + + switch (drmfmt) { + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + case DRM_FORMAT_YUV422: + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + case DRM_FORMAT_P010: + case DRM_FORMAT_P016: + ret = height * 3 / 2; + break; + case DRM_FORMAT_NV16: + ret = height * 2; + break; + default: + ret = height; + break; + } + + return ret; +} + +static int drm_setup_buffer2(int fd, struct drm_dev_t *dev, + int width, int height, + struct drm_buffer_t *buffer, int map, int export) +{ + struct drm_mode_create_dumb create_req; + struct drm_mode_map_dumb map_req; + int ret = 0; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + buffer->dmabuf_fd = -1; + + memset(&create_req, 0, sizeof(struct drm_mode_create_dumb)); + // For NV12 or NV21, bpp is 8, height is height * 3 / 2 + create_req.width = width; + create_req.height = drm_get_height_from_drm(dev->drm_format, height); + create_req.bpp = drm_get_bpp_from_drm(dev->drm_format); + if (drmIoctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_req) < 0) { + fatal("drmIoctl DRM_IOCTL_MODE_CREATE_DUMB failed"); + } + buffer->pitch = create_req.pitch; + buffer->size = create_req.size; + buffer->bo_handle = create_req.handle; /* GEM buffer handle */ + + if (export) { +#if 0 + memset(&map_req, 0, sizeof(struct drm_mode_map_dumb)); + map_req.handle = buffer->bo_handle; + ret = drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map_req); + if (ret) { + fatal("drmIoctl DRM_IOCTL_MODE_MAP_DUMB failed"); + } + buffer->buf = (uint8_t *) mmap(0, buffer->size, + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, map_req.offset); + if (buffer->buf == MAP_FAILED) { + error("drm mmap"); + } + LOG(STF_LEVEL_INFO, "buffer->buf= %p\n", buffer->buf); +#endif + + ret = drmPrimeHandleToFD(fd, buffer->bo_handle, + DRM_CLOEXEC | DRM_RDWR, &buffer->dmabuf_fd); + if (ret < 0) { + fatal("could not export the dump buffer"); + } + LOG(STF_LEVEL_DEBUG, "drm fd=%d, bo_handle=%d, dmabuf_fd=%d\n", + fd, buffer->bo_handle, buffer->dmabuf_fd); + } + + if (map) { + memset(&map_req, 0, sizeof(struct drm_mode_map_dumb)); + map_req.handle = buffer->bo_handle; + + if (drmIoctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map_req)) { + fatal("drmIoctl DRM_IOCTL_MODE_MAP_DUMB failed"); + } + buffer->buf = (uint8_t *)mmap(0, buffer->size, + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, map_req.offset); + if (buffer->buf == MAP_FAILED) { + error("mmap"); + } + } + + uint32_t handles[4] = {0}, pitches[4] = {0}, offsets[4] = {0}; + handles[0] = buffer->bo_handle; + pitches[0] = buffer->pitch; + offsets[0] = 0; + handles[1] = buffer->bo_handle; + pitches[1] = buffer->pitch; + offsets[1] = buffer->pitch * height; + // planes[0] = virtual; + // planes[1] = virtual + offsets[1]; + + LOG(STF_LEVEL_INFO, "map=%d, export=%d. width=%d, height=%d, " + "pitch=%d, size=%d, bo_handle=%d, dmabuf_fd=%d\n", + map, export, width, height, buffer->pitch, buffer->size, + buffer->bo_handle, buffer->dmabuf_fd); + + //DRM_FORMAT_NV12 + ret = drmModeAddFB2(fd, dev->width, dev->height, + dev->drm_format, handles, pitches, offsets, &(buffer->fb_id), 0); + LOG(STF_LEVEL_TRACE, "Exit\n"); + return ret; + // return drmModeAddFB(fd, dev->width, dev->height, + // DEPTH, BPP, dev->bufs[i].pitch, + // dev->bufs[i].bo_handle, &dev->bufs[i].fb_id); +} + +static void drm_setup_dummy(int fd, struct drm_dev_t *dev, int map, int export) +{ + int i; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + for (i = 0; i < BUFCOUNT; i++) { + drm_setup_buffer(fd, dev, dev->width, dev->height, + &dev->bufs[i], map, export); + } + + /* Assume all buffers have the same pitch */ + dev->pitch = dev->bufs[0].pitch; + LOG(STF_LEVEL_INFO, "DRM: buffer pitch = %d bytes\n", dev->pitch); + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +static void drm_setup_fb(int fd, struct drm_dev_t *dev, int map, int export) +{ + int i; + + LOG(STF_LEVEL_TRACE, "Enter\n"); +#if 0 + for (i = 0; i < BUFCOUNT; i++) { + int ret; + + drm_setup_buffer(fd, dev, dev->width, dev->height, + &dev->bufs[i], map, export); + + ret = drmModeAddFB(fd, dev->width, dev->height, + DEPTH, BPP, dev->bufs[i].pitch, + dev->bufs[i].bo_handle, &dev->bufs[i].fb_id); + if (ret) + fatal("drmModeAddFB failed"); +LOG(STF_LEVEL_INFO, "width=%d,height=%d,pitch=%d,bo_handle=%d,fb_id=%d\n", + dev->width, dev->height,dev->bufs[i].pitch,dev->bufs[i].bo_handle, dev->bufs[i].fb_id); + } +#else + for (i = 0; i < BUFCOUNT; i++) { + int ret = -1; + ret = drm_setup_buffer2(fd, dev, dev->width, dev->height, + &dev->bufs[i], map, export); + if (ret) { + fatal("drmModeAddFB failed"); + } + } +#endif + + /* Assume all buffers have the same pitch */ + dev->pitch = dev->bufs[0].pitch; + LOG(STF_LEVEL_DEBUG, "DRM: buffer pitch %d bytes\n", dev->pitch); + + dev->saved_crtc = drmModeGetCrtc(fd, dev->crtc_id); /* must store crtc data */ + + /* First buffer to DRM */ + if (drmModeSetCrtc(fd, dev->crtc_id, dev->bufs[0].fb_id, 0, 0, + &dev->conn_id, 1, &dev->mode)) { + fatal("drmModeSetCrtc() failed"); + } + + /* First flip */ + drmModePageFlip(fd, dev->crtc_id, + dev->bufs[0].fb_id, DRM_MODE_PAGE_FLIP_EVENT, + dev); + + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +static void drm_destroy(int fd, struct drm_dev_t *dev_head) +{ + struct drm_dev_t *devp, *devp_tmp; + int i; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + for (devp = dev_head; devp != NULL;) { + if (devp->saved_crtc) { + drmModeSetCrtc(fd, devp->saved_crtc->crtc_id, devp->saved_crtc->buffer_id, + devp->saved_crtc->x, devp->saved_crtc->y, &devp->conn_id, 1, &devp->saved_crtc->mode); + drmModeFreeCrtc(devp->saved_crtc); + } + + for (i = 0; i < BUFCOUNT; i++) { + struct drm_mode_destroy_dumb dreq = { .handle = devp->bufs[i].bo_handle }; + + if (devp->bufs[i].buf) { + munmap(devp->bufs[i].buf, devp->bufs[i].size); + } + if (devp->bufs[i].dmabuf_fd >= 0) { + close(devp->bufs[i].dmabuf_fd); + } + drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &dreq); + drmModeRmFB(fd, devp->bufs[i].fb_id); + } + + devp_tmp = devp; + devp = devp->next; + free(devp_tmp); + } + + drmClose(fd); + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +void stf_drm_open(DRMParam_t *param, char *device_name, int iomthd) +{ + int drm_fd; + LOG(STF_LEVEL_TRACE, "Enter\n"); + + if (IO_METHOD_MMAP == iomthd) { + drm_fd = drm_open(device_name, 1, 0); + } else if (IO_METHOD_DMABUF == iomthd) { + drm_fd = drm_open(device_name, 1, 1); + } else { + LOG(STF_LEVEL_ERR, "drm: not support io_method %d\n", iomthd); + exit (EXIT_FAILURE); + } + + param->fd = drm_fd; + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +// try to use v4l2_fmt +void stf_drm_init(DRMParam_t *param, uint32_t width, uint32_t height, + uint32_t v4l2_fmt, int iomthd, int *dmabufs, int nsize) +{ + struct drm_dev_t *dev_head = NULL; + int i = 0; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + dev_head = drm_find_dev(param->fd, width, height); + if (dev_head == NULL) { + LOG(STF_LEVEL_ERR, "available drm_dev not found\n"); + exit (EXIT_FAILURE); + } + + dev_head->drm_format = v4l2fmt_to_drmfmt(v4l2_fmt); + + if (IO_METHOD_MMAP == iomthd) { + drm_setup_fb(param->fd, dev_head, 1, 0); + } else if (IO_METHOD_DMABUF == iomthd) { + drm_setup_fb(param->fd, dev_head, 0, 1); + assert(nsize == BUFCOUNT); + for (i = 0; i < nsize; i++) { + dmabufs[i] = dev_head->bufs[i].dmabuf_fd; + } + } else { + LOG(STF_LEVEL_ERR, "drm: not support io_method %d\n", iomthd); + exit (EXIT_FAILURE); + } + + param->dev_head = dev_head; + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +void stf_drm_close(DRMParam_t *param) +{ + drm_destroy(param->fd, param->dev_head); +} diff --git a/package/starfive/v4l2_test/stf_drm.h b/package/starfive/v4l2_test/stf_drm.h new file mode 100644 index 00000000..081d3f4e --- /dev/null +++ b/package/starfive/v4l2_test/stf_drm.h @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ +#ifndef __STF_DRM_H__ +#define __STF_DRM_H__ + +#include +#include +#include +#include "common.h" +#include "stf_log.h" + +struct drm_buffer_t { + uint32_t pitch, size; + + uint32_t fb_id; + int dmabuf_fd; // used for dmabuf + int bo_handle; + uint8_t *buf; +}; + +typedef struct drm_dev_t { + uint32_t conn_id, enc_id, crtc_id; + uint32_t width, height, pitch; + drmModeModeInfo mode; + drmModeCrtc *saved_crtc; + + // int v4l2_fd; + // int drm_fd; + uint32_t drm_format; + + struct drm_buffer_t bufs[BUFCOUNT]; + struct drm_dev_t *next; +} drm_dev_t; + +typedef struct DRMParam_t { + drm_dev_t* dev_head; + int fd; +} DRMParam_t; + + +inline static void fatal(char *str) +{ + LOG(STF_LEVEL_ERR, "%s\n", str); + exit(EXIT_FAILURE); +} + +inline static void error(char *str) +{ + perror(str); + exit(EXIT_FAILURE); +} + +extern void stf_drm_open(DRMParam_t *param, char *device_name, int iomthd); +extern void stf_drm_init(DRMParam_t *param, uint32_t width, uint32_t height, + uint32_t v4l2_fmt, int iomthd, int *dmabufs, int nsize); +extern void stf_drm_close(DRMParam_t *param); + +#endif // __STF_DRM_H__ diff --git a/package/starfive/v4l2_test/stf_framebuffer.c b/package/starfive/v4l2_test/stf_framebuffer.c new file mode 100644 index 00000000..735cb696 --- /dev/null +++ b/package/starfive/v4l2_test/stf_framebuffer.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ + +#include +#include +#include "common.h" +#include "stf_framebuffer.h" +#include "stf_log.h" + +#define FBIOPAN_GET_PP_MODE 0x4609 +#define FBIOPAN_SET_PP_MODE 0x460a + +void stf_fb_open(FBParam_t *param, char *device_name, char *stfbc_name) +{ + LOG(STF_LEVEL_TRACE, "Enter\n"); + //open framebuffer + param->fd = open(device_name, O_RDWR); + if (param->fd == -1) { + LOG(STF_LEVEL_ERR, "Error: cannot open framebuffer device.\n"); + exit(EXIT_FAILURE); + } + //open stfbc device for pp setting + param->stfbc_fd = open(stfbc_name, O_RDWR); + if (param->stfbc_fd == -1) { + LOG(STF_LEVEL_ERR, "Error: cannot open stfbcdev device.\n"); + exit(EXIT_FAILURE); + } + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +void stf_fb_close(FBParam_t *param) +{ + LOG(STF_LEVEL_TRACE, "Enter\n"); + if (param->fd > 0) { + close(param->fd); + param->fd = 0; + } + + if (param->stfbc_fd > 0) { + close(param->stfbc_fd); + param->stfbc_fd = 0; + } + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +void stf_fb_init(FBParam_t *param, uint32_t v4l2_fmt) +{ + int pixformat; + struct pp_mode pp_info[3]; + struct fb_var_screeninfo vinfo; + struct fb_fix_screeninfo finfo; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + // step 1: try to set the fb format got from cmd options + pixformat = v4l2fmt_to_fbfmt(v4l2_fmt); + if (-1 == ioctl(param->stfbc_fd, FBIOPAN_GET_PP_MODE, &pp_info[0])) { + LOG(STF_LEVEL_ERR, "Error reading variable information.\n"); + exit (EXIT_FAILURE); + } + LOG(STF_LEVEL_INFO, "Before set_pp_mode. get fb format:%d, will set fb format:%d\n", + pp_info[1].src.format, pixformat); + + pp_info[1].src.format = pixformat; + if (-1 == ioctl(param->stfbc_fd, FBIOPAN_SET_PP_MODE, &pp_info[0])) { + LOG(STF_LEVEL_ERR, "Error reading variable information.\n"); + exit (EXIT_FAILURE); + } + + if (-1 == ioctl(param->stfbc_fd, FBIOPAN_GET_PP_MODE, &pp_info[0])) { + LOG(STF_LEVEL_ERR, "Error reading variable information.\n"); + exit (EXIT_FAILURE); + } + LOG(STF_LEVEL_INFO, "After set_pp_mode. get fb format:%d\n", pp_info[1].src.format); + pixformat = pp_info[1].src.format; + param->pixformat = pixformat; + + // step 2: Get fixed screen information + if (-1 == ioctl(param->fd, FBIOGET_FSCREENINFO, &finfo)) { + LOG(STF_LEVEL_ERR, "Error reading fixed information.\n"); + exit (EXIT_FAILURE); + } + memcpy(&(param->finfo), &finfo, sizeof(finfo)); + + // step 3: Get variable screen information + if (-1 == ioctl(param->fd, FBIOGET_VSCREENINFO, &vinfo)) { + LOG(STF_LEVEL_ERR, "Error reading variable information.\n"); + exit (EXIT_FAILURE); + } + memcpy(&(param->vinfo), &vinfo, sizeof(vinfo)); + LOG(STF_LEVEL_INFO, "print screen information:\n"); + LOG(STF_LEVEL_INFO, " vinfo.xres = %d, vinfo.yres = %d, grayscale = %d\n", vinfo.xres, vinfo.yres, vinfo.grayscale); + LOG(STF_LEVEL_INFO, " vinfo.xoffset = %d, vinfo.yoffset = %d\n", vinfo.xoffset, vinfo.yoffset); + LOG(STF_LEVEL_INFO, " vinfo.bits_per_pixel = %d, finfo.line_length = %d\n", vinfo.bits_per_pixel, finfo.line_length); + // if (ioctl(param->fd, FBIOPUT_VSCREENINFO, &g_vinfo) < 0) { + // LOG(STF_LEVEL_ERR, "FBIOPUT_VSCREENINFO.\n"); + // exit (EXIT_FAILURE); + // } + + // step 4: mmap fb buf to user space and update the actually screen param + param->width = vinfo.xres; + param->height = vinfo.yres; + param->bpp = vinfo.bits_per_pixel; + param->screen_size = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; + // g_screensize = g_vinfo.xres * g_vinfo.yres * 32 / 8; + param->screen_buf = (uint8_t *)mmap(NULL, param->screen_size, + PROT_READ | PROT_WRITE, MAP_SHARED, param->fd, 0); + if (param->screen_buf == (void *)(-1)) { + LOG(STF_LEVEL_ERR, "Error: failed to map framebuffer device to memory.\n"); + exit (EXIT_FAILURE) ; + } + memset(param->screen_buf, 0x00, param->screen_size); + + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +void stf_fb_uninit(FBParam_t *param) +{ + LOG(STF_LEVEL_TRACE, "Enter\n"); + if (-1 == munmap((void *)param->screen_buf, param->screen_size)) { + LOG(STF_LEVEL_ERR, " Error: framebuffer device munmap() failed.\n"); + exit (EXIT_FAILURE) ; + } + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + + diff --git a/package/starfive/v4l2_test/stf_framebuffer.h b/package/starfive/v4l2_test/stf_framebuffer.h new file mode 100644 index 00000000..b0abd39a --- /dev/null +++ b/package/starfive/v4l2_test/stf_framebuffer.h @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ +#ifndef __STF_FRAMEBUFFER_H__ +#define __STF_FRAMEBUFFER_H__ +#include +#include +#include "common.h" + +struct pp_video_mode { + enum COLOR_FORMAT format; + unsigned int height; + unsigned int width; + unsigned int addr; +}; + +struct pp_mode { + char pp_id; + bool bus_out; /*out to ddr*/ + bool fifo_out; /*out to lcdc*/ + bool inited; + struct pp_video_mode src; + struct pp_video_mode dst; +}; + +typedef struct FBParam_t { + int fd; + int stfbc_fd; + struct fb_var_screeninfo vinfo; + struct fb_fix_screeninfo finfo; + uint8_t *screen_buf; + uint32_t screen_size; + + int pixformat; // default COLOR_YUV420_NV21 + uint32_t width; // default 1920 + uint32_t height; // default 1080 + uint32_t bpp; +} FBParam_t; + +extern void stf_fb_open(FBParam_t *param, char *device_name, char *stfbc_name); +extern void stf_fb_close(FBParam_t *param); +extern void stf_fb_init(FBParam_t *param, uint32_t v4l2_fmt); +extern void stf_fb_uninit(FBParam_t *param); + +#endif // __STF_FRAMEBUFFER_H__ diff --git a/package/starfive/v4l2_test/stf_log.c b/package/starfive/v4l2_test/stf_log.c new file mode 100644 index 00000000..2b01e61d --- /dev/null +++ b/package/starfive/v4l2_test/stf_log.c @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ +#include +#include +#include +#include +#include "stf_log.h" + +#define ANSI_COLOR_ERR "\x1b[31m" // RED +#define ANSI_COLOR_TRACE "\x1b[32m" // GREEN +#define ANSI_COLOR_WARN "\x1b[33m" // YELLOW +#define ANSI_COLOR_BLUE "\x1b[34m" // BLUE +#define ANSI_COLOR_INFO "" +// For future +#define ANSI_COLOR_MAGENTA "\x1b[35m" // MAGENTA +#define ANSI_COLOR_CYAN "\x1b[36m" // CYAN +#define ANSI_COLOR_RESET "\x1b[0m" // RESET + +#define MAX_PRINT_LENGTH 512 +#define STF_LOG_FILE_PATH "./STF_ErrorLog.txt" +#define STF_LOG_ENV_VARIABLE "V4L2_DEBUG" + +// static unsigned int log_decor = LOG_HAS_TIME | LOG_HAS_FILE | LOG_HAS_COLOR; +static unsigned int log_decor = LOG_HAS_TIME | LOG_HAS_COLOR; +static FILE *fpLog = NULL; +static int max_log_level = STF_LEVEL_ERR; + +int init_log() +{ + char *strDebug_level = NULL; + int level; + + if ((log_decor & LOG_HAS_FILE) && !fpLog) { + fpLog = fopen(STF_LOG_FILE_PATH, "w"); + } + + strDebug_level = getenv(STF_LOG_ENV_VARIABLE); + if (strDebug_level) { + level = atoi(strDebug_level); + if (level >=0) { + max_log_level = level; + } + } + + return 0; +} + +void deinit_log() +{ + if (fpLog) { + fclose(fpLog); + fpLog = NULL; + } +} + +void set_maxLogLevel(int level) +{ + max_log_level = level; +} + +int get_maxLogLevel() +{ + return max_log_level; +} + +void logmsg(int level, const char *format, ...) +{ + va_list ptr; + char logBuf[MAX_PRINT_LENGTH] = {0}; + char* prefix = ""; + char* postfix= ""; + + if (level > max_log_level) + return; + + if ((log_decor & LOG_HAS_COLOR)) { + postfix = ANSI_COLOR_RESET; + switch (level) { + case STF_LEVEL_ERR: prefix = ANSI_COLOR_ERR "[ERROR]"; break; + case STF_LEVEL_WARN: prefix = ANSI_COLOR_WARN"[WARN ]"; break; + case STF_LEVEL_INFO: prefix = ANSI_COLOR_INFO"[INFO ]"; break; + case STF_LEVEL_DEBUG: prefix = ANSI_COLOR_INFO"[DEBUG]"; break; + case STF_LEVEL_LOG: prefix = ANSI_COLOR_INFO"[LOG ]"; break; + case STF_LEVEL_TRACE: prefix = ANSI_COLOR_TRACE"[TRACE]"; break; + default: prefix = ""; break; + } + } + + va_start(ptr, format); + vsnprintf(logBuf, MAX_PRINT_LENGTH, format, ptr); + va_end(ptr); + + fputs(prefix, stderr); + fputs(logBuf, stderr); + fputs(postfix, stderr); + + if ((log_decor & LOG_HAS_FILE) && fpLog) { + fwrite(logBuf, strlen(logBuf), 1,fpLog); + fflush(fpLog); + } +} + diff --git a/package/starfive/v4l2_test/stf_log.h b/package/starfive/v4l2_test/stf_log.h new file mode 100644 index 00000000..4c5822fc --- /dev/null +++ b/package/starfive/v4l2_test/stf_log.h @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ +#ifndef __STF_LOG_H__ +#define __STF_LOG_H__ + +// Log Debug +typedef enum { + STF_LEVEL_NONE = 0, + STF_LEVEL_ERR, + STF_LEVEL_WARN, + STF_LEVEL_INFO, + STF_LEVEL_DEBUG, + STF_LEVEL_LOG, + STF_LEVEL_TRACE, + STF_LEVEL_ALL +} StfDebugLevelType; + +enum { + LOG_HAS_DAY_NAME = 1, /**< Include day name [default: no] */ + LOG_HAS_YEAR = 2, /**< Include year digit [no] */ + LOG_HAS_MONTH = 4, /**< Include month [no] */ + LOG_HAS_DAY_OF_MON = 8, /**< Include day of month [no] */ + LOG_HAS_TIME = 16, /**< Include time [yes] */ + LOG_HAS_MICRO_SEC = 32, /**< Include microseconds [yes] */ + LOG_HAS_FILE = 64, /**< Include sender in the log [yes] */ + LOG_HAS_NEWLINE = 128, /**< Terminate each call with newline [yes] */ + LOG_HAS_CR = 256, /**< Include carriage return [no] */ + LOG_HAS_SPACE = 512, /**< Include two spaces before log [yes] */ + LOG_HAS_COLOR = 1024, /**< Colorize logs [yes on win32] */ + LOG_HAS_LEVEL_TEXT = 2048 /**< Include level text string [no] */ +}; +enum { + TERM_COLOR_R = 2, /**< Red */ + TERM_COLOR_G = 4, /**< Green */ + TERM_COLOR_B = 1, /**< Blue. */ + TERM_COLOR_BRIGHT = 8 /**< Bright mask. */ +}; + +int init_log(void); +void deinit_log(void); +void set_maxLogLevel(int level); +int get_maxLogLevel(void); +void logmsg(int level, const char *format, ...); + +#define ENABLE_DEBUG +#ifdef ENABLE_DEBUG +#define LOG(level, fmt, ...) logmsg(level, "[%s,%d]: " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__); +#define FuncIn() logmsg(STF_LEVEL_DEBUG, "[%s,%d]: FUNC IN\n", __FUNCTION__, __LINE__); +#define FuncOut() logmsg(STF_LEVEL_DEBUG, "[%s,%d]: FUNC OUT\n", __FUNCTION__, __LINE__); +#else +#define LOG(level, fmt, ...) +#define FuncIn() +#define FuncOut() +#endif + +#endif // __STF_LOG_H__ diff --git a/package/starfive/v4l2_test/stf_v4l2.c b/package/starfive/v4l2_test/stf_v4l2.c new file mode 100644 index 00000000..674c72d1 --- /dev/null +++ b/package/starfive/v4l2_test/stf_v4l2.c @@ -0,0 +1,698 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ +#include +#include +#include +#include "common.h" +#include "stf_v4l2.h" +#include "stf_log.h" + +#define FILENAME_MAX_LEN 30 +struct stfisp_fw_info { + char filename[FILENAME_MAX_LEN]; +}; + +struct v4l2_subdev_frame_size_enum { + __u32 index; + __u32 pad; + __u32 code; + __u32 min_width; + __u32 max_width; + __u32 min_height; + __u32 max_height; + __u32 which; + __u32 reserved[8]; +}; + +#define VIDIOC_STFISP_LOAD_FW \ + _IOW('V', BASE_VIDIOC_PRIVATE + 1, struct stfisp_fw_info) + +#define VIDIOC_SUBDEV_ENUM_FRAME_SIZE \ + _IOWR('V', 74, struct v4l2_subdev_frame_size_enum) +#define MEDIA_BUS_FMT_SRGGB10_1X10 0x300f + +/** + Do ioctl and retry if error was EINTR ("A signal was caught during the ioctl() operation."). Parameters are the same as on ioctl. + \param fd file descriptor + \param request request + \param argp argument + \returns result from ioctl +*/ +int xioctl(int fd, int request, void* argp) +{ + int r; + + // TODO: the orign is v4l2_ioctl() + do r = ioctl(fd, request, argp); + while (-1 == r && EINTR == errno); + + return r; +} + +void sensor_image_size_info(V4l2Param_t *param) +{ + int fd = 0; + uint32_t i = 0; + struct v4l2_subdev_frame_size_enum frame_size; + LOG(STF_LEVEL_DEBUG, "go in sensor_image_size_info....\n"); + + fd = open(param->device_name, O_RDWR /* required */ | O_NONBLOCK, 0); + if (-1 == fd) { + LOG(STF_LEVEL_ERR, "Cannot open '%s': %d, %s\n", param->device_name, errno, strerror(errno)); + close(fd); + exit(EXIT_FAILURE); + } + + for (i = 0; i < 4; i++) { + frame_size.index = i; + frame_size.code = MEDIA_BUS_FMT_SRGGB10_1X10; + if (-1 == ioctl(fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE, &frame_size)) { + close(fd); + errno_exit("VIDIOC_SIZE_INFO"); + } + LOG(STF_LEVEL_DEBUG, "image_size: width[%d] = %d, height[%d] = %d \n", + i, frame_size.min_width, i, frame_size.min_height); + } + close(fd); +} + +void loadfw_start(char *filename, V4l2Param_t *param) +{ + struct stfisp_fw_info fw_info = {0}; + int fd = 0; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + fd = open(param->device_name, O_RDWR /* required */ | O_NONBLOCK, 0); + if (-1 == fd) { + LOG(STF_LEVEL_ERR, "Cannot open '%s': %d, %s\n", param->device_name, errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (filename && (strlen(filename) < FILENAME_MAX_LEN)) { + memcpy(fw_info.filename, filename, strlen(filename) + 1); + } + + LOG(STF_LEVEL_INFO, "VIDIOC_STFISP_LOAD_FW = 0x%lx, filename = %s, size = %lu, device=%s\n", + VIDIOC_STFISP_LOAD_FW, fw_info.filename, sizeof(struct stfisp_fw_info), param->device_name); + if (-1 == ioctl(fd, VIDIOC_STFISP_LOAD_FW, &fw_info)) { + if (EINVAL == errno) { + close(fd); + LOG(STF_LEVEL_ERR, "%s is no V4L2 device\n", param->device_name); + exit(EXIT_FAILURE); + } else { + close(fd); + errno_exit("VIDIOC_STFISP_LOAD_FW"); + } + } + + close(fd); + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +static void convert_v4l2_mem_type(int iomthd, enum v4l2_memory *mem_type) +{ + if (iomthd < IO_METHOD_MMAP || iomthd > IO_METHOD_READ) { + LOG(STF_LEVEL_ERR, "iomthd %d out of range\n", iomthd); + exit(EXIT_FAILURE); + } + + switch (iomthd) { + case IO_METHOD_MMAP: + *mem_type = V4L2_MEMORY_MMAP; + break; + case IO_METHOD_USERPTR: + *mem_type = V4L2_MEMORY_USERPTR; + break; + case IO_METHOD_DMABUF: + *mem_type = V4L2_MEMORY_DMABUF; + break; + case IO_METHOD_READ: + *mem_type = 0; // not use memory machanism + break; + default: + *mem_type = 0; // not use memory machanism + break; + } +} + +void stf_v4l2_open(V4l2Param_t *param, char *device_name) +{ + struct stat st; + //struct v4l2_capability cap; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + // stat file + if (-1 == stat(device_name, &st)) { + LOG(STF_LEVEL_ERR, "Cannot identify '%s': %d, %s\n", device_name, errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + // check if is device + if (!S_ISCHR(st.st_mode)) { + LOG(STF_LEVEL_ERR, "%s is no device\n", device_name); + exit(EXIT_FAILURE); + } + + // open device + param->fd = v4l2_open(device_name, O_RDWR /* required */ | O_NONBLOCK, 0); + // param->fd = v4l2_open(device_name, O_RDWR, 0); + if (-1 == param->fd) { + LOG(STF_LEVEL_ERR, "Cannot open '%s': %d, %s\n", device_name, errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +void stf_v4l2_close(V4l2Param_t *param) +{ + LOG(STF_LEVEL_TRACE, "Enter\n"); + if (-1 == v4l2_close(param->fd)) { + errno_exit("close"); + } + param->fd = -1; + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +void stf_v4l2_init(V4l2Param_t *param) +{ + struct v4l2_capability cap; + struct v4l2_cropcap cropcap; + struct v4l2_crop crop; + struct v4l2_format fmt; + struct v4l2_streamparm frameint; + //struct v4l2_streamparm frameget; + unsigned int min; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + // query capability + if (-1 == xioctl(param->fd, VIDIOC_QUERYCAP, &cap)) { + if (EINVAL == errno) { + LOG(STF_LEVEL_ERR, "%s is no V4L2 device\n", param->device_name); + exit(EXIT_FAILURE); + } else { + errno_exit("VIDIOC_QUERYCAP"); + } + } + if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { + LOG(STF_LEVEL_ERR, "%s is no video capture device\n", param->device_name); + exit(EXIT_FAILURE); + } + + switch (param->io_mthd) { + case IO_METHOD_READ: + if (!(cap.capabilities & V4L2_CAP_READWRITE)) { + LOG(STF_LEVEL_ERR, "%s does not support read i/o\n", param->device_name); + exit(EXIT_FAILURE); + } + break; + case IO_METHOD_MMAP: + case IO_METHOD_USERPTR: + case IO_METHOD_DMABUF: + if (!(cap.capabilities & V4L2_CAP_STREAMING)) { + LOG(STF_LEVEL_ERR, "%s does not support streaming i/o\n", param->device_name); + exit(EXIT_FAILURE); + } + break; + default: + LOG(STF_LEVEL_ERR, "%s does not specify streaming i/o\n", param->device_name); + exit(EXIT_FAILURE); + break; + } + + /* Select video input, video standard and tune here. */ + CLEAR(cropcap); + cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (0 == xioctl(param->fd, VIDIOC_CROPCAP, &cropcap)) { + crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + crop.c = cropcap.defrect; /* reset to default */ + if (-1 == xioctl(param->fd, VIDIOC_S_CROP, &crop)) { + switch (errno) { + case EINVAL: + /* Cropping not supported. */ + break; + default: + /* Errors ignored. */ + break; + } + } + } else { + /* Errors ignored. */ + } + + /* If the user has set the fps to -1, don't try to set the frame interval */ + if (param->fps != -1) { + CLEAR(frameint); + /* Attempt to set the frame interval. */ + frameint.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + frameint.parm.capture.timeperframe.numerator = 1; + frameint.parm.capture.timeperframe.denominator = param->fps; + if (-1 == xioctl(param->fd, VIDIOC_S_PARM, &frameint)) { + LOG(STF_LEVEL_WARN, "Unable to set frame interval.\n"); + } + LOG(STF_LEVEL_INFO, "set frame interval = %d.\n", frameint.parm.capture.timeperframe.denominator); + } + + // set v4l2_format + CLEAR(fmt); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.width = param->width; + fmt.fmt.pix.height = param->height; + fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; + fmt.fmt.pix.pixelformat = param->format; + if (-1 == xioctl(param->fd, VIDIOC_S_FMT, &fmt)) { + errno_exit("VIDIOC_S_FMT"); + } + + if (param->crop_flag) { + struct v4l2_selection sel_crop = { + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_SEL_TGT_CROP, + 0, + {param->crop_info.left, param->crop_info.top, + param->crop_info.width, param->crop_info.height} // TODO: opt here + }; + struct v4l2_selection get_crop = { + V4L2_BUF_TYPE_VIDEO_CAPTURE, + V4L2_SEL_TGT_CROP, + }; + LOG(STF_LEVEL_DEBUG, "sel_crop.left = %d, %d, %d, %d\n", + sel_crop.r.left, sel_crop.r.top, sel_crop.r.width, sel_crop.r.height); + + if (-1 == xioctl(param->fd, VIDIOC_S_SELECTION, &sel_crop)) { + LOG(STF_LEVEL_ERR, "S_SELECTION Failed.\n"); + } + LOG(STF_LEVEL_DEBUG, "sel_crop.left = %d, %d, %d, %d\n", + sel_crop.r.left, sel_crop.r.top, sel_crop.r.width, sel_crop.r.height); + + if (-1 == xioctl(param->fd, VIDIOC_G_SELECTION, &get_crop)) { + LOG(STF_LEVEL_ERR, "G_SELECTION Failed.\n"); + } + LOG(STF_LEVEL_DEBUG, "get_crop.left = %d, %d, %d, %d\n", + get_crop.r.left, get_crop.r.top, get_crop.r.width, get_crop.r.height); + + if (memcmp(&sel_crop, &get_crop, sizeof(sel_crop))) { + LOG(STF_LEVEL_WARN, "set/get selection diff.\n"); + } + } + + // get v4l2_format + memset(&fmt, 0, sizeof(struct v4l2_format)); + fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fmt.fmt.pix.field = V4L2_FIELD_ANY; + if (-1 == ioctl(param->fd, VIDIOC_G_FMT, &fmt)) { + errno_exit("VIDIOC_G_FMT"); + } + LOG(STF_LEVEL_INFO, "VIDIOC_G_FMT: type=%d, Fourcc format=%c%c%c%c\n", + fmt.type, fmt.fmt.pix.pixelformat & 0xff, + (fmt.fmt.pix.pixelformat >> 8) &0xff, + (fmt.fmt.pix.pixelformat >> 16) &0xff, + (fmt.fmt.pix.pixelformat >> 24) &0xff); + LOG(STF_LEVEL_INFO, " \t width=%d, height=%d, field=%d, bytesperline=%d, sizeimage=%d\n", + fmt.fmt.pix.width, fmt.fmt.pix.height, fmt.fmt.pix.field, + fmt.fmt.pix.bytesperline, fmt.fmt.pix.sizeimage); + + //if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_YUV420) { + //if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB565) { + if (fmt.fmt.pix.pixelformat != param->format) { + LOG(STF_LEVEL_ERR, "v4l2 didn't accept format %d. Can't proceed.\n", param->format); + exit(EXIT_FAILURE); + } + + /* Note VIDIOC_S_FMT may change width and height. */ + if (param->width != fmt.fmt.pix.width) { + param->width = fmt.fmt.pix.width; + LOG(STF_LEVEL_WARN, "Correct image width set to %i by device %s.\n", param->width, param->device_name); + } + + if (param->height != fmt.fmt.pix.height) { + param->height = fmt.fmt.pix.height; + LOG(STF_LEVEL_WARN, "Correct image height set to %i by device %s.\n", param->height, param->device_name); + } + + // TODO: who and why add the below here? Change bytesperline and sizeimage + /* Buggy driver paranoia. */ + min = fmt.fmt.pix.width * 2; + if (fmt.fmt.pix.bytesperline < min) { + fmt.fmt.pix.bytesperline = min; + } + min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; + if (fmt.fmt.pix.sizeimage < min) { + fmt.fmt.pix.sizeimage = min; + } + // param->image_size = fmt.fmt.pix.sizeimage; // wrong here + LOG(STF_LEVEL_LOG, "fmt.fmt.pix.sizeimage=%d, fmt.fmt.pix.bytesperline=%d\n", + fmt.fmt.pix.sizeimage, fmt.fmt.pix.bytesperline); + + // convert mem type + convert_v4l2_mem_type(param->io_mthd, ¶m->mem_type); + + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +void stf_v4l2_uninit(V4l2Param_t *param) +{ + uint32_t i; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + switch (param->io_mthd) { + case IO_METHOD_READ: + free(param->pBuffers[0].start); + break; + + case IO_METHOD_MMAP: + for (i = 0; i < param->n_buffers; ++i) { + if (-1 == v4l2_munmap(param->pBuffers[i].start, + param->pBuffers[i].length)) { + errno_exit("munmap"); + } + } + break; + + case IO_METHOD_USERPTR: + for (i = 0; i < param->n_buffers; ++i) { + free(param->pBuffers[i].start); + } + break; + + case IO_METHOD_DMABUF: + break; + + default: + break; + } + free(param->pBuffers); + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +static void stf_v4l2_readInit(V4l2Param_t *param) +{ + LOG(STF_LEVEL_TRACE, "Enter\n"); + param->n_buffers = 1; + param->pBuffers = calloc(param->n_buffers, sizeof(*param->pBuffers)); + if (!param->pBuffers) { + LOG(STF_LEVEL_ERR, "Out of memory\n"); + exit(EXIT_FAILURE); + } + + param->pBuffers[0].length = param->image_size; + param->pBuffers[0].start = malloc(param->image_size); + if (!param->pBuffers[0].start) { + LOG(STF_LEVEL_ERR, "Out of memory\n"); + exit(EXIT_FAILURE); + } + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +static void stf_v4l2_mmapInit(V4l2Param_t *param) +{ + int i = 0; + struct v4l2_requestbuffers req; + CLEAR(req); + + LOG(STF_LEVEL_TRACE, "Enter\n"); + req.count = BUFCOUNT; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_MMAP; + if (-1 == xioctl(param->fd, VIDIOC_REQBUFS, &req)) { + if (EINVAL == errno) { + LOG(STF_LEVEL_ERR, "%s does not support memory mapping\n", param->device_name); + exit(EXIT_FAILURE); + } else { + errno_exit("VIDIOC_REQBUFS"); + } + } + if (req.count < 2) { + LOG(STF_LEVEL_ERR, "Insufficient buffer memory on %s\n", param->device_name); + exit(EXIT_FAILURE); + } + + param->n_buffers = req.count; + param->pBuffers = calloc(param->n_buffers, sizeof(*param->pBuffers)); + if (!param->pBuffers) { + LOG(STF_LEVEL_ERR, "Out of memory\n"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < param->n_buffers; ++i) { + struct v4l2_buffer buf; + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + buf.index = i; + if (-1 == xioctl(param->fd, VIDIOC_QUERYBUF, &buf)) + errno_exit("VIDIOC_QUERYBUF"); + + param->pBuffers[i].length = buf.length; + param->pBuffers[i].start = v4l2_mmap(NULL, /* start anywhere */ + buf.length, PROT_READ | PROT_WRITE, /* required */ + MAP_SHARED, /* recommended */ + param->fd, buf.m.offset); + if (MAP_FAILED == param->pBuffers[i].start) { + errno_exit("mmap"); + } + param->image_size = buf.length; // NOTE: updated value + } + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +static void stf_v4l2_dmabufInit(V4l2Param_t *param, int *dmabufs, int count) +{ + int i = 0; + struct v4l2_requestbuffers req; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + CLEAR(req); + req.count = BUFCOUNT; // TODO: modify later + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_DMABUF; + + if (-1 == xioctl(param->fd, VIDIOC_REQBUFS, &req)) { + if (EINVAL == errno) { + fprintf(stderr, "does not support dmabuf\n"); + exit(EXIT_FAILURE); + } else { + errno_print("VIDIOC_REQBUFS"); + } + } + if (req.count < 2) { + fprintf(stderr, "Insufficient buffer memory\n"); + exit(EXIT_FAILURE); + } + + param->n_buffers = req.count; + param->pBuffers = calloc(param->n_buffers, sizeof(*param->pBuffers)); + if (!param->pBuffers) { + LOG(STF_LEVEL_ERR, "Out of memory\n"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < req.count; ++i) { + struct v4l2_buffer buf; + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_DMABUF; + buf.index = i; + if (-1 == xioctl(param->fd, VIDIOC_QUERYBUF, &buf)) { + errno_print("VIDIOC_QUERYBUF"); + } + param->pBuffers[i].index = buf.index; + param->pBuffers[i].dmabuf_fd = dmabufs[i]; +#if 0 + param->pBuffers[i].length = buf.length; + param->pBuffers[i].start = mmap(NULL /* start anywhere */, + buf.length, + PROT_READ | PROT_WRITE /* required */, + MAP_SHARED /* recommended */, + dmabufs[i], 0); + + if (MAP_FAILED == param->pBuffers[i].start) + errno_print("mmap"); +#endif + } + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +static void stf_v4l2_userptrInit(V4l2Param_t *param) +{ + struct v4l2_requestbuffers req; + unsigned int page_size; + unsigned int buffer_size = param->image_size; + int i = 0; + + page_size = getpagesize(); + buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1); + + CLEAR(req); + req.count = BUFCOUNT; + req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + req.memory = V4L2_MEMORY_USERPTR; + if (-1 == xioctl(param->fd, VIDIOC_REQBUFS, &req)) { + if (EINVAL == errno) { + LOG(STF_LEVEL_ERR, "%s does not support user pointer i/o\n", param->device_name); + exit(EXIT_FAILURE); + } else { + errno_exit("VIDIOC_REQBUFS"); + } + } + + param->n_buffers = 4; + param->pBuffers = calloc(param->n_buffers, sizeof(*param->pBuffers)); + if (!param->pBuffers) { + LOG(STF_LEVEL_ERR, "Out of memory\n"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < param->n_buffers; ++i) { + param->pBuffers[i].length = buffer_size; + param->pBuffers[i].start = memalign(/* boundary */ page_size, buffer_size); + if (!param->pBuffers[i].start) { + LOG(STF_LEVEL_ERR, "Out of memory\n"); + exit(EXIT_FAILURE); + } + } + param->image_size = buffer_size; +} + +void sft_v4l2_prepare_capturing(V4l2Param_t *param, int *dmabufs, int count) +{ + LOG(STF_LEVEL_TRACE, "Enter\n"); + switch (param->io_mthd) { + case IO_METHOD_READ: + stf_v4l2_readInit(param); + break; + + case IO_METHOD_MMAP: + stf_v4l2_mmapInit(param); + break; + + case IO_METHOD_USERPTR: + stf_v4l2_userptrInit(param); + break; + + case IO_METHOD_DMABUF: + stf_v4l2_dmabufInit(param, dmabufs, count); + break; + + default: + LOG(STF_LEVEL_ERR, "%s does not specify streaming i/o\n", param->device_name); + exit(EXIT_FAILURE); + break; + } + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +void sft_v4l2_start_capturing(V4l2Param_t *param) +{ + unsigned int i; + enum v4l2_buf_type type; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + switch (param->io_mthd) { + case IO_METHOD_READ: + /* Nothing to do. */ + break; + + case IO_METHOD_MMAP: + case IO_METHOD_USERPTR: + case IO_METHOD_DMABUF: + for (i = 0; i < param->n_buffers; ++i) { + stf_v4l2_queue_buffer(param, i); + } + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl(param->fd, VIDIOC_STREAMON, &type)) { + errno_exit("VIDIOC_STREAMON"); + } + break; + + default: + break; + } + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +void stf_v4l2_stop_capturing(V4l2Param_t *param) +{ + enum v4l2_buf_type type; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + switch (param->io_mthd) { + case IO_METHOD_READ: + /* Nothing to do. */ + break; + case IO_METHOD_MMAP: + case IO_METHOD_USERPTR: + case IO_METHOD_DMABUF: + type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if (-1 == xioctl(param->fd, VIDIOC_STREAMOFF, &type)) + errno_exit("VIDIOC_STREAMOFF"); + break; + default: + break; + } + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +// support V4L2_MEMORY_MMAP / V4L2_MEMORY_USERPTR / V4L2_MEMORY_DMABUF +// NOTE: for V4L2_MEMORY_USERPTR, index is pBuffers index +void stf_v4l2_queue_buffer(V4l2Param_t *param, int index) +{ + struct v4l2_buffer buf; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + assert(index < param->n_buffers); + CLEAR(buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = param->mem_type; + buf.index = index; // NOTE: for V4L2_MEMORY_USERPTR not used here? + + if (param->mem_type == V4L2_MEMORY_DMABUF) { + //buf.m.fd = param->dmabuf_fd; + buf.m.fd = param->pBuffers[index].dmabuf_fd; + } else if (param->mem_type == V4L2_MEMORY_USERPTR) { + buf.m.userptr = (unsigned long)param->pBuffers[index].start; + buf.length = param->pBuffers[index].length; + } + if (-1 == xioctl(param->fd, VIDIOC_QBUF, &buf)) { + errno_print("VIDIOC_QBUF"); + } + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +// support V4L2_MEMORY_MMAP / V4L2_MEMORY_USERPTR / V4L2_MEMORY_DMABUF +int stf_v4l2_dequeue_buffer(V4l2Param_t *param, struct v4l2_buffer *buf) +{ + int index = 0; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + PCLEAR(buf); + buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf->memory = param->mem_type; + if (-1 == xioctl(param->fd, VIDIOC_DQBUF, buf)) { + switch (errno) { + case EAGAIN: + return 0; + case EIO: + /* Could ignore EIO, see spec. */ + /* fall through */ + default: + errno_print("VIDIOC_DQBUF"); + } + } + + index = buf->index; + if (param->mem_type == V4L2_MEMORY_USERPTR) { + for (index = 0; index < param->n_buffers; ++index) { + if (buf->m.userptr == (unsigned long)param->pBuffers[index].start + && buf->length == param->pBuffers[index].length) { + break; + } + } + } + + assert(index < param->n_buffers); + LOG(STF_LEVEL_TRACE, "Exit\n"); + return 1; +} diff --git a/package/starfive/v4l2_test/stf_v4l2.h b/package/starfive/v4l2_test/stf_v4l2.h new file mode 100644 index 00000000..f49f9fc7 --- /dev/null +++ b/package/starfive/v4l2_test/stf_v4l2.h @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ +#ifndef __STF_V4L2_H__ +#define __STF_V4L2_H__ + +#include "common.h" + +// reference to enum v4l2_memory + +typedef struct V4l2Param_t { + char *device_name;// = "/dev/video0"; + int fd; + IOMethod io_mthd; // IO_METHOD_MMAP + enum v4l2_memory mem_type; + + // int dmabuf_fd; // for IO_METHOD_DMABUF + + struct buffer *pBuffers; + uint32_t n_buffers; + + uint32_t image_size; + uint32_t format; // = V4L2_PIX_FMT_RGB565 + + uint32_t width; // = 1920; + uint32_t height; // = 1080; + uint32_t fps; // = 30; + + int crop_flag; + struct v4l2_rect crop_info; + +} V4l2Param_t; + +extern int xioctl(int fd, int request, void* argp); + +extern void sensor_image_size_info(V4l2Param_t *param); +extern void loadfw_start(char *filename, V4l2Param_t *param); + +extern void stf_v4l2_open(V4l2Param_t *param, char *device_name); +extern void stf_v4l2_close(V4l2Param_t *param); +extern void stf_v4l2_init(V4l2Param_t *param); +extern void stf_v4l2_uninit(V4l2Param_t *param); +extern void sft_v4l2_prepare_capturing(V4l2Param_t *param, int *dmabufs, int count); +extern void sft_v4l2_start_capturing(V4l2Param_t *param); +extern void stf_v4l2_stop_capturing(V4l2Param_t *param); + +extern void stf_v4l2_queue_buffer(V4l2Param_t *param, int index); +extern int stf_v4l2_dequeue_buffer(V4l2Param_t *param, struct v4l2_buffer *buf); + +#endif // __STF_V4L2_H__ diff --git a/package/v4l2_test/string.c b/package/starfive/v4l2_test/string.c old mode 100755 new mode 100644 similarity index 100% rename from package/v4l2_test/string.c rename to package/starfive/v4l2_test/string.c diff --git a/package/starfive/v4l2_test/v4l2_test.c b/package/starfive/v4l2_test/v4l2_test.c new file mode 100644 index 00000000..38b37d58 --- /dev/null +++ b/package/starfive/v4l2_test/v4l2_test.c @@ -0,0 +1,919 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2021 StarFive Technology Co., Ltd. + */ + +#include +#include +#include +#include +#include +#include +#include "common.h" +#include "yuv.h" +#include "convert.h" +#include "stf_v4l2.h" +#include "stf_framebuffer.h" +#include "stf_drm.h" +#include "stf_log.h" + +#define FB_DEVICE_NAME "/dev/fb0" +#define STFBC_DEVICE_NAME "/dev/stfbcdev" +#define DRM_DEVICE_NAME "/dev/dri/card0" +#define V4L2_DFT_DEVICE_NAME "/dev/video0" + +typedef struct enum_value_t { + int value; + const char *name; +} enum_value_t; + +static const enum_value_t g_disp_values[] = { + { STF_DISP_NONE, "NONE"}, + { STF_DISP_FB, "FB"}, + { STF_DISP_DRM, "DRM"} +}; + +static const enum_value_t g_iomthd_values[] = { + { IO_METHOD_MMAP, "MMAP"}, + { IO_METHOD_USERPTR, "USERPTR"}, + { IO_METHOD_DMABUF, "DMABUF"}, + { IO_METHOD_READ, "READ"} +}; + +typedef struct { + V4l2Param_t v4l2_param; + FBParam_t fb_param; + DRMParam_t drm_param; + + enum STF_DISP_TYPE disp_type; + enum IOMethod io_mthd; + int continuous; + + uint8_t jpegQuality; + char* jpegFilename; + FILE *rec_fp; + + int dmabufs[BUFCOUNT]; // for dmabuf use, mmap not use it +} ConfigParam_t; +ConfigParam_t *gp_cfg_param = NULL; + +static int g_drm_buf_next_idx = -1; +static int g_drm_buf_curr_idx = 0; + +static void alloc_default_config(ConfigParam_t **pp_data) +{ + ConfigParam_t *cfg_param = NULL; + cfg_param = malloc(sizeof(*cfg_param)); + if (!cfg_param) { + errno_exit("malloc"); + } + memset(cfg_param, 0, sizeof(*cfg_param)); + + cfg_param->disp_type = STF_DISP_NONE; + cfg_param->continuous = 0; + cfg_param->jpegQuality = 70; + cfg_param->io_mthd = IO_METHOD_MMAP; + + cfg_param->v4l2_param.device_name = V4L2_DFT_DEVICE_NAME; + cfg_param->v4l2_param.fd = -1; + cfg_param->v4l2_param.io_mthd = cfg_param->io_mthd; + cfg_param->v4l2_param.width = 1920; + cfg_param->v4l2_param.height = 1080; + cfg_param->v4l2_param.image_size = cfg_param->v4l2_param.width * + cfg_param->v4l2_param.height * 3 / 2; + cfg_param->v4l2_param.format = V4L2_PIX_FMT_NV12; // V4L2_PIX_FMT_RGB565 + cfg_param->v4l2_param.fps = 30; + + // the fb param will be updated after fb init + cfg_param->fb_param.fd = -1; + cfg_param->fb_param.pixformat = COLOR_YUV420_NV21; // COLOR_RGB565 + cfg_param->fb_param.width = 1920; + cfg_param->fb_param.height = 1080; + cfg_param->fb_param.bpp = 16; + cfg_param->fb_param.screen_size = cfg_param->fb_param.width * + cfg_param->fb_param.height * cfg_param->fb_param.bpp / 8; + + *pp_data = cfg_param; +} + +static void check_cfg_params(ConfigParam_t *cfg_param) +{ + LOG(STF_LEVEL_TRACE, "Enter\n"); + int disp_type = cfg_param->disp_type; + int io_mthd = cfg_param->io_mthd; + int ret = EXIT_FAILURE; + + assert(disp_type >= STF_DISP_NONE && disp_type <= STF_DISP_DRM); + assert(io_mthd >= IO_METHOD_MMAP && io_mthd <= IO_METHOD_READ); + + // when mmap, support display NONE, DRM, FB + if (IO_METHOD_MMAP == io_mthd) { + ret = EXIT_SUCCESS; + } + + // when dmabuf, only support DRM, and not save file + if (IO_METHOD_DMABUF == io_mthd + && STF_DISP_DRM == disp_type + && !cfg_param->jpegFilename) { + ret = EXIT_SUCCESS; + } + + if (EXIT_FAILURE == ret) { + LOG(STF_LEVEL_ERR, "Not support: io method is %s, display type is %s\n", + g_iomthd_values[io_mthd].name, g_disp_values[disp_type].name); + exit(EXIT_FAILURE); + } + + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +/** +SIGINT interput handler +*/ +void StopContCapture(int sig_id) { + LOG(STF_LEVEL_INFO, "stoping continuous capture\n"); + gp_cfg_param->continuous = 0; +} + +void InstallSIGINTHandler() { + struct sigaction sa; + CLEAR(sa); + + sa.sa_handler = StopContCapture; + if (sigaction(SIGINT, &sa, 0) != 0) { + LOG(STF_LEVEL_ERR, "could not install SIGINT handler, continuous capture disabled\n"); + gp_cfg_param->continuous = 0; + } +} + +/** + process image read, recommand NV21 or NV12 + TODO: use ffmpeg or opencv to convert the image format +*/ +static void imageProcess(const uint8_t* inbuf, uint8_t* outbuf, + struct timeval timestamp) +{ + //timestamp.tv_sec + //timestamp.tv_usec + int in_width = gp_cfg_param->v4l2_param.width; + int in_height = gp_cfg_param->v4l2_param.height; + int in_imagesize = gp_cfg_param->v4l2_param.image_size; + uint32_t in_format = gp_cfg_param->v4l2_param.format; + char* jpegFilename = gp_cfg_param->jpegFilename; + int disp_type = gp_cfg_param->disp_type; + int new_in_format = 0; + int out_format = 0; + int out_size = 0; + uint8_t* dst = malloc(in_width * in_height * 3); + int is_yuv420sp = 0; // NOTE: NV21 or NV12, it is special for starfive framebuffer + static int s_frmcnt = 0; + + if (STF_DISP_FB == disp_type) { + new_in_format = v4l2fmt_to_fbfmt(in_format); + out_format = gp_cfg_param->fb_param.pixformat; + out_size = gp_cfg_param->fb_param.screen_size; + is_yuv420sp = gp_cfg_param->fb_param.vinfo.grayscale; + } else if (STF_DISP_DRM == disp_type) { + new_in_format = v4l2fmt_to_drmfmt(in_format); + out_format = gp_cfg_param->drm_param.dev_head->drm_format; + out_size = gp_cfg_param->drm_param.dev_head->bufs[0].size; + } + + LOG(STF_LEVEL_LOG, "in_width=%d, in_height=%d, in_imagesize=%d, out_size=%d, p=%p\n", + in_width, in_height, in_imagesize, out_size, inbuf); + + // write jpeg + char filename[512]; + switch (in_format) { + case V4L2_PIX_FMT_YUV420: + // if (jpegFilename) { + // // sprintf(filename, "%d-yuv420-%s", s_frmcnt, jpegFilename); + // // YUV420toYUV444(in_width, in_height, inbuf, dst); + // // jpegWrite(dst, filename); + // sprintf(filename, "raw-%d-yuv420-%s", s_frmcnt, jpegFilename); + // write_file(filename, inbuf, in_imagesize); + // s_frmcnt++; + // } + if (gp_cfg_param->jpegFilename && gp_cfg_param->rec_fp) { + fwrite(inbuf, in_imagesize, 1, gp_cfg_param->rec_fp); + } + break; + case V4L2_PIX_FMT_YUYV: + case V4L2_PIX_FMT_YVYU: + // if (jpegFilename) { + // // sprintf(filename, "%d-yuv422-%s", s_frmcnt, jpegFilename); + // // YUV422toYUV444(in_width, in_height, inbuf, dst); + // // jpegWrite(dst, filename); + // sprintf(filename, "raw-%d-yuv422-%s", s_frmcnt, jpegFilename); + // write_file(filename, inbuf, in_imagesize); + // s_frmcnt++; + // } + if (gp_cfg_param->jpegFilename && gp_cfg_param->rec_fp) { + fwrite(inbuf, in_imagesize, 1, gp_cfg_param->rec_fp); + } + if (out_format == new_in_format) { + yuyv_resize(inbuf, outbuf, in_width, in_height); + } else if ((STF_DISP_FB == disp_type) && is_yuv420sp) { + convert_yuyv_to_nv12(inbuf, outbuf, in_width, in_height, 1); + } else if ((STF_DISP_DRM == disp_type) && (out_format == V4L2_PIX_FMT_NV12)) { + convert_yuyv_to_nv12(inbuf, outbuf, in_width, in_height, 1); + } else { + convert_yuyv_to_rgb(inbuf, outbuf, in_width, in_height, 0); + } + break; + case V4L2_PIX_FMT_NV21: + // if (gp_cfg_param->jpegFilename) { + // // sprintf(filename, "%d-nv21-%s", s_frmcnt, gp_cfg_param->jpegFilename); + // // YUV420NV21toYUV444(in_width, in_height, inbuf, dst, 0); + // // jpegWrite(dst, filename); + // sprintf(filename, "raw-nv21-%s", gp_cfg_param->jpegFilename); + // write_file(filename, inbuf, in_imagesize); + // s_frmcnt++; + // } + if (gp_cfg_param->jpegFilename && gp_cfg_param->rec_fp) { + fwrite(inbuf, in_imagesize, 1, gp_cfg_param->rec_fp); + } + LOG(STF_LEVEL_LOG, "out_format=%d, new_in_format=%d, is_yuv420sp=%d\n", out_format, + new_in_format, is_yuv420sp); + if (outbuf) { + if (out_format == new_in_format) { + convert_nv21_to_nv12(inbuf, outbuf, in_width, in_height, 0); + } else if ((STF_DISP_FB == disp_type) && is_yuv420sp) { + convert_nv21_to_nv12(inbuf, outbuf, in_width, in_height, 1); + } else { + convert_nv21_to_nv12(inbuf, outbuf, in_width, in_height, 1); + } + } + break; + case V4L2_PIX_FMT_NV12: + // if (jpegFilename) { + // // sprintf(filename, "%d-nv12-%s", s_frmcnt, jpegFilename); + // // YUV420NV12toYUV444(in_width, in_height, inbuf, dst); + // // jpegWrite(dst, filename); + // sprintf(filename, "raw-%d-nv12-%s", s_frmcnt, jpegFilename); + // write_file(filename, inbuf, in_imagesize); + // s_frmcnt++; + // } + if (gp_cfg_param->jpegFilename && gp_cfg_param->rec_fp) { + fwrite(inbuf, in_imagesize, 1, gp_cfg_param->rec_fp); + } + LOG(STF_LEVEL_DEBUG, "out_format=%d, new_in_format=%d, is_yuv420sp=%d\n", out_format, + new_in_format, is_yuv420sp); + if (out_format == new_in_format) { + convert_nv21_to_nv12(inbuf, outbuf, in_width, in_height, 0); + } else if ((STF_DISP_FB == disp_type) && is_yuv420sp) { + convert_nv21_to_nv12(inbuf, outbuf, in_width, in_height, 1); + } else { + convert_nv21_to_rgb(inbuf, outbuf, in_width, in_height, 0); + } + break; + case V4L2_PIX_FMT_RGB24: + // if (jpegFilename) { + // // sprintf(filename, "%d-rgb-%s", s_frmcnt, jpegFilename); + // // RGB565toRGB888(in_width, in_height, inbuf, dst); + // // write_JPEG_file(filename, inbuf, in_width, in_height, jpegQuality); + // sprintf(filename, "raw-%d-rgb-%s", s_frmcnt, jpegFilename); + // write_file(filename, inbuf, in_imagesize); + // s_frmcnt++; + // } + if (gp_cfg_param->jpegFilename && gp_cfg_param->rec_fp) { + fwrite(inbuf, in_imagesize, 1, gp_cfg_param->rec_fp); + } + convert_rgb888_to_rgb(inbuf, outbuf, in_width, in_height, 0); + break; + case V4L2_PIX_FMT_RGB565: + // if (jpegFilename) { + // // sprintf(filename, "%d-rgb565-%s", s_frmcnt, jpegFilename); + // // RGB565toRGB888(in_width, in_height, inbuf, dst); + // // write_JPEG_file(filename, dst, in_width, in_height, jpegQuality); + // sprintf(filename, "raw-%d-rgb565-%s", s_frmcnt, jpegFilename); + // write_file(filename, inbuf, in_imagesize); + // s_frmcnt++; + // } + if (gp_cfg_param->jpegFilename && gp_cfg_param->rec_fp) { + fwrite(inbuf, in_imagesize, 1, gp_cfg_param->rec_fp); + } + if (out_format == new_in_format) + convert_rgb565_to_rgb(inbuf, outbuf, in_width, in_height, 0); + else if ((STF_DISP_FB == disp_type) && is_yuv420sp) + convert_rgb565_to_nv12(inbuf, outbuf, in_width, in_height, 0); + else + convert_rgb565_to_rgb(inbuf, outbuf, in_width, in_height, 0); + break; + case V4L2_PIX_FMT_SRGGB12: + if (jpegFilename) + sprintf(filename, "raw-%d-RGGB12-%s", s_frmcnt, jpegFilename); + else + sprintf(filename, "raw-%d-RGGB12.raw", s_frmcnt); + write_file(filename, inbuf, in_imagesize); + RAW12toRAW16(in_width, in_height, inbuf, dst); + if (jpegFilename) + sprintf(filename, "raw-%d-RGGB16-%s", s_frmcnt, jpegFilename); + else + sprintf(filename, "raw-%d-RGGB16.raw", s_frmcnt); + write_file(filename, (const uint8_t *)dst, in_width * in_height * 2); + s_frmcnt++; + break; + case V4L2_PIX_FMT_SGRBG12: + if (jpegFilename) + sprintf(filename, "raw-%d-GRBG12-%s", s_frmcnt, jpegFilename); + else + sprintf(filename, "raw-%d-GRBG12.raw", s_frmcnt); + write_file(filename, inbuf, in_imagesize); + RAW12toRAW16(in_width, in_height, inbuf, dst); + if (jpegFilename) + sprintf(filename, "raw-%d-GRBG16-%s", s_frmcnt, jpegFilename); + else + sprintf(filename, "raw-%d-GRBG16.raw", s_frmcnt); + write_file(filename, (const uint8_t *)dst, in_width * in_height * 2); + s_frmcnt++; + break; + case V4L2_PIX_FMT_SGBRG12: + if (jpegFilename) + sprintf(filename, "raw-%d-GBRG12-%s", s_frmcnt, jpegFilename); + else + sprintf(filename, "raw-%d-GBRG12.raw", s_frmcnt); + write_file(filename, inbuf, in_imagesize); + RAW12toRAW16(in_width, in_height, inbuf, dst); + if (jpegFilename) + sprintf(filename, "raw-%d-GBRG16-%s", s_frmcnt, jpegFilename); + else + sprintf(filename, "raw-%d-GBRG16.raw", s_frmcnt); + write_file(filename, (const uint8_t *)dst, in_width * in_height * 2); + s_frmcnt++; + break; + case V4L2_PIX_FMT_SBGGR12: + if (jpegFilename) + sprintf(filename, "raw-%d-BGGR12-%s", s_frmcnt, jpegFilename); + else + sprintf(filename, "raw-%d-BGGR12.raw", s_frmcnt); + write_file(filename, inbuf, in_imagesize); + RAW12toRAW16(in_width, in_height, inbuf, dst); + if (jpegFilename) + sprintf(filename, "raw-%d-BGGR16-%s", s_frmcnt, jpegFilename); + else + sprintf(filename, "raw-%d-BGGR16.raw", s_frmcnt); + write_file(filename, (const uint8_t *)dst, in_width * in_height * 2); + s_frmcnt++; + break; + default: + LOG(STF_LEVEL_ERR, "unknow in_format\n"); + break; + } + + // free temporary image + free(dst); +} + +void calc_frame_fps() +{ + static uint32_t frm_cnt = 0; + static struct timespec ts_old; + struct timespec ts; + uint32_t fps = 0; + uint32_t diff_ms = 0; + + if (frm_cnt == 0) { + clock_gettime(CLOCK_MONOTONIC, &ts_old); + } + if (frm_cnt++ >= 50) { + clock_gettime(CLOCK_MONOTONIC, &ts); + diff_ms = (ts.tv_sec - ts_old.tv_sec) * 1000 + (ts.tv_nsec - ts_old.tv_nsec) / 1000000; + fps = 1000 * (frm_cnt - 1) / diff_ms; + frm_cnt = 0; + LOG(STF_LEVEL_INFO, "pipeline display fps=%d\n", fps); + } +} + +/** + read single frame +*/ +static int frameRead(void) +{ + struct v4l2_buffer buf; + V4l2Param_t *pv4l2_param = &gp_cfg_param->v4l2_param; + uint8_t *dst = NULL; + + if (STF_DISP_FB == gp_cfg_param->disp_type) { + dst = gp_cfg_param->fb_param.screen_buf; + } else if (STF_DISP_DRM == gp_cfg_param->disp_type && + IO_METHOD_DMABUF != gp_cfg_param->io_mthd) { + dst = gp_cfg_param->drm_param.dev_head->bufs[0].buf; + } else { + LOG(STF_LEVEL_LOG, "Not display\n"); + } + + switch (pv4l2_param->io_mthd) { + case IO_METHOD_READ: + if (-1 == v4l2_read(pv4l2_param->fd, pv4l2_param->pBuffers[0].start, + pv4l2_param->pBuffers[0].length)) { + switch (errno) { + case EAGAIN: + return 0; + case EIO: + // Could ignore EIO, see spec. + // fall through + default: + errno_exit("read"); + } + } + struct timespec ts; + struct timeval timestamp; + clock_gettime(CLOCK_MONOTONIC,&ts); + timestamp.tv_sec = ts.tv_sec; + timestamp.tv_usec = ts.tv_nsec/1000; + imageProcess((uint8_t *)(pv4l2_param->pBuffers[0].start), dst, timestamp); + break; + + case IO_METHOD_MMAP: + stf_v4l2_dequeue_buffer(pv4l2_param, &buf); + LOG(STF_LEVEL_LOG, "buf.index=%d, n_buffers=%d\n", + buf.index, gp_cfg_param->v4l2_param.n_buffers); + imageProcess((uint8_t *)(pv4l2_param->pBuffers[buf.index].start), dst, buf.timestamp); + stf_v4l2_queue_buffer(pv4l2_param, buf.index); + if (STF_DISP_DRM == gp_cfg_param->disp_type) { + drmModePageFlip(gp_cfg_param->drm_param.fd, gp_cfg_param->drm_param.dev_head->crtc_id, + gp_cfg_param->drm_param.dev_head->bufs[0].fb_id, + DRM_MODE_PAGE_FLIP_EVENT, gp_cfg_param->drm_param.dev_head); + } + LOG(STF_LEVEL_LOG, "buf.index: %d, buf.bytesused=%d\n", buf.index, buf.bytesused); + break; + + case IO_METHOD_USERPTR: + stf_v4l2_dequeue_buffer(pv4l2_param, &buf); + imageProcess((uint8_t *)(buf.m.userptr), dst, buf.timestamp); + stf_v4l2_queue_buffer(pv4l2_param, buf.index); + break; + case IO_METHOD_DMABUF: + default: + break; + } + return 1; +} + +/** + * mainloop_select: read frames with select() and process them + */ +static void mainloop_select(void) +{ + int count, i; + uint32_t numberOfTimeouts; + + numberOfTimeouts = 0; + count = 3; + + while (count-- > 0) { + for (i = 0; i < 1; i++) { + fd_set fds; + struct timeval tv; + int r; + + FD_ZERO(&fds); + FD_SET(gp_cfg_param->v4l2_param.fd, &fds); + + /* Timeout. */ + tv.tv_sec = 1; + tv.tv_usec = 0; + r = select(gp_cfg_param->v4l2_param.fd + 1, &fds, NULL, NULL, &tv); + if (-1 == r) { + if (EINTR == errno) { + continue; + } + errno_exit("select"); + } else if (0 == r) { + if (numberOfTimeouts <= 0) { + // count++; + } else { + LOG(STF_LEVEL_ERR, "select timeout\n"); + exit(EXIT_FAILURE); + } + } + if (gp_cfg_param->continuous == 1) { + count = 3; + } + + if (frameRead()) + break; + + /* EAGAIN - continue select loop. */ + } + } +} + +static void page_flip_handler(int fd, unsigned int frame, + unsigned int sec, unsigned int usec, + void *data) +{ + struct drm_dev_t *dev = data; + + /* If we have a next buffer, then let's return the current one, + * and grab the next one. + */ + if (g_drm_buf_next_idx > 0) { + stf_v4l2_queue_buffer(&gp_cfg_param->v4l2_param, g_drm_buf_curr_idx); + g_drm_buf_curr_idx = g_drm_buf_next_idx; + g_drm_buf_next_idx = -1; + } + drmModePageFlip(fd, dev->crtc_id, dev->bufs[g_drm_buf_curr_idx].fb_id, + DRM_MODE_PAGE_FLIP_EVENT, dev); +} + +static void mainloop() +{ + struct v4l2_buffer buf; + int r; + int count = 3; + drmEventContext ev; + struct pollfd* fds = NULL; + uint32_t nfds = 0; + + LOG(STF_LEVEL_TRACE, "Enter\n"); + if (STF_DISP_FB == gp_cfg_param->disp_type || + IO_METHOD_MMAP == gp_cfg_param->io_mthd) { + // fb or (drm + mmap) + nfds = 1; + fds = (struct pollfd*)malloc(sizeof(struct pollfd) * nfds); + memset(fds, 0, sizeof(struct pollfd) * nfds); + fds[0].fd = gp_cfg_param->v4l2_param.fd; + fds[0].events = POLLIN; + } else if (STF_DISP_DRM == gp_cfg_param->disp_type && + IO_METHOD_DMABUF == gp_cfg_param->io_mthd) { + // (drm + dmabuf) + nfds = 2; + fds = (struct pollfd*)malloc(sizeof(struct pollfd) * nfds); + memset(fds, 0, sizeof(struct pollfd) * nfds); + fds[0].fd = gp_cfg_param->v4l2_param.fd; + fds[0].events = POLLIN; + fds[1].fd = gp_cfg_param->drm_param.fd; + fds[1].events = POLLIN; + + memset(&ev, 0, sizeof ev); + ev.version = DRM_EVENT_CONTEXT_VERSION; + ev.vblank_handler = NULL; + ev.page_flip_handler = page_flip_handler; + } else { + LOG(STF_LEVEL_ERR, "Display type %d and io method type %d not support\n", + gp_cfg_param->disp_type, gp_cfg_param->io_mthd); + exit(EXIT_FAILURE); + } + + if (!gp_cfg_param->rec_fp && gp_cfg_param->jpegFilename) { + gp_cfg_param->rec_fp = fopen(gp_cfg_param->jpegFilename, "w+"); + if (!gp_cfg_param->rec_fp) { + LOG(STF_LEVEL_ERR, "can't open %s\n", gp_cfg_param->jpegFilename); + exit(EXIT_FAILURE); + } + } + + while (count-- > 0) { + r = poll(fds, nfds, 3000); + if (-1 == r) { + if (EINTR == errno) { + continue; + } + LOG(STF_LEVEL_ERR, "error in poll %d", errno); + break; + } + if (0 == r) { + LOG(STF_LEVEL_ERR, "poll timeout, %d\n", errno); + break; + } + + if (STF_DISP_FB == gp_cfg_param->disp_type || + IO_METHOD_MMAP == gp_cfg_param->io_mthd) { + // fb or (drm + mmap) + if (fds[0].revents & POLLIN) { + frameRead(); + calc_frame_fps(); + } + } else if (STF_DISP_DRM == gp_cfg_param->disp_type && + IO_METHOD_DMABUF == gp_cfg_param->io_mthd) { + // drm + dmabuf + if (fds[0].revents & POLLIN) { + int dequeued = stf_v4l2_dequeue_buffer(&gp_cfg_param->v4l2_param, &buf); + if (dequeued) { + g_drm_buf_next_idx = buf.index; + frameRead(); // TODO: add support for save file later + calc_frame_fps(); + } + } + if (fds[1].revents & POLLIN) { + if (g_drm_buf_next_idx > 0) { + drmHandleEvent(gp_cfg_param->drm_param.fd, &ev); + } + } + } + + if (gp_cfg_param->continuous == 1) { + count = 3; + } + + usleep(1 * 1000); + } + + if (fds) { + free(fds); + fds = NULL; + } + + + if (gp_cfg_param->rec_fp) { + fclose(gp_cfg_param->rec_fp); + gp_cfg_param->rec_fp = NULL; + } + + + LOG(STF_LEVEL_TRACE, "Exit\n"); +} + +static void usage(FILE* fp, int argc, char** argv) +{ + fprintf(fp, + "Usage: %s [options]\n\n" + "Options:\n" + "-d | --device name Video device name [default /dev/video0]\n" + "-h | --help Print this message\n" + "-o | --output Save raw data to filename\n" + //"-q | --quality Set JPEG quality (0-100)\n" + "-m | --method Set V4L2 videobuf2 memory type, default 0\n" + " 0: IO_METHOD_MMAP\n" + " 1: IO_METHOD_USERPTR\n" + " 2: IO_METHOD_DMABUF\n" + " 3: IO_METHOD_READ\n" + "-W | --width Set v4l2 image width, default 1920\n" + "-H | --height Set v4l2 image height, default 1080\n" + "-X | --left Set v4l2 image crop x start\n" + "-Y | --up Set v4l2 image crop y start\n" + "-R | --right Set v4l2 image crop x width\n" + "-D | --down Set v4l2 image crop y height\n" + "-I | --interval Set frame interval (fps) (-1 to skip)\n" + "-c | --continuous Do continous capture, stop with SIGINT.\n" + "-v | --version Print version\n" + "-f | --format image format, default 5\n" + " 0: V4L2_PIX_FMT_RGB565\n" + " 1: V4L2_PIX_FMT_RGB24\n" + " 2: V4L2_PIX_FMT_YUV420\n" + " 3: V4L2_PIX_FMT_YUYV\n" + " 4: V4L2_PIX_FMT_NV21\n" + " 5: V4L2_PIX_FMT_NV12\n" + " 6: V4L2_PIX_FMT_YVYU\n" + " 7: V4L2_PIX_FMT_SRGGB12\n" + " 8: V4L2_PIX_FMT_SGRBG12\n" + " 9: V4L2_PIX_FMT_SGBRG12\n" + " 10: V4L2_PIX_FMT_SBGGR12\n" + " default: V4L2_PIX_FMT_NV12\n" + "-t | --distype set display type, default 0\n" + " 0: Not display\n" + " 1: Use Framebuffer Display\n" + " 2: Use DRM Display\n" + "-l | --loadfw load stfisp fw image\n" + "-s | --g_imagesize print image size\n" + "\n" + "Eg:\n" + "\t drm: v4l2test -d /dev/video2 -f 5 -c -W 1920 -H 1080 -m 2 -t 2\n" + "\t fb: v4l2test -d /dev/video2 -f 5 -c -W 1920 -H 1080 -m 0 -t 1\n" + "\n" + "Open debug log level: \n" + "\t export V4L2_DEBUG=3\n" + "\t default level 1, level range 0 ~ 7\n" + "", + argv[0]); +} + +static const char short_options [] = "d:ho:q:m:W:H:I:vcf:t:X:Y:R:D:l:s"; + +static const struct option long_options [] = { + { "device", required_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, + { "output", required_argument, NULL, 'o' }, + { "quality", required_argument, NULL, 'q' }, + { "method", required_argument, NULL, 'm' }, + { "width", required_argument, NULL, 'W' }, + { "height", required_argument, NULL, 'H' }, + { "left", required_argument, NULL, 'X' }, + { "up", required_argument, NULL, 'Y' }, + { "right", required_argument, NULL, 'R' }, + { "down", required_argument, NULL, 'D' }, + { "interval", required_argument, NULL, 'I' }, + { "version", no_argument, NULL, 'v' }, + { "continuous", no_argument, NULL, 'c' }, + { "format", required_argument, NULL, 'f' }, + { "distype", required_argument, NULL, 't' }, + { "loadfw", required_argument, NULL, 'l' }, + { "g_imagesize",no_argument, NULL, 's' }, + { 0, 0, 0, 0 } +}; + +void parse_options(int argc, char **argv, ConfigParam_t *cfg_param) +{ + int index, c = 0; + int value = 0; + + while ((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) { + switch (c) { + case 0: /* getopt_long() flag */ + break; + + case 'd': + cfg_param->v4l2_param.device_name = strdup(optarg); + break; + + case 'h': + usage(stdout, argc, argv); + exit(EXIT_SUCCESS); + + case 'o': + // set jpeg filename + cfg_param->jpegFilename = strdup(optarg); + break; + + case 'q': + // set jpeg quality + cfg_param->jpegQuality = atoi(optarg); + break; + + case 'm': + value = atoi(optarg); + if (value < IO_METHOD_MMAP || value > IO_METHOD_READ) { + LOG(STF_LEVEL_ERR, "io method %d is out of range [%d, %d]\n", value, + IO_METHOD_MMAP, IO_METHOD_READ); + exit(EXIT_FAILURE); + } + LOG(STF_LEVEL_INFO, "io method: %s\n", g_iomthd_values[value].name); + cfg_param->io_mthd = value; + cfg_param->v4l2_param.io_mthd = cfg_param->io_mthd; + break; + + case 'W': + // set v4l2 width + cfg_param->v4l2_param.width = atoi(optarg); + break; + + case 'H': + // set v4l2 height + cfg_param->v4l2_param.height = atoi(optarg); + break; + + case 'X': + // set x start + cfg_param->v4l2_param.crop_info.left = atoi(optarg); + cfg_param->v4l2_param.crop_flag = 1; + break; + + case 'Y': + // set y start + cfg_param->v4l2_param.crop_info.top = atoi(optarg); + cfg_param->v4l2_param.crop_flag = 1; + break; + + case 'R': + // set x width + cfg_param->v4l2_param.crop_info.width = atoi(optarg); + cfg_param->v4l2_param.crop_flag = 1; + break; + + case 'D': + // set y height + cfg_param->v4l2_param.crop_info.height = atoi(optarg); + cfg_param->v4l2_param.crop_flag = 1; + break; + + case 'I': + // set fps + cfg_param->v4l2_param.fps = atoi(optarg); + break; + + case 'c': + // set flag for continuous capture, interuptible by sigint + cfg_param->continuous = 1; + InstallSIGINTHandler(); + break; + + case 'v': + printf("Version: %s\n", TEST_VERSION); + exit(EXIT_SUCCESS); + break; + + case 'f': + LOG(STF_LEVEL_INFO, "v4l2 format: %s\n", optarg); + value = atoi(optarg); + LOG(STF_LEVEL_INFO, "v4l2 format: %d\n", value); + switch (value) { + case 0: + value = V4L2_PIX_FMT_RGB565; + break; + case 1: + value = V4L2_PIX_FMT_RGB24; + break; + case 2: + value = V4L2_PIX_FMT_YUV420; + break; + case 3: + value = V4L2_PIX_FMT_YUYV; + break; + case 4: + value = V4L2_PIX_FMT_NV21; + break; + case 5: + value = V4L2_PIX_FMT_NV12; + break; + case 6: + value = V4L2_PIX_FMT_YVYU; + break; + case 7: + value = V4L2_PIX_FMT_SRGGB12; + break; + case 8: + value = V4L2_PIX_FMT_SGRBG12; + break; + case 9: + value = V4L2_PIX_FMT_SGBRG12; + break; + case 10: + value = V4L2_PIX_FMT_SBGGR12; + break; + default: + value = V4L2_PIX_FMT_RGB565; + break; + } + cfg_param->v4l2_param.format = value; + break; + + case 't': + value = atoi(optarg); + if (value < STF_DISP_NONE || value > STF_DISP_DRM) { + LOG(STF_LEVEL_ERR, "Display Type %d is out of range [%d, %d]\n", value, + STF_DISP_NONE, STF_DISP_DRM); + exit(EXIT_FAILURE); + } + LOG(STF_LEVEL_INFO, "Display Type: %s\n", g_disp_values[value].name); + cfg_param->disp_type = value; + break; + + case 'l': + loadfw_start(optarg, &(cfg_param->v4l2_param)); + exit(EXIT_SUCCESS); + break; + case 's': + sensor_image_size_info(&(cfg_param->v4l2_param)); + exit(EXIT_SUCCESS); + break; + default: + usage(stderr, argc, argv); + exit(EXIT_FAILURE); + } + } +} + +int main(int argc, char **argv) +{ + init_log(); + alloc_default_config(&gp_cfg_param); + parse_options(argc, argv, gp_cfg_param); + check_cfg_params(gp_cfg_param); + + // open and initialize v4l2 device + stf_v4l2_open(&gp_cfg_param->v4l2_param, gp_cfg_param->v4l2_param.device_name); + stf_v4l2_init(&gp_cfg_param->v4l2_param); + + if (STF_DISP_FB == gp_cfg_param->disp_type) { + stf_fb_open(&gp_cfg_param->fb_param, FB_DEVICE_NAME, STFBC_DEVICE_NAME); + stf_fb_init(&gp_cfg_param->fb_param, gp_cfg_param->v4l2_param.format); + update_videocvt_param(gp_cfg_param->disp_type, gp_cfg_param->fb_param.width, + gp_cfg_param->fb_param.height, gp_cfg_param->fb_param.bpp, + gp_cfg_param->fb_param.screen_size); + + } else if (STF_DISP_DRM == gp_cfg_param->disp_type) { + stf_drm_open(&gp_cfg_param->drm_param, DRM_DEVICE_NAME, gp_cfg_param->io_mthd); + stf_drm_init(&gp_cfg_param->drm_param, gp_cfg_param->v4l2_param.width, + gp_cfg_param->v4l2_param.height, gp_cfg_param->v4l2_param.format, + gp_cfg_param->io_mthd, gp_cfg_param->dmabufs, + sizeof(gp_cfg_param->dmabufs) / sizeof(gp_cfg_param->dmabufs[0])); + update_videocvt_param(gp_cfg_param->disp_type, gp_cfg_param->drm_param.dev_head->width, + gp_cfg_param->drm_param.dev_head->height, 32, + gp_cfg_param->drm_param.dev_head->bufs[0].size); + + } + + // prepare and start v4l2 capturing + sft_v4l2_prepare_capturing(&gp_cfg_param->v4l2_param, gp_cfg_param->dmabufs, BUFCOUNT); + sft_v4l2_start_capturing(&(gp_cfg_param->v4l2_param)); + + // process frames + mainloop(); + + stf_v4l2_stop_capturing(&gp_cfg_param->v4l2_param); + stf_v4l2_uninit(&gp_cfg_param->v4l2_param); + stf_v4l2_close(&gp_cfg_param->v4l2_param); + + if (STF_DISP_FB == gp_cfg_param->disp_type) { + stf_fb_uninit(&gp_cfg_param->fb_param); + stf_fb_close(&gp_cfg_param->fb_param); + } else if (STF_DISP_DRM == gp_cfg_param->disp_type) { + stf_drm_close(&gp_cfg_param->drm_param); + } + + deinit_log(); + free(gp_cfg_param); + return 0; +} diff --git a/package/starfive/v4l2_test/v4l2_test.mk b/package/starfive/v4l2_test/v4l2_test.mk new file mode 100644 index 00000000..1017b7e6 --- /dev/null +++ b/package/starfive/v4l2_test/v4l2_test.mk @@ -0,0 +1,39 @@ +################################################################################ +# +# v4l2test +# +################################################################################ + +V4L2_TEST_LICENSE = GPL-2.0+ + +define V4L2_TEST_BUILD_CMDS + cp package/starfive/v4l2_test/v4l2_test.c $(@D)/ + cp package/starfive/v4l2_test/yuv.c $(@D)/ + cp package/starfive/v4l2_test/yuv.h $(@D)/ + cp package/starfive/v4l2_test/convert.c $(@D)/ + cp package/starfive/v4l2_test/convert.h $(@D)/ + cp package/starfive/v4l2_test/stf_v4l2.c $(@D)/ + cp package/starfive/v4l2_test/stf_v4l2.h $(@D)/ + cp package/starfive/v4l2_test/stf_framebuffer.c $(@D)/ + cp package/starfive/v4l2_test/stf_framebuffer.h $(@D)/ + cp package/starfive/v4l2_test/stf_drm.c $(@D)/ + cp package/starfive/v4l2_test/stf_drm.h $(@D)/ + cp package/starfive/v4l2_test/config.h $(@D)/ + cp package/starfive/v4l2_test/common.c $(@D)/ + cp package/starfive/v4l2_test/common.h $(@D)/ + cp package/starfive/v4l2_test/stf_log.c $(@D)/ + cp package/starfive/v4l2_test/stf_log.h $(@D)/ + cp package/starfive/v4l2_test/media-ctl-pipeline.sh $(@D)/ + (cd $(@D); $(TARGET_CC) -Wall -O2 v4l2_test.c common.c yuv.c convert.c \ + stf_v4l2.c stf_framebuffer.c stf_drm.c stf_log.c -lv4l2 -ljpeg \ + -I$(STAGING_DIR)/usr/include/drm -ldrm -o v4l2test) +endef + +define V4L2_TEST_INSTALL_TARGET_CMDS + install -m 0755 -D $(@D)/v4l2test $(TARGET_DIR)/usr/bin/v4l2test + install -m 0755 -D $(@D)/media-ctl-pipeline.sh $(TARGET_DIR)/usr/bin/media-ctl-pipeline.sh +endef + +V4L2_TEST_DEPENDENCIES = jpeg libv4l +$(eval $(generic-package)) + diff --git a/package/v4l2_test/yuv.c b/package/starfive/v4l2_test/yuv.c old mode 100755 new mode 100644 similarity index 88% rename from package/v4l2_test/yuv.c rename to package/starfive/v4l2_test/yuv.c index b2f640c7..57eab2ac --- a/package/v4l2_test/yuv.c +++ b/package/starfive/v4l2_test/yuv.c @@ -51,7 +51,9 @@ void YUV420toYUV444(int width, int height, unsigned char* src, unsigned char* ds } } -void YUV420NV21toYUV444(int width, int height, unsigned char* src, unsigned char* dst) { +void YUV420NV21toYUV444(int width, int height, unsigned char* src, unsigned char* dst, + int is_nv21) +{ int line, column; unsigned char *py, *pu, *pv; unsigned char *tmp = dst; @@ -64,10 +66,14 @@ void YUV420NV21toYUV444(int width, int height, unsigned char* src, unsigned char for (line = 0; line < height; ++line) { for (column = 0; column < width; ++column) { - py = base_py+(line*width)+column; - pu = base_pu+((line/2*width/2)+column/2)*2+1; - pv = base_pv+((line/2*width/2)+column/2)*2; - + py = base_py + (line * width) + column; + if (is_nv21) { + pu = base_pu + ((line / 2 * width / 2) + column / 2) * 2 + 1; + pv = base_pv + ((line / 2 * width / 2) + column / 2) * 2; + } else { + pu = base_pu + ((line / 2 * width / 2) + column / 2) * 2; + pv = base_pv + ((line / 2 * width / 2) + column / 2) * 2 + 1; + } *tmp++ = *py; *tmp++ = *pu; *tmp++ = *pv; @@ -83,8 +89,8 @@ void YUV422toYUV444(int width, int height, unsigned char* src, unsigned char* ds // In this format each four bytes is two pixels. Each four bytes is two Y's, a Cb and a Cr. // Each Y goes to one of the pixels, and the Cb and Cr belong to both pixels. unsigned char *base_py = src; - unsigned char *base_pu = src+(height*width); - unsigned char *base_pv = src+(height*width)+(height*width)/2; + //unsigned char *base_pu = src+(height*width); + //unsigned char *base_pv = src+(height*width)+(height*width)/2; for (line = 0; line < height; ++line) { for (column = 0; column < width; ++column) { diff --git a/package/v4l2_test/yuv.h b/package/starfive/v4l2_test/yuv.h old mode 100755 new mode 100644 similarity index 77% rename from package/v4l2_test/yuv.h rename to package/starfive/v4l2_test/yuv.h index 7c4101aa..3090f681 --- a/package/v4l2_test/yuv.h +++ b/package/starfive/v4l2_test/yuv.h @@ -4,7 +4,7 @@ void YUV420toYUV444(int width, int height, unsigned char* src, unsigned char* dst); void YUV422toYUV444(int width, int height, unsigned char* src, unsigned char* dst); void RGB565toRGB888(int width, int height, unsigned char* src, unsigned char* dst); -void RAW12toRAW16(int width, int height, unsigned char* src, unsigned char* dst); -void YUV420NV21toYUV444(int width, int height, unsigned char* src, unsigned char* dst); - +void RAW12toRAW16(int width, int height, const unsigned char* src, unsigned char* dst); +void YUV420NV21toYUV444(int width, int height, unsigned char* src, unsigned char* dst, + int is_nv21); #endif diff --git a/package/v4l2_test/convert.h b/package/v4l2_test/convert.h deleted file mode 100755 index 29ec15b4..00000000 --- a/package/v4l2_test/convert.h +++ /dev/null @@ -1,16 +0,0 @@ - -#ifndef _CONVERT_H_ -#define _CONVERT_H_ - -extern int yuyv_resize(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight); - -extern int convert_yuyv_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_yuyv); -extern int convert_nv21_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21); -extern int convert_nv21_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21); -extern int convert_rgb565_to_nv12(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int is_nv21); -extern int convert_yuyv_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod); -extern int convert_yuv444_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod); -extern int convert_rgb565_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod); -extern int convert_rgb888_to_rgb(unsigned char *inBuf, unsigned char *outBuf, int imgWidth, int imgHeight, int cvtMethod); - -#endif // _CONVERT_H_ diff --git a/package/v4l2_test/pipeline_setting.sh b/package/v4l2_test/pipeline_setting.sh deleted file mode 100755 index b7f03d1e..00000000 --- a/package/v4l2_test/pipeline_setting.sh +++ /dev/null @@ -1,283 +0,0 @@ -#!/bin/sh - -USAGE="Usage: media-ctl-pipeline interface_type sensor_type {start|stop}" - -echo "Pipeline $1 $2 $3" - -case $1 in - dvp) - case $3 in - start) - # media-ctl -vl "'sc2235 1-0030':0 -> 'stf_dvp0':0 [1]" - # media-ctl -vl "'ov5640 1-003c':0 -> 'stf_dvp0':0 [1]" - case $2 in - VIN) - echo "DVP vin 使能pipeline:" - media-ctl -vl "'stf_dvp0':1 -> 'stf_vin0_wr':0 [1]" - # media-ctl -vl "'stf_vin0_wr':1 -> 'stf_vin0_wr_video0':0 [1]" - ;; - ISP0) - echo "DVP ISP0 使能pipeline:" - media-ctl -vl "'stf_dvp0':1 -> 'stf_isp0':0 [1]" - media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [1]" - # media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]" - ;; - ISP0RAW) - echo "DVP ISP0RAW 使能pipeline:" - media-ctl -vl "'stf_dvp0':1 -> 'stf_isp0':0 [1]" - media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [1]" - # media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]" - ;; - ISP1) - echo "DVP ISP1 使能pipeline:" - media-ctl -vl "'stf_dvp0':1 -> 'stf_isp1':0 [1]" - media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [1]" - # media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]" - ;; - ISP1RAW) - echo "DVP ISP1RAW 使能pipeline:" - media-ctl -vl "'stf_dvp0':1 -> 'stf_isp1':0 [1]" - media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [1]" - # media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]" - ;; - *) - echo $USAGE - exit 1 - ;; - esac - ;; - stop) - # media-ctl -vl "'sc2235 1-0030':0 -> 'stf_dvp0':0 [0]" - # media-ctl -vl "'ov5640 1-003c':0 -> 'stf_dvp0':0 [0]" - case $2 in - VIN) - echo "DVP vin 关闭pipeline:" - media-ctl -vl "'stf_dvp0':1 -> 'stf_vin0_wr':0 [0]" - # media-ctl -vl "'stf_vin0_wr':1 -> 'stf_vin0_wr_video0':0 [0]" - ;; - ISP0) - echo "DVP ISP0 关闭pipeline:" - media-ctl -vl "'stf_dvp0':1 -> 'stf_isp0':0 [0]" - media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [0]" - # media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]" - ;; - ISP0RAW) - echo "DVP ISP0RAW 关闭pipeline:" - media-ctl -vl "'stf_dvp0':1 -> 'stf_isp0':0 [0]" - media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [0]" - # media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]" - ;; - ISP1) - echo "DVP ISP1 关闭pipeline:" - media-ctl -vl "'stf_dvp0':1 -> 'stf_isp1':0 [0]" - media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [0]" - # media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]" - ;; - ISP1RAW) - echo "DVP ISP1RAW 关闭pipeline:" - media-ctl -vl "'stf_dvp0':1 -> 'stf_isp1':0 [0]" - media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [0]" - # media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]" - ;; - *) - echo $USAGE - exit 1 - ;; - esac - ;; - *) - echo $USAGE - exit 1 - ;; - esac - ;; - csiphy0) - case $3 in - start) - # media-ctl -vl "'ov4689 0-0036':0 -> 'stf_csiphy0':0 [1]" - case $2 in - VIN) - echo "csiphy0 CSIRX0 vin 使能pipeline:" - media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]" - media-ctl -vl "'stf_csi0':1 -> 'stf_vin0_wr':0 [1]" - ;; - ISP0) - echo "csiphy0 CSIRX0 ISP0 使能pipeline:" - media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]" - media-ctl -vl "'stf_csi0':1 -> 'stf_isp0':0 [1]" - media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [1]" - # media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]" - ;; - ISP0RAW) - echo "csiphy0 CSIRX0 ISP0RAW 使能pipeline:" - media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]" - media-ctl -vl "'stf_csi0':1 -> 'stf_isp0':0 [1]" - media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [1]" - # media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]" - ;; - ISP1) - echo "csiphy0 CSIRX0 ISP1 使能pipeline:" - media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]" - media-ctl -vl "'stf_csi0':1 -> 'stf_isp1':0 [1]" - media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [1]" - # media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]" - ;; - ISP1RAW) - echo "csiphy0 CSIRX0 ISP1RAW 使能pipeline:" - media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [1]" - media-ctl -vl "'stf_csi0':1 -> 'stf_isp1':0 [1]" - media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [1]" - # media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]" - ;; - - *) - echo $USAGE - exit 1 - ;; - esac - ;; - stop) - # media-ctl -vl "'ov4689 0-0036':0 -> 'stf_csiphy0':0 [0]" - case $2 in - VIN) - echo "csiphy0 CSIRX0 vin 关闭pipeline:" - media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]" - media-ctl -vl "'stf_csi0':1 -> 'stf_vin0_wr':0 [0]" - ;; - ISP0) - echo "csiphy0 CSIRX0 ISP0 关闭pipeline:" - media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]" - media-ctl -vl "'stf_csi0':1 -> 'stf_isp0':0 [0]" - media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [0]" - # media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]" - ;; - ISP0RAW) - echo "csiphy0 CSIRX0 ISP0RAW 关闭pipeline:" - media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]" - media-ctl -vl "'stf_csi0':1 -> 'stf_isp0':0 [0]" - media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [0]" - # media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]" - ;; - ISP1) - echo "csiphy0 CSIRX0 ISP1 关闭pipeline:" - media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]" - media-ctl -vl "'stf_csi0':1 -> 'stf_isp1':0 [0]" - media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [0]" - # media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]" - ;; - ISP1RAW) - echo "csiphy0 CSIRX0 ISP1RAW 关闭pipeline:" - media-ctl -vl "'stf_csiphy0':1 -> 'stf_csi0':0 [0]" - media-ctl -vl "'stf_csi0':1 -> 'stf_isp1':0 [0]" - media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [0]" - # media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]" - ;; - - *) - echo $USAGE - exit 1 - ;; - esac - ;; - *) - echo $USAGE - exit 1 - ;; - esac - ;; - csiphy1) - case $3 in - start) - # media-ctl -vl "'ov4689 2-0036':0 -> 'stf_csiphy1':0 [1]" - case $2 in - VIN) - echo "csiphy1 CSIRX0 vin 使能pipeline:" - ;; - ISP0) - echo "csiphy1 CSIRX1 ISP0 使能pipeline:" - media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [1]" - media-ctl -vl "'stf_csi1':1 -> 'stf_isp0':0 [1]" - media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [1]" - # media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]" - ;; - ISP0RAW) - echo "csiphy1 CSIRX1 ISP0RAW 使能pipeline:" - media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [1]" - media-ctl -vl "'stf_csi1':1 -> 'stf_isp0':0 [1]" - media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [1]" - # media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [1]" - ;; - ISP1) - echo "csiphy1 CSIRX1 ISP1 使能pipeline:" - media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [1]" - media-ctl -vl "'stf_csi1':1 -> 'stf_isp1':0 [1]" - media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [1]" - # media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]" - ;; - ISP1RAW) - echo "csiphy1 CSIRX1 ISP1RAW 使能pipeline:" - media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [1]" - media-ctl -vl "'stf_csi1':1 -> 'stf_isp1':0 [1]" - media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [1]" - # media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [1]" - ;; - - *) - echo $USAGE - exit 1 - ;; - esac - ;; - stop) - # media-ctl -vl "'ov4689 0-0036':0 -> 'stf_csiphy0':0 [0]" - case $2 in - VIN) - echo "csiphy1 CSIRX0 vin 关闭pipeline:" - ;; - ISP0) - echo "csiphy1 CSIRX1 ISP0 关闭pipeline:" - media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [0]" - media-ctl -vl "'stf_csi1':1 -> 'stf_isp0':0 [0]" - media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0':0 [0]" - # media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]" - ;; - ISP0RAW) - echo "csiphy1 CSIRX1 ISP0RAW 关闭pipeline:" - media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [0]" - media-ctl -vl "'stf_csi1':1 -> 'stf_isp0':0 [0]" - media-ctl -vl "'stf_isp0':1 -> 'stf_vin0_isp0_raw':0 [0]" - # media-ctl -vl "'stf_vin0_isp0':1 -> 'stf_vin0_isp0_video1':0 [0]" - ;; - ISP1) - echo "csiphy1 CSIRX1 ISP1 关闭pipeline:" - media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [0]" - media-ctl -vl "'stf_csi1':1 -> 'stf_isp1':0 [0]" - media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1':0 [0]" - # media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]" - ;; - ISP1RAW) - echo "csiphy1 CSIRX1 ISP1RAW 关闭pipeline:" - media-ctl -vl "'stf_csiphy1':1 -> 'stf_csi1':0 [0]" - media-ctl -vl "'stf_csi1':1 -> 'stf_isp1':0 [0]" - media-ctl -vl "'stf_isp1':1 -> 'stf_vin0_isp1_raw':0 [0]" - # media-ctl -vl "'stf_vin0_isp1':1 -> 'stf_vin0_isp1_video2':0 [0]" - ;; - *) - echo $USAGE - exit 1 - ;; - esac - ;; - *) - echo $USAGE - exit 1 - ;; - esac - ;; - *) - echo $USAGE - exit 1 - ;; -esac - -exit 0; diff --git a/package/v4l2_test/v4l2_test.c b/package/v4l2_test/v4l2_test.c deleted file mode 100755 index a5303cf7..00000000 --- a/package/v4l2_test/v4l2_test.c +++ /dev/null @@ -1,1711 +0,0 @@ -/*************************************************************************** - * v4l2grab Version 0.3 * - * Copyright (C) 2012 by Tobias Müller * - * Tobias_Mueller@twam.info * - * * - * based on V4L2 Specification, Appendix B: Video Capture Example * - * (http://v4l2spec.bytesex.org/spec/capture-example.html) * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * - ***************************************************************************/ - - /************************************************************************** - * Modification History * - * * - * Matthew Witherwax 21AUG2013 * - * Added ability to change frame interval (ie. frame rate/fps) * - * Martin Savc 7JUL2015 - * Added support for continuous capture using SIGINT to stop. - ***************************************************************************/ - -// compile with all three access methods -#if !defined(IO_READ) && !defined(IO_MMAP) && !defined(IO_USERPTR) -#define IO_READ -#define IO_MMAP -#define IO_USERPTR -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "yuv.h" -#include "convert.h" - -#define CLEAR(x) memset (&(x), 0, sizeof (x)) - -#ifndef VERSION -#define VERSION "unknown" -#endif - -#define FILENAME_MAX_LEN 30 -struct stfisp_fw_info { - char filename[FILENAME_MAX_LEN]; -}; - -#define VIDIOC_STFISP_LOAD_FW \ - _IOW('V', BASE_VIDIOC_PRIVATE + 1, struct stfisp_fw_info) - -#define FBIOPAN_GET_PP_MODE 0x4609 -#define FBIOPAN_SET_PP_MODE 0x460a - -enum COLOR_FORMAT{ - COLOR_YUV422_UYVY = 0, //00={Y1,V0,Y0,U0} - COLOR_YUV422_VYUY = 1, //01={Y1,U0,Y0,V0} - COLOR_YUV422_YUYV = 2, //10={V0,Y1,U0,Y0} - COLOR_YUV422_YVYU = 3, //11={U0,Y1,V0,Y0} - - COLOR_YUV420P, //4 - COLOR_YUV420_NV21, //5 - COLOR_YUV420_NV12, //6 - - COLOR_RGB888_ARGB, //7 - COLOR_RGB888_ABGR, //8 - COLOR_RGB888_RGBA, //9 - COLOR_RGB888_BGRA, //10 - COLOR_RGB565, //11 -}; - -struct pp_video_mode { - enum COLOR_FORMAT format; - unsigned int height; - unsigned int width; - unsigned int addr; -}; - -struct pp_mode { - char pp_id; - bool bus_out; /*out to ddr*/ - bool fifo_out; /*out to lcdc*/ - bool inited; - struct pp_video_mode src; - struct pp_video_mode dst; -}; - -#if defined(IO_MMAP) || defined(IO_USERPTR) -// minimum number of buffers to request in VIDIOC_REQBUFS call -#define VIDIOC_REQBUFS_COUNT 3 -#endif - -typedef enum { -#ifdef IO_READ - IO_METHOD_READ, -#endif -#ifdef IO_MMAP - IO_METHOD_MMAP, -#endif -#ifdef IO_USERPTR - IO_METHOD_USERPTR, -#endif -} io_method; - -struct buffer { - void * start; - size_t length; -}; - -static io_method io = IO_METHOD_MMAP; -static int fd = -1; -static int fbfd = -1; -static int stfbcdevfd = -1; -struct buffer * buffers = NULL; -static unsigned int n_buffers = 0; -struct fb_var_screeninfo vinfo; -struct fb_fix_screeninfo finfo; -static char *fbp = NULL; -long screensize = 1920 * 1080 * 2; -long imagesize = 1920 * 1080 * 2; -// global settings -static unsigned int format= V4L2_PIX_FMT_RGB565; -static int pixformat = COLOR_RGB565; -static unsigned int width = 1920; -static unsigned int height = 1080; -static unsigned int left = 0; -static unsigned int up = 0; -static unsigned int right = 0; -static unsigned int down = 0; -static unsigned int crop_flag = 0; -static int istride = 1280; -static unsigned int fps = 30; -static unsigned int test_fps = 0; -static int continuous = 0; -static unsigned char jpegQuality = 70; -static char* jpegFilename = NULL; -static char* deviceName = "/dev/video0"; -static unsigned int fps_count = 0; - -static const char* const continuousFilenameFmt = "%s_%010"PRIu32"_%"PRId64".jpg"; - -inline int clip(int value, int min, int max) { - return (value > max ? max : value < min ? min : value); -} - -static int v4l2fmt_to_fbfmt(unsigned int format) -{ - int pixformat = COLOR_RGB565; - - switch (format) { - case V4L2_PIX_FMT_RGB565: - pixformat = COLOR_RGB565; - break; - case V4L2_PIX_FMT_RGB24: - pixformat = COLOR_RGB888_ARGB; - break; - case V4L2_PIX_FMT_YUV420: - pixformat = COLOR_YUV420P; - break; - case V4L2_PIX_FMT_YUYV: - pixformat = COLOR_YUV422_YUYV; - break; - case V4L2_PIX_FMT_NV21: - pixformat = COLOR_YUV420_NV21; - break; - case V4L2_PIX_FMT_NV12: - pixformat = COLOR_YUV420_NV12; - break; - case V4L2_PIX_FMT_YVYU: - pixformat = COLOR_YUV422_YVYU; - break; - default: - pixformat = COLOR_RGB565; - break; - } - - return pixformat; -} - -void test_float_1() -{ - int count = 1920 * 1080 * 2; - float r, g, b; - float y = 10, u = 20, v = 30; - int int_r, int_g, int_b; - int int_y = 10, int_u = 20, int_v = 30; - struct timeval tv1, tv2, tv3; - long long elapse = 0; - int i; - - gettimeofday(&tv1, NULL); - while (count--) { - b = 1.164 * (y - 16) + 2.018 * (u - 128); - g = 1.164 * (y - 16) - 0.813 * (v - 128) - 0.391 * (u - 128); - r = 1.164 * (y - 16) + 1.596 * (v - 128); - - y ++; - u ++; - v ++; - } - gettimeofday(&tv2, NULL); - elapse = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000; - printf("elapse: %lldms, out: r=%f, g=%f, b=%f\n", - elapse ,r, g, b); - - count = 1920 * 1080 * 2; - gettimeofday(&tv1, NULL); - while (count--) { - int_b = 1164 * (y - 16) + 2018 * (u - 128); - int_g = 1164 * (y - 16) - 813 * (v - 128) - 391 * (u - 128); - int_r = 1164 * (y - 16) + 1596 * (v - 128); - - int_y ++; - int_u ++; - int_v ++; - } - gettimeofday(&tv2, NULL); - elapse = (tv2.tv_sec - tv1.tv_sec) + (tv2.tv_usec - tv1.tv_usec); - printf("elapse: %lldus, out: r=%d, g=%d, b=%d\n", - elapse , int_r, int_g, int_b); - - count = 1920 * 1080 * 2; - unsigned char* arraybuf = NULL; - arraybuf = (unsigned char*)malloc(count); - if (!arraybuf) { - printf("arraybuf malloc error\n"); - return; - } - - unsigned char* arraybuf2 = NULL; - arraybuf2 = (unsigned char*)malloc(count); - if (!arraybuf2) { - printf("arraybuf2 malloc error\n"); - return; - } - - gettimeofday(&tv1, NULL); - - for (i = 0; i < count; i++) { - arraybuf[i] = i + 1; - } - - gettimeofday(&tv2, NULL); - - memcpy(arraybuf2, arraybuf, count); - - gettimeofday(&tv3, NULL); - - elapse = (tv2.tv_sec - tv1.tv_sec) * 1000 + (tv2.tv_usec - tv1.tv_usec) / 1000; - printf("for() elapse: %lldms\n", elapse); - - elapse = (tv3.tv_sec - tv2.tv_sec) * 1000000 + (tv3.tv_usec - tv2.tv_usec); - printf("memcpy() run elapse: %lldus\n", elapse); - - convert_nv21_to_rgb(arraybuf, arraybuf2, 1920, 1080, 1); - - free(arraybuf); - free(arraybuf2); -} - -/** -SIGINT interput handler -*/ -void StopContCapture(int sig_id) { - printf("stoping continuous capture\n"); - continuous = 0; -} - -void InstallSIGINTHandler() { - struct sigaction sa; - CLEAR(sa); - - sa.sa_handler = StopContCapture; - if(sigaction(SIGINT, &sa, 0) != 0) - { - fprintf(stderr,"could not install SIGINT handler, continuous capture disabled"); - continuous = 0; - } -} - -/** - Print error message and terminate programm with EXIT_FAILURE return code. - - \param s error message to print -*/ -static void errno_exit(const char* s) -{ - fprintf(stderr, "%s error %d, %s\n", s, errno, strerror(errno)); - exit(EXIT_FAILURE); -} - -/** - Do ioctl and retry if error was EINTR ("A signal was caught during the ioctl() operation."). Parameters are the same as on ioctl. - - \param fd file descriptor - \param request request - \param argp argument - \returns result from ioctl -*/ -static int xioctl(int fd, int request, void* argp) -{ - int r; - - do r = v4l2_ioctl(fd, request, argp); - while (-1 == r && EINTR == errno); - - return r; -} - -/** - Write image to jpeg file. - - \param img image to write -*/ -int write_file (char * filename,unsigned char *image_buffer, int size) -{ - /* More stuff */ - - FILE * outfile; /* target file */ - - if ((outfile = fopen(filename, "w+")) == NULL) { - - fprintf(stderr, "can't open %s\n", filename); - - return -1; - - } - fwrite(image_buffer, size, 1, outfile); - - fclose(outfile); - return 0 ; -} - -int write_JPEG_file (char * filename,unsigned char *image_buffer, int image_width, int image_height, int quality ) - -{ - - struct jpeg_compress_struct cinfo; - - struct jpeg_error_mgr jerr; - - /* More stuff */ - - FILE * outfile; /* target file */ - - JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ - - int row_stride; /* physical row width in image buffer */ - - - - /* Step 1: allocate and initialize JPEG compression object */ - - cinfo.err = jpeg_std_error(&jerr); - - /* Now we can initialize the JPEG compression object. */ - - jpeg_create_compress(&cinfo); - - - - /* Step 2: specify data destination (eg, a file) */ - - /* Note: steps 2 and 3 can be done in either order. */ - - - - if ((outfile = fopen(filename, "w+")) == NULL) { - - fprintf(stderr, "can't open %s\n", filename); - - return -1; - - } - - jpeg_stdio_dest(&cinfo, outfile); - - - - /* Step 3: set parameters for compression */ - - cinfo.image_width = image_width; /* image width and height, in pixels */ - - cinfo.image_height = image_height; - - cinfo.input_components = 3; /* # of color components per pixel */ - - cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ - - - - jpeg_set_defaults(&cinfo); - - jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); - - - - /* Step 4: Start compressor */ - - - - jpeg_start_compress(&cinfo, TRUE); - - - - /* Step 5: while (scan lines remain to be written) */ - - row_stride = image_width * 3; /* JSAMPLEs per row in image_buffer */ - - - - while (cinfo.next_scanline < cinfo.image_height) { - - row_pointer[0] = & image_buffer[cinfo.next_scanline * row_stride]; - - (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); - - } - - - - /* Step 6: Finish compression */ - - - - jpeg_finish_compress(&cinfo); - - /* After finish_compress, we can close the output file. */ - - fclose(outfile); - - - - /* Step 7: release JPEG compression object */ - - - - /* This is an important step since it will release a good deal of memory. */ - - jpeg_destroy_compress(&cinfo); - - - - /* And we're done! */ - - return 0 ; - -} - -static void jpegWrite(unsigned char* img, char* jpegFilename) -{ - struct jpeg_compress_struct cinfo; - struct jpeg_error_mgr jerr; - - JSAMPROW row_pointer[1]; - FILE *outfile = fopen( jpegFilename, "wb" ); - - // try to open file for saving - if (!outfile) { - errno_exit("jpeg"); - } - - // create jpeg data - cinfo.err = jpeg_std_error( &jerr ); - jpeg_create_compress(&cinfo); - jpeg_stdio_dest(&cinfo, outfile); - - // set image parameters - cinfo.image_width = width; - cinfo.image_height = height; - cinfo.input_components = 3; - cinfo.in_color_space = JCS_YCbCr; - - // set jpeg compression parameters to default - jpeg_set_defaults(&cinfo); - // and then adjust quality setting - jpeg_set_quality(&cinfo, jpegQuality, TRUE); - - // start compress - jpeg_start_compress(&cinfo, TRUE); - - // feed data - while (cinfo.next_scanline < cinfo.image_height) { - row_pointer[0] = &img[cinfo.next_scanline * cinfo.image_width * cinfo.input_components]; - jpeg_write_scanlines(&cinfo, row_pointer, 1); - } - - // finish compression - jpeg_finish_compress(&cinfo); - - // destroy jpeg data - jpeg_destroy_compress(&cinfo); - - // close output file - fclose(outfile); -} - -/** - process image read -*/ -static void imageProcess(const void* p, struct timeval timestamp) -{ - //timestamp.tv_sec - //timestamp.tv_usec - unsigned char* src = (unsigned char*)p; - unsigned char* dst = malloc(width*height*3*sizeof(char)); - static int count = 0; - char filename[512]; - sprintf(filename, "raw-%d-nv21-%s", count, jpegFilename); - write_file(filename, src, imagesize); - count++; - if (test_fps) - return; - - // write jpeg - - switch (format) { - case V4L2_PIX_FMT_YUV420: - if (jpegFilename) { - // sprintf(filename, "%d-yuv420-%s", count, jpegFilename); - // YUV420toYUV444(width, height, src, dst); - // jpegWrite(dst, filename); - sprintf(filename, "raw-%d-yuv420-%s", count, jpegFilename); - write_file(filename, src, imagesize); - count++; - } - break; - case V4L2_PIX_FMT_YUYV: - case V4L2_PIX_FMT_YVYU: - if (jpegFilename) { - // sprintf(filename, "%d-yuv422-%s", count, jpegFilename); - // YUV422toYUV444(width, height, src, dst); - // jpegWrite(dst, filename); - sprintf(filename, "raw-%d-yuv422-%s", count, jpegFilename); - write_file(filename, src, imagesize); - count++; - } - if (pixformat == v4l2fmt_to_fbfmt(format)) - yuyv_resize(src, fbp, width, height); - else if (vinfo.grayscale) - convert_yuyv_to_nv12(src, fbp, width, height, 1); - else - convert_yuyv_to_rgb(src, fbp, width, height, 0); - break; - case V4L2_PIX_FMT_NV21: - if (jpegFilename) { - // sprintf(filename, "%d-nv21-%s", count, jpegFilename); - // YUV420NV21toYUV444(width, height, src, dst); - // jpegWrite(dst, filename); - sprintf(filename, "raw-%d-nv21-%s", count, jpegFilename); - write_file(filename, src, imagesize); - count++; - } - if (pixformat == v4l2fmt_to_fbfmt(format)) - convert_nv21_to_nv12(src, fbp, width, height, 0); - else if (vinfo.grayscale) - convert_nv21_to_nv12(src, fbp, width, height, 1); - else - convert_nv21_to_rgb(src, fbp, width, height, 1); - break; - case V4L2_PIX_FMT_NV12: - if (jpegFilename) { - // sprintf(filename, "%d-nv12-%s", count, jpegFilename); - // YUV420NV12toYUV444(width, height, src, dst); - // jpegWrite(dst, filename); - sprintf(filename, "raw-%d-nv12-%s", count, jpegFilename); - write_file(filename, src, imagesize); - count++; - } - if (pixformat == v4l2fmt_to_fbfmt(format)) - convert_nv21_to_nv12(src, fbp, width, height, 0); - else if (vinfo.grayscale) - convert_nv21_to_nv12(src, fbp, width, height, 0); - else - convert_nv21_to_rgb(src, fbp, width, height, 0); - break; - case V4L2_PIX_FMT_RGB24: - if (jpegFilename) { - // sprintf(filename, "%d-rgb-%s", count, jpegFilename); - // RGB565toRGB888(width, height, src, dst); - // write_JPEG_file(filename, src, width, height, jpegQuality); - sprintf(filename, "raw-%d-rgb-%s", count, jpegFilename); - write_file(filename, src, imagesize); - count++; - } - convert_rgb888_to_rgb(src, fbp, width, height, 0); - break; - case V4L2_PIX_FMT_RGB565: - if (jpegFilename) { - // sprintf(filename, "%d-rgb565-%s", count, jpegFilename); - // RGB565toRGB888(width, height, src, dst); - // write_JPEG_file(filename, dst, width, height, jpegQuality); - sprintf(filename, "raw-%d-rgb565-%s", count, jpegFilename); - write_file(filename, src, imagesize); - count++; - } - if (pixformat == v4l2fmt_to_fbfmt(format)) - convert_rgb565_to_rgb(src, fbp, width, height, 0); - else if (vinfo.grayscale) - convert_rgb565_to_nv12(src, fbp, width, height, 0); - else - convert_rgb565_to_rgb(src, fbp, width, height, 0); - break; - case V4L2_PIX_FMT_SRGGB12: - if (jpegFilename) - sprintf(filename, "raw-%d-RGGB12-%s", count, jpegFilename); - else - sprintf(filename, "raw-%d-RGGB12.raw", count); - write_file(filename, src, imagesize); - RAW12toRAW16(width, height, src, dst); - if (jpegFilename) - sprintf(filename, "raw-%d-RGGB16-%s", count, jpegFilename); - else - sprintf(filename, "raw-%d-RGGB16.raw", count); - write_file(filename, dst, width * height * 2); - count++; - break; - case V4L2_PIX_FMT_SGRBG12: - if (jpegFilename) - sprintf(filename, "raw-%d-GRBG12-%s", count, jpegFilename); - else - sprintf(filename, "raw-%d-GRBG12.raw", count); - write_file(filename, src, imagesize); - RAW12toRAW16(width, height, src, dst); - if (jpegFilename) - sprintf(filename, "raw-%d-GRBG16-%s", count, jpegFilename); - else - sprintf(filename, "raw-%d-GRBG16.raw", count); - write_file(filename, dst, width * height * 2); - count++; - break; - case V4L2_PIX_FMT_SGBRG12: - if (jpegFilename) - sprintf(filename, "raw-%d-GBRG12-%s", count, jpegFilename); - else - sprintf(filename, "raw-%d-GBRG12.raw", count); - write_file(filename, src, imagesize); - RAW12toRAW16(width, height, src, dst); - if (jpegFilename) - sprintf(filename, "raw-%d-GBRG16-%s", count, jpegFilename); - else - sprintf(filename, "raw-%d-GBRG16.raw", count); - write_file(filename, dst, width * height * 2); - count++; - break; - case V4L2_PIX_FMT_SBGGR12: - if (jpegFilename) - sprintf(filename, "raw-%d-BGGR12-%s", count, jpegFilename); - else - sprintf(filename, "raw-%d-BGGR12.raw", count); - write_file(filename, src, imagesize); - RAW12toRAW16(width, height, src, dst); - if (jpegFilename) - sprintf(filename, "raw-%d-BGGR16-%s", count, jpegFilename); - else - sprintf(filename, "raw-%d-BGGR16.raw", count); - write_file(filename, dst, width * height * 2); - count++; - break; - default: - printf("unknow format\n"); - break; - } - - // free temporary image - free(dst); -} - -/** - read single frame -*/ -static int frameRead(void) -{ - struct v4l2_buffer buf; -#ifdef IO_USERPTR - unsigned int i; -#endif - - switch (io) { -#ifdef IO_READ - case IO_METHOD_READ: - if (-1 == v4l2_read(fd, buffers[0].start, buffers[0].length)) { - switch (errno) { - case EAGAIN: - return 0; - - case EIO: - // Could ignore EIO, see spec. - // fall through - - default: - errno_exit("read"); - } - } - - struct timespec ts; - struct timeval timestamp; - clock_gettime(CLOCK_MONOTONIC,&ts); - timestamp.tv_sec = ts.tv_sec; - timestamp.tv_usec = ts.tv_nsec/1000; - - imageProcess(buffers[0].start,timestamp); - break; -#endif - -#ifdef IO_MMAP - case IO_METHOD_MMAP: - CLEAR(buf); - - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - - if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { - switch (errno) { - case EAGAIN: - return 0; - - case EIO: - // Could ignore EIO, see spec - // fall through - - default: - errno_exit("VIDIOC_DQBUF"); - } - } - - assert(buf.index < n_buffers); - - imageProcess(buffers[buf.index].start, buf.timestamp); - if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) - errno_exit("VIDIOC_QBUF"); - - break; -#endif - -#ifdef IO_USERPTR - case IO_METHOD_USERPTR: - CLEAR (buf); - - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_USERPTR; - - if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { - switch (errno) { - case EAGAIN: - return 0; - - case EIO: - // Could ignore EIO, see spec. - // fall through - - default: - errno_exit("VIDIOC_DQBUF"); - } - } - - for (i = 0; i < n_buffers; ++i) - if (buf.m.userptr == (unsigned long)buffers[i].start && buf.length == buffers[i].length) - break; - - assert (i < n_buffers); - - imageProcess((void *)buf.m.userptr, buf.timestamp); - - if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) - errno_exit("VIDIOC_QBUF"); - break; -#endif - } - - static unsigned int start_timems; - unsigned int time_ms, tmp_ms; - struct timespec ts; - clock_gettime(CLOCK_MONOTONIC, &ts); - tmp_ms = ts.tv_sec * 1000 + ts.tv_nsec/1000000; - time_ms = tmp_ms - start_timems; - start_timems = tmp_ms; - - if (!(++fps_count%5)) - { - fps_count = 0; - printf("%s format = 0x%x\n", __func__, format); - printf("fps: %d\n", 1000/time_ms); - } - - return 1; -} - -/** - mainloop: read frames and process them -*/ -static void mainLoop(void) -{ - int count, i; - unsigned int numberOfTimeouts; - - numberOfTimeouts = 0; - count = 3; - - while (count-- > 0) { - for (i = 0; i < 1; i++) { - fd_set fds; - struct timeval tv; - int r; - - FD_ZERO(&fds); - FD_SET(fd, &fds); - - /* Timeout. */ - tv.tv_sec = 1; - tv.tv_usec = 0; - - r = select(fd + 1, &fds, NULL, NULL, &tv); - - if (-1 == r) { - if (EINTR == errno) - continue; - - errno_exit("select"); - } - - if (0 == r) { - if (numberOfTimeouts <= 0) { - // count++; - } else { - fprintf(stderr, "select timeout\n"); - exit(EXIT_FAILURE); - } - } - if(continuous == 1) { - count = 3; - } - - if (frameRead()) - break; - - /* EAGAIN - continue select loop. */ - } - } -} - -/** - stop capturing -*/ -static void captureStop(void) -{ - enum v4l2_buf_type type; - - switch (io) { -#ifdef IO_READ - case IO_METHOD_READ: - /* Nothing to do. */ - break; -#endif - -#ifdef IO_MMAP - case IO_METHOD_MMAP: -#endif -#ifdef IO_USERPTR - case IO_METHOD_USERPTR: -#endif -#if defined(IO_MMAP) || defined(IO_USERPTR) - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) - errno_exit("VIDIOC_STREAMOFF"); - - break; -#endif - } -} - -/** - start capturing -*/ -static void captureStart(void) -{ - unsigned int i; - enum v4l2_buf_type type; - - switch (io) { -#ifdef IO_READ - case IO_METHOD_READ: - /* Nothing to do. */ - break; -#endif - -#ifdef IO_MMAP - case IO_METHOD_MMAP: - for (i = 0; i < n_buffers; ++i) { - struct v4l2_buffer buf; - - CLEAR(buf); - - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = i; - - if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) - errno_exit("VIDIOC_QBUF"); - } - - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) - errno_exit("VIDIOC_STREAMON"); - - break; -#endif - -#ifdef IO_USERPTR - case IO_METHOD_USERPTR: - for (i = 0; i < n_buffers; ++i) { - struct v4l2_buffer buf; - - CLEAR (buf); - - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_USERPTR; - buf.index = i; - buf.m.userptr = (unsigned long) buffers[i].start; - buf.length = buffers[i].length; - - if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) - errno_exit("VIDIOC_QBUF"); - } - - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) - errno_exit("VIDIOC_STREAMON"); - - break; -#endif - } -} - -static void deviceUninit(void) -{ - unsigned int i; - - switch (io) { -#ifdef IO_READ - case IO_METHOD_READ: - free(buffers[0].start); - break; -#endif - -#ifdef IO_MMAP - case IO_METHOD_MMAP: - for (i = 0; i < n_buffers; ++i) - if (-1 == v4l2_munmap(buffers[i].start, buffers[i].length)) - errno_exit("munmap"); - break; -#endif - -#ifdef IO_USERPTR - case IO_METHOD_USERPTR: - for (i = 0; i < n_buffers; ++i) - free(buffers[i].start); - break; -#endif - } - - free(buffers); - - if (!test_fps) { - if (-1 == munmap(fbp, screensize)) { - printf(" Error: framebuffer device munmap() failed.\n"); - exit (EXIT_FAILURE) ; - } - } -} - -#ifdef IO_READ -static void readInit(unsigned int buffer_size) -{ - buffers = calloc(1, sizeof(*buffers)); - - if (!buffers) { - fprintf(stderr, "Out of memory\n"); - exit(EXIT_FAILURE); - } - - buffers[0].length = buffer_size; - buffers[0].start = malloc(buffer_size); - - if (!buffers[0].start) { - fprintf (stderr, "Out of memory\n"); - exit(EXIT_FAILURE); - } -} -#endif - -#ifdef IO_MMAP -static void mmapInit(void) -{ - struct v4l2_requestbuffers req; - - CLEAR(req); - - req.count = VIDIOC_REQBUFS_COUNT; - req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - req.memory = V4L2_MEMORY_MMAP; - - if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { - if (EINVAL == errno) { - fprintf(stderr, "%s does not support memory mapping\n", deviceName); - exit(EXIT_FAILURE); - } else { - errno_exit("VIDIOC_REQBUFS"); - } - } - - if (req.count < 2) { - fprintf(stderr, "Insufficient buffer memory on %s\n", deviceName); - exit(EXIT_FAILURE); - } - - buffers = calloc(req.count, sizeof(*buffers)); - - if (!buffers) { - fprintf(stderr, "Out of memory\n"); - exit(EXIT_FAILURE); - } - - for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { - struct v4l2_buffer buf; - - CLEAR(buf); - - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = n_buffers; - - if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) - errno_exit("VIDIOC_QUERYBUF"); - - buffers[n_buffers].length = buf.length; - buffers[n_buffers].start = v4l2_mmap(NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, fd, buf.m.offset); - - if (MAP_FAILED == buffers[n_buffers].start) - errno_exit("mmap"); - imagesize = buf.length; - } -} -#endif - -#ifdef IO_USERPTR -static void userptrInit(unsigned int buffer_size) -{ - struct v4l2_requestbuffers req; - unsigned int page_size; - - page_size = getpagesize(); - buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1); - - CLEAR(req); - - req.count = VIDIOC_REQBUFS_COUNT; - req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - req.memory = V4L2_MEMORY_USERPTR; - - if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { - if (EINVAL == errno) { - fprintf(stderr, "%s does not support user pointer i/o\n", deviceName); - exit(EXIT_FAILURE); - } else { - errno_exit("VIDIOC_REQBUFS"); - } - } - - buffers = calloc(4, sizeof(*buffers)); - - if (!buffers) { - fprintf(stderr, "Out of memory\n"); - exit(EXIT_FAILURE); - } - - for (n_buffers = 0; n_buffers < 4; ++n_buffers) { - buffers[n_buffers].length = buffer_size; - buffers[n_buffers].start = memalign(/* boundary */ page_size, buffer_size); - - if (!buffers[n_buffers].start) { - fprintf(stderr, "Out of memory\n"); - exit(EXIT_FAILURE); - } - } -} -#endif - -/** - initialize device -*/ -static void deviceInit(void) -{ - struct v4l2_capability cap; - struct v4l2_cropcap cropcap; - struct v4l2_crop crop; - struct v4l2_format fmt; - struct v4l2_streamparm frameint; - unsigned int min; - - if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) { - if (EINVAL == errno) { - fprintf(stderr, "%s is no V4L2 device\n",deviceName); - exit(EXIT_FAILURE); - } else { - errno_exit("VIDIOC_QUERYCAP"); - } - } - - if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { - fprintf(stderr, "%s is no video capture device\n",deviceName); - exit(EXIT_FAILURE); - } - - switch (io) { -#ifdef IO_READ - case IO_METHOD_READ: - if (!(cap.capabilities & V4L2_CAP_READWRITE)) { - fprintf(stderr, "%s does not support read i/o\n",deviceName); - exit(EXIT_FAILURE); - } - break; -#endif - -#ifdef IO_MMAP - case IO_METHOD_MMAP: -#endif -#ifdef IO_USERPTR - case IO_METHOD_USERPTR: -#endif -#if defined(IO_MMAP) || defined(IO_USERPTR) - if (!(cap.capabilities & V4L2_CAP_STREAMING)) { - fprintf(stderr, "%s does not support streaming i/o\n",deviceName); - exit(EXIT_FAILURE); - } - break; -#endif - } - - /* Select video input, video standard and tune here. */ - CLEAR(cropcap); - - cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) { - crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - crop.c = cropcap.defrect; /* reset to default */ - - if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) { - switch (errno) { - case EINVAL: - /* Cropping not supported. */ - break; - default: - /* Errors ignored. */ - break; - } - } - } else { - /* Errors ignored. */ - } - - CLEAR(fmt); - - // v4l2_format - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.width = width; - fmt.fmt.pix.height = height; - fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; - fmt.fmt.pix.pixelformat = format; - - /* If the user has set the fps to -1, don't try to set the frame interval */ - if (fps != -1) - { - CLEAR(frameint); - - /* Attempt to set the frame interval. */ - frameint.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - frameint.parm.capture.timeperframe.numerator = 1; - frameint.parm.capture.timeperframe.denominator = fps; - if (-1 == xioctl(fd, VIDIOC_S_PARM, &frameint)) - fprintf(stderr,"Unable to set frame interval.\n"); - fprintf(stderr,"set frame interval = %d.\n", frameint.parm.capture.timeperframe.denominator); - } - - if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) - errno_exit("VIDIOC_S_FMT"); - - if (crop_flag) { - struct v4l2_selection sel_crop = { - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_SEL_TGT_CROP, - 0, - { left, up, right, down } - }; - struct v4l2_selection get_crop = { - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_SEL_TGT_CROP, - }; - - fprintf(stderr, "sel_crop.left = %d, %d, %d, %d\n", - sel_crop.r.left, sel_crop.r.top, sel_crop.r.width, sel_crop.r.height); - if (-1 == xioctl(fd, VIDIOC_S_SELECTION, &sel_crop)) { - fprintf(stderr,"S_SELECTION Failed.\n"); - } - - fprintf(stderr, "sel_crop.left = %d, %d, %d, %d\n", - sel_crop.r.left, sel_crop.r.top, sel_crop.r.width, sel_crop.r.height); - if (-1 == xioctl(fd, VIDIOC_G_SELECTION, &get_crop)) { - fprintf(stderr,"G_SELECTION Failed.\n"); - } - - fprintf(stderr, "get_crop.left = %d, %d, %d, %d\n", - get_crop.r.left, get_crop.r.top, get_crop.r.width, get_crop.r.height); - if (memcmp(&sel_crop, &get_crop, sizeof(sel_crop))) { - fprintf(stderr,"set/get selection diff.\n"); - } - - memset(&fmt, 0, sizeof(struct v4l2_format)); - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - fmt.fmt.pix.field = V4L2_FIELD_ANY; - - if (-1 == ioctl(fd, VIDIOC_G_FMT, &fmt)) - errno_exit("VIDIOC_G_FMT"); - } - - //if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_YUV420) { - //if (fmt.fmt.pix.pixelformat != V4L2_PIX_FMT_RGB565) { - if (fmt.fmt.pix.pixelformat != format) { - fprintf(stderr,"Libv4l didn't accept format. Can't proceed.\n"); - exit(EXIT_FAILURE); - } - - /* Note VIDIOC_S_FMT may change width and height. */ - if (width != fmt.fmt.pix.width) { - width = fmt.fmt.pix.width; - fprintf(stderr,"Image width set to %i by device %s.\n", width, deviceName); - } - - if (height != fmt.fmt.pix.height) { - height = fmt.fmt.pix.height; - fprintf(stderr,"Image height set to %i by device %s.\n", height, deviceName); - } - - /* Buggy driver paranoia. */ - min = fmt.fmt.pix.width * 2; - if (fmt.fmt.pix.bytesperline < min) - fmt.fmt.pix.bytesperline = min; - min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; - if (fmt.fmt.pix.sizeimage < min) - fmt.fmt.pix.sizeimage = min; - - switch (io) { -#ifdef IO_READ - case IO_METHOD_READ: - readInit(fmt.fmt.pix.sizeimage); - break; -#endif - -#ifdef IO_MMAP - case IO_METHOD_MMAP: - mmapInit(); - break; -#endif - -#ifdef IO_USERPTR - case IO_METHOD_USERPTR: - userptrInit(fmt.fmt.pix.sizeimage); - break; -#endif - } - - if (!test_fps) { - struct pp_mode pp_info[3]; - - pixformat = v4l2fmt_to_fbfmt(format); - if (-1 == ioctl(stfbcdevfd, FBIOPAN_GET_PP_MODE, &pp_info[0])) { - printf("Error reading variable information.\n"); - exit (EXIT_FAILURE); - } - printf("get pp format :%d, %d\n", pp_info[1].src.format, __LINE__); - - pp_info[1].src.format = pixformat; - - if (-1 == ioctl(stfbcdevfd, FBIOPAN_SET_PP_MODE, &pp_info[0])) { - printf("Error reading variable information.\n"); - exit (EXIT_FAILURE); - } - - if (-1 == ioctl(stfbcdevfd, FBIOPAN_GET_PP_MODE, &pp_info[0])) { - printf("Error reading variable information.\n"); - exit (EXIT_FAILURE); - } - printf("get pp format :%d, %d\n", pp_info[1].src.format, __LINE__); - pixformat = pp_info[1].src.format; - - // Get fixed screen information - if (-1 == xioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) { - printf("Error reading fixed information.\n"); - exit (EXIT_FAILURE); - } - - // Get variable screen information - if (-1 == xioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) { - printf("Error reading variable information.\n"); - exit (EXIT_FAILURE); - } - - printf("vinfo.xres = %d, vinfo.yres = %d, grayscale = %d\n", vinfo.xres, vinfo.yres, vinfo.grayscale); - printf("vinfo.xoffset = %d, vinfo.yoffset = %d\n", vinfo.xoffset, vinfo.yoffset); - printf("vinfo.bits_per_pixel = %d, finfo.line_length = %d\n", vinfo.bits_per_pixel, finfo.line_length); - - // if (ioctl(fbfd, FBIOPUT_VSCREENINFO, &vinfo) < 0) { - // printf("FBIOPUT_VSCREENINFO.\n"); - // exit (EXIT_FAILURE); - // } - - // printf("vinfo.bits_per_pixel = %d, finfo.line_length = %d\n", vinfo.bits_per_pixel, finfo.line_length); - screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; - // screensize = vinfo.xres * vinfo.yres * 32 / 8; - //mmap framebuffer - fbp = (char *)mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); - if ((int)fbp == -1) { - printf("Error: failed to map framebuffer device to memory.\n"); - exit (EXIT_FAILURE) ; - } - memset(fbp, 0x00, screensize); - } -} - -/** - close device -*/ -static void deviceClose(void) -{ - if (-1 == v4l2_close(fd)) - errno_exit("close"); - - fd = -1; - if (!test_fps) { - close(fbfd); - close(stfbcdevfd); - } -} - -/** - open device -*/ -static void deviceOpen(void) -{ - struct stat st; - struct v4l2_capability cap; - - // stat file - if (-1 == stat(deviceName, &st)) { - fprintf(stderr, "Cannot identify '%s': %d, %s\n", deviceName, errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - // check if its device - if (!S_ISCHR(st.st_mode)) { - fprintf(stderr, "%s is no device\n", deviceName); - exit(EXIT_FAILURE); - } - - // open device - fd = v4l2_open(deviceName, O_RDWR /* required */ | O_NONBLOCK, 0); - // fd = v4l2_open(deviceName, O_RDWR, 0); - - // check if opening was successfull - if (-1 == fd) { - fprintf(stderr, "Cannot open '%s': %d, %s\n", deviceName, errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - //open framebuffer - if (!test_fps) { - fbfd = open("/dev/fb0", O_RDWR); - if (fbfd == -1) { - printf("Error: cannot open framebuffer device.\n"); - exit (EXIT_FAILURE); - } - stfbcdevfd = open("/dev/stfbcdev", O_RDWR); - if (stfbcdevfd == -1) { - printf("Error: cannot open stfbcdev device.\n"); - exit (EXIT_FAILURE); - } - } -} - -void loadfw_start(char *filename) -{ - struct stfisp_fw_info fw_info = {0}; - - // open device - fd = open(deviceName, O_RDWR /* required */ | O_NONBLOCK, 0); - - // check if opening was successfull - if (-1 == fd) { - fprintf(stderr, "Cannot open '%s': %d, %s\n", deviceName, errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - if (filename && (strlen(filename) < FILENAME_MAX_LEN)) - memcpy(fw_info.filename, filename, strlen(filename) + 1); - - fprintf(stderr, "VIDIOC_STFISP_LOAD_FW = 0x%lx, filename = %s, fw_info = 0x%x, size = %d\n", - VIDIOC_STFISP_LOAD_FW, fw_info.filename, fw_info, sizeof(struct stfisp_fw_info)); - if (-1 == ioctl(fd, VIDIOC_STFISP_LOAD_FW, &fw_info)) { - if (EINVAL == errno) { - fprintf(stderr, "%s is no V4L2 device\n",deviceName); - exit(EXIT_FAILURE); - } else { - errno_exit("VIDIOC_STFISP_LOAD_FW"); - } - } -} - -/** - print usage information -*/ -static void usage(FILE* fp, int argc, char** argv) -{ - fprintf(fp, - "Usage: %s [options]\n\n" - "Options:\n" - "-d | --device name Video device name [/dev/video0]\n" - "-h | --help Print this message\n" - "-o | --output Set JPEG output filename\n" - "-q | --quality Set JPEG quality (0-100)\n" - "-m | --mmap Use memory mapped buffers\n" - "-r | --read Use read() calls\n" - "-u | --userptr Use application allocated buffers\n" - "-W | --width Set image width\n" - "-H | --height Set image height\n" - "-X | --left Set image x start\n" - "-Y | --up Set image y start\n" - "-R | --right Set image x width\n" - "-D | --down Set image y height\n" - "-I | --interval Set frame interval (fps) (-1 to skip)\n" - "-c | --continuous Do continous capture, stop with SIGINT.\n" - "-v | --version Print version\n" - "-f | --format image format\n" - " 0:V4L2_PIX_FMT_RGB565\n" - " 1:V4L2_PIX_FMT_RGB24\n" - " 2:V4L2_PIX_FMT_YUV420\n" - " 3:V4L2_PIX_FMT_YUYV\n" - " 4:V4L2_PIX_FMT_NV21\n" - " 5:V4L2_PIX_FMT_NV12\n" - " 6:V4L2_PIX_FMT_YVYU\n" - " 7:V4L2_PIX_FMT_SRGGB12\n" - " 8:V4L2_PIX_FMT_SGRBG12\n" - " 9:V4L2_PIX_FMT_SGBRG12\n" - " 10:V4L2_PIX_FMT_SBGGR12\n" - " default:V4L2_PIX_FMT_RGB565\n" - "-t | --testfps test fps\n" - "-l | --loadfw load stfisp fw image\n" - "", - argv[0]); - } - -static const char short_options [] = "d:ho:q:mruW:H:I:vcf:tX:Y:R:D:l:"; - -static const struct option -long_options [] = { - { "device", required_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "output", required_argument, NULL, 'o' }, - { "quality", required_argument, NULL, 'q' }, - { "mmap", no_argument, NULL, 'm' }, - { "read", no_argument, NULL, 'r' }, - { "userptr", no_argument, NULL, 'u' }, - { "width", required_argument, NULL, 'W' }, - { "height", required_argument, NULL, 'H' }, - { "left", required_argument, NULL, 'X' }, - { "up", required_argument, NULL, 'Y' }, - { "right", required_argument, NULL, 'R' }, - { "down", required_argument, NULL, 'D' }, - { "interval", required_argument, NULL, 'I' }, - { "version", no_argument, NULL, 'v' }, - { "continuous", no_argument, NULL, 'c' }, - { "format", required_argument, NULL, 'f' }, - { "testfps", no_argument, NULL, 't' }, - { "loadfw", required_argument, NULL, 'l' }, - { 0, 0, 0, 0 } -}; - -int main(int argc, char **argv) -{ - for (;;) { - int index, c = 0; - - c = getopt_long(argc, argv, short_options, long_options, &index); - - if (-1 == c) - break; - - switch (c) { - case 0: /* getopt_long() flag */ - break; - - case 'd': - deviceName = optarg; - break; - - case 'h': - // print help - usage(stdout, argc, argv); - exit(EXIT_SUCCESS); - - case 'o': - // set jpeg filename - jpegFilename = optarg; - break; - - case 'q': - // set jpeg quality - jpegQuality = atoi(optarg); - break; - - case 'm': -#ifdef IO_MMAP - io = IO_METHOD_MMAP; -#else - fprintf(stderr, "You didn't compile for mmap support.\n"); - exit(EXIT_FAILURE); -#endif - break; - - case 'r': -#ifdef IO_READ - io = IO_METHOD_READ; -#else - fprintf(stderr, "You didn't compile for read support.\n"); - exit(EXIT_FAILURE); -#endif - break; - - case 'u': -#ifdef IO_USERPTR - io = IO_METHOD_USERPTR; -#else - fprintf(stderr, "You didn't compile for userptr support.\n"); - exit(EXIT_FAILURE); -#endif - break; - - case 'W': - // set width - width = atoi(optarg); - break; - - case 'H': - // set height - height = atoi(optarg); - break; - - case 'X': - // set x start - left = atoi(optarg); - crop_flag = 1; - break; - - case 'Y': - // set y start - up = atoi(optarg); - crop_flag = 1; - break; - - case 'R': - // set x width - right = atoi(optarg); - crop_flag = 1; - break; - - case 'D': - // set y height - down = atoi(optarg); - crop_flag = 1; - break; - - case 'I': - // set fps - fps = atoi(optarg); - break; - - case 'c': - // set flag for continuous capture, interuptible by sigint - continuous = 1; - InstallSIGINTHandler(); - break; - - - case 'v': - printf("Version: %s\n", VERSION); - exit(EXIT_SUCCESS); - break; - - case 'f': - printf("format: %s\n", optarg); - format = atoi(optarg); - switch (format) { - case 0: - format = V4L2_PIX_FMT_RGB565; - break; - case 1: - format = V4L2_PIX_FMT_RGB24; - break; - case 2: - format = V4L2_PIX_FMT_YUV420; - break; - case 3: - format = V4L2_PIX_FMT_YUYV; - break; - case 4: - format = V4L2_PIX_FMT_NV21; - break; - case 5: - format = V4L2_PIX_FMT_NV12; - break; - case 6: - format = V4L2_PIX_FMT_YVYU; - break; - case 7: - format = V4L2_PIX_FMT_SRGGB12; - break; - case 8: - format = V4L2_PIX_FMT_SGRBG12; - break; - case 9: - format = V4L2_PIX_FMT_SGBRG12; - break; - case 10: - format = V4L2_PIX_FMT_SBGGR12; - break; - default: - format = V4L2_PIX_FMT_RGB565; - break; - } - break; - - case 't': - test_fps = 1; - break; - case 'l': - loadfw_start(optarg); - exit(EXIT_SUCCESS); - break; - default: - usage(stderr, argc, argv); - exit(EXIT_FAILURE); - } - } - - // open and initialize device - deviceOpen(); - deviceInit(); - - test_float_1(); - // start capturing - captureStart(); - - // process frames - mainLoop(); - - // stop capturing - captureStop(); - - // close device - deviceUninit(); - deviceClose(); - - exit(EXIT_SUCCESS); - - return 0; -} diff --git a/package/v4l2_test/v4l2_test.mk b/package/v4l2_test/v4l2_test.mk deleted file mode 100755 index 1e551a73..00000000 --- a/package/v4l2_test/v4l2_test.mk +++ /dev/null @@ -1,29 +0,0 @@ -################################################################################ -# -# v4l2test -# -################################################################################ - -V4L2_TEST_LICENSE = GPL-2.0+ - -define V4L2_TEST_BUILD_CMDS - cp package/v4l2_test/v4l2_test.c $(@D)/ - cp package/v4l2_test/yuv.c $(@D)/ - cp package/v4l2_test/yuv.h $(@D)/ - cp package/v4l2_test/convert.c $(@D)/ - cp package/v4l2_test/convert.h $(@D)/ - cp package/v4l2_test/config.h $(@D)/ - cp package/v4l2_test/string.c $(@D)/ - cp package/v4l2_test/pipeline_setting.sh $(@D)/ - (cd $(@D); $(TARGET_CC) -Wall -O2 v4l2_test.c yuv.c convert.c string.c -l v4l2 -l jpeg -o v4l2test) - #(cd $(@D); $(TARGET_CC) -Wall -O2 v4l2_test.c -o v4l2test) -endef - -define V4L2_TEST_INSTALL_TARGET_CMDS - install -m 0755 -D $(@D)/v4l2test $(TARGET_DIR)/usr/bin/v4l2test - install -m 0755 -D $(@D)/pipeline_setting.sh $(TARGET_DIR)/usr/bin/pipeline_setting.sh -endef - -V4L2_TEST_DEPENDENCIES = jpeg libv4l -$(eval $(generic-package)) -