123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547 |
- /**************************************************************************//**
- *
- * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2022-8-16 Wayne First version
- *
- ******************************************************************************/
- #include <rtthread.h>
- #if defined(BSP_USING_CCAP)
- #include "drv_ccap.h"
- #include <dfs_posix.h>
- #define DBG_ENABLE
- #define DBG_LEVEL DBG_LOG
- #define DBG_SECTION_NAME "ccap.demo"
- #define DBG_COLOR
- #include <rtdbg.h>
- #define THREAD_PRIORITY 5
- #define THREAD_STACK_SIZE 4096
- #define THREAD_TIMESLICE 5
- #define DEF_CROP_PACKET_RECT
- #define DEF_ENABLE_PLANAR_PIPE 0
- #define DEF_DURATION 10
- #if defined(BSP_USING_CCAP0) && defined(BSP_USING_CCAP1)
- #define DEF_GRID_VIEW 1
- #elif defined(BSP_USING_CCAP0) || defined(BSP_USING_CCAP1)
- #define DEF_GRID_VIEW 0
- #endif
- typedef struct
- {
- char *thread_name;
- char *devname_ccap;
- char *devname_sensor;
- char *devname_lcd;
- } ccap_grabber_param;
- typedef ccap_grabber_param *ccap_grabber_param_t;
- typedef struct
- {
- ccap_config sCcapConfig;
- struct rt_device_graphic_info sLcdInfo;
- uint32_t u32CurFBPointer;
- uint32_t u32FrameEnd;
- rt_sem_t semFrameEnd;
- } ccap_grabber_context;
- typedef ccap_grabber_context *ccap_grabber_context_t;
- static void nu_ccap_event_hook(void *pvData, uint32_t u32EvtMask)
- {
- ccap_grabber_context_t psGrabberContext = (ccap_grabber_context_t)pvData;
- if (u32EvtMask & NU_CCAP_FRAME_END)
- {
- rt_sem_release(psGrabberContext->semFrameEnd);
- }
- if (u32EvtMask & NU_CCAP_ADDRESS_MATCH)
- {
- LOG_I("Address matched");
- }
- if (u32EvtMask & NU_CCAP_MEMORY_ERROR)
- {
- LOG_E("Access memory error");
- }
- }
- static rt_device_t ccap_sensor_init(ccap_grabber_context_t psGrabberContext, ccap_grabber_param_t psGrabberParam)
- {
- rt_err_t ret;
- ccap_view_info_t psViewInfo;
- sensor_mode_info *psSensorModeInfo;
- rt_device_t psDevSensor = RT_NULL;
- rt_device_t psDevCcap = RT_NULL;
- struct rt_device_graphic_info *psLcdInfo = &psGrabberContext->sLcdInfo;
- ccap_config_t psCcapConfig = &psGrabberContext->sCcapConfig;
- psDevCcap = rt_device_find(psGrabberParam->devname_ccap);
- if (psDevCcap == RT_NULL)
- {
- LOG_E("Can't find %s", psGrabberParam->devname_ccap);
- goto exit_ccap_sensor_init;
- }
- psDevSensor = rt_device_find(psGrabberParam->devname_sensor);
- if (psDevSensor == RT_NULL)
- {
- LOG_E("Can't find %s", psGrabberParam->devname_sensor);
- goto exit_ccap_sensor_init;
- }
- /* Packet pipe for preview */
- if (DEF_GRID_VIEW)
- {
- psCcapConfig->sPipeInfo_Packet.u32Width = psLcdInfo->width / 2;
- psCcapConfig->sPipeInfo_Packet.u32Height = psLcdInfo->height / 2;
- psCcapConfig->sPipeInfo_Packet.u32PixFmt = (psLcdInfo->pixel_format == RTGRAPHIC_PIXEL_FORMAT_RGB565) ? CCAP_PAR_OUTFMT_RGB565 : 0;
- psCcapConfig->u32Stride_Packet = psLcdInfo->width;
- if (!rt_strcmp(psGrabberParam->devname_ccap, "ccap1"))
- psCcapConfig->sPipeInfo_Packet.pu8FarmAddr = psLcdInfo->framebuffer + (psCcapConfig->sPipeInfo_Packet.u32Width * 2);
- else
- psCcapConfig->sPipeInfo_Packet.pu8FarmAddr = psLcdInfo->framebuffer;
- }
- else
- {
- psCcapConfig->sPipeInfo_Packet.pu8FarmAddr = psLcdInfo->framebuffer;
- psCcapConfig->sPipeInfo_Packet.u32Height = psLcdInfo->height;
- psCcapConfig->sPipeInfo_Packet.u32Width = psLcdInfo->width;
- psCcapConfig->sPipeInfo_Packet.u32PixFmt = (psLcdInfo->pixel_format == RTGRAPHIC_PIXEL_FORMAT_RGB565) ? CCAP_PAR_OUTFMT_RGB565 : 0;
- psCcapConfig->u32Stride_Packet = psLcdInfo->width;
- }
- /* Planar pipe for encoding */
- #if DEF_ENABLE_PLANAR_PIPE
- psCcapConfig->sPipeInfo_Planar.u32Width = psLcdInfo->width / 2;
- psCcapConfig->sPipeInfo_Planar.u32Height = psLcdInfo->height / 2;
- psCcapConfig->sPipeInfo_Planar.pu8FarmAddr = rt_malloc_align(psCcapConfig->sPipeInfo_Planar.u32Height * psCcapConfig->sPipeInfo_Planar.u32Width * 2, 32);
- psCcapConfig->sPipeInfo_Planar.u32PixFmt = CCAP_PAR_PLNFMT_YUV420; //CCAP_PAR_PLNFMT_YUV422;
- psCcapConfig->u32Stride_Planar = psCcapConfig->sPipeInfo_Planar.u32Width;
- if (psCcapConfig->sPipeInfo_Planar.pu8FarmAddr == RT_NULL)
- {
- psCcapConfig->sPipeInfo_Planar.u32Height = 0;
- psCcapConfig->sPipeInfo_Planar.u32Width = 0;
- psCcapConfig->sPipeInfo_Planar.u32PixFmt = 0;
- psCcapConfig->u32Stride_Planar = 0;
- }
- LOG_I("Planar.FarmAddr@0x%08X", psCcapConfig->sPipeInfo_Planar.pu8FarmAddr);
- LOG_I("Planar.FarmWidth: %d", psCcapConfig->sPipeInfo_Planar.u32Width);
- LOG_I("Planar.FarmHeight: %d", psCcapConfig->sPipeInfo_Planar.u32Height);
- #endif
- /* open CCAP */
- ret = rt_device_open(psDevCcap, 0);
- if (ret != RT_EOK)
- {
- LOG_E("Can't open %s", psGrabberParam->devname_ccap);
- goto exit_ccap_sensor_init;
- }
- /* Find suit mode for packet pipe */
- if (psCcapConfig->sPipeInfo_Packet.pu8FarmAddr != RT_NULL)
- {
- /* Check view window of packet pipe */
- psViewInfo = &psCcapConfig->sPipeInfo_Packet;
- if ((rt_device_control(psDevSensor, CCAP_SENSOR_CMD_GET_SUIT_MODE, (void *)&psViewInfo) != RT_EOK)
- || (psViewInfo == RT_NULL))
- {
- LOG_E("Can't get suit mode for packet.");
- goto fail_ccap_init;
- }
- }
- /* Find suit mode for planner pipe */
- if (psCcapConfig->sPipeInfo_Planar.pu8FarmAddr != RT_NULL)
- {
- int recheck = 1;
- if (psViewInfo != RT_NULL)
- {
- if ((psCcapConfig->sPipeInfo_Planar.u32Width <= psViewInfo->u32Width) ||
- (psCcapConfig->sPipeInfo_Planar.u32Height <= psViewInfo->u32Height))
- recheck = 0;
- }
- if (recheck)
- {
- /* Check view window of planner pipe */
- psViewInfo = &psCcapConfig->sPipeInfo_Planar;
- /* Find suit mode */
- if ((rt_device_control(psDevSensor, CCAP_SENSOR_CMD_GET_SUIT_MODE, (void *)&psViewInfo) != RT_EOK)
- || (psViewInfo == RT_NULL))
- {
- LOG_E("Can't get suit mode for planner.");
- goto exit_ccap_sensor_init;
- }
- }
- }
- #if defined(DEF_CROP_PACKET_RECT)
- /* Set cropping rectangle */
- if (psViewInfo->u32Width >= psCcapConfig->sPipeInfo_Packet.u32Width)
- {
- /* sensor.width >= preview.width */
- psCcapConfig->sRectCropping.x = (psViewInfo->u32Width - psCcapConfig->sPipeInfo_Packet.u32Width) / 2;
- psCcapConfig->sRectCropping.width = psCcapConfig->sPipeInfo_Packet.u32Width;
- }
- else
- {
- /* sensor.width < preview.width */
- psCcapConfig->sRectCropping.x = 0;
- psCcapConfig->sRectCropping.width = psViewInfo->u32Width;
- }
- if (psViewInfo->u32Height >= psCcapConfig->sPipeInfo_Packet.u32Height)
- {
- /* sensor.height >= preview.height */
- psCcapConfig->sRectCropping.y = (psViewInfo->u32Height - psCcapConfig->sPipeInfo_Packet.u32Height) / 2;
- psCcapConfig->sRectCropping.height = psCcapConfig->sPipeInfo_Packet.u32Height;
- }
- else
- {
- /* sensor.height < preview.height */
- psCcapConfig->sRectCropping.y = 0;
- psCcapConfig->sRectCropping.height = psViewInfo->u32Height;
- }
- #else
- /* Set cropping rectangle */
- psCcapConfig->sRectCropping.x = 0;
- psCcapConfig->sRectCropping.y = 0;
- psCcapConfig->sRectCropping.width = psViewInfo->u32Width;
- psCcapConfig->sRectCropping.height = psViewInfo->u32Height;
- #endif
- /* ISR Hook */
- psCcapConfig->pfnEvHndler = nu_ccap_event_hook;
- psCcapConfig->pvData = (void *)psGrabberContext;
- /* Get Suitable mode. */
- psSensorModeInfo = (sensor_mode_info *)psViewInfo;
- /* Feed CCAP configuration */
- ret = rt_device_control(psDevCcap, CCAP_CMD_CONFIG, (void *)psCcapConfig);
- if (ret != RT_EOK)
- {
- LOG_E("Can't feed configuration %s", psGrabberParam->devname_ccap);
- goto fail_ccap_init;
- }
- {
- int i32SenClk = psSensorModeInfo->u32SenClk;
- if (DEF_GRID_VIEW && DEF_ENABLE_PLANAR_PIPE)
- i32SenClk = 45000000; /* Bandwidth limitation: Slow down sensor clock */
- /* speed up pixel clock */
- if (rt_device_control(psDevCcap, CCAP_CMD_SET_SENCLK, (void *)&i32SenClk) != RT_EOK)
- {
- LOG_E("Can't feed setting.");
- goto fail_ccap_init;
- }
- }
- /* Initial CCAP sensor */
- if (rt_device_open(psDevSensor, 0) != RT_EOK)
- {
- LOG_E("Can't open sensor.");
- goto fail_sensor_init;
- }
- /* Feed settings to sensor */
- if (rt_device_control(psDevSensor, CCAP_SENSOR_CMD_SET_MODE, (void *)psSensorModeInfo) != RT_EOK)
- {
- LOG_E("Can't feed setting.");
- goto fail_sensor_init;
- }
- ret = rt_device_control(psDevCcap, CCAP_CMD_SET_PIPES, (void *)psViewInfo);
- if (ret != RT_EOK)
- {
- LOG_E("Can't set pipes %s", psGrabberParam->devname_ccap);
- goto fail_ccap_init;
- }
- return psDevCcap;
- fail_sensor_init:
- if (psDevSensor)
- rt_device_close(psDevSensor);
- fail_ccap_init:
- if (psDevCcap)
- rt_device_close(psDevCcap);
- exit_ccap_sensor_init:
- psDevCcap = psDevSensor = RT_NULL;
- return psDevCcap;
- }
- static void ccap_sensor_fini(rt_device_t psDevCcap, rt_device_t psDevSensor)
- {
- if (psDevSensor)
- rt_device_close(psDevSensor);
- if (psDevCcap)
- rt_device_close(psDevCcap);
- }
- #if DEF_ENABLE_PLANAR_PIPE
- static int ccap_save_planar_frame(char *name, rt_tick_t timestamp, const void *data, size_t size)
- {
- int fd;
- char szFilename[32];
- int wrote_size = 0;
- rt_snprintf(szFilename, sizeof(szFilename), "/%s-%08d.yuv", name, timestamp);
- fd = open(szFilename, O_WRONLY | O_CREAT);
- if (fd < 0)
- {
- LOG_E("Could not open %s for writing.", szFilename);
- goto exit_ccap_save_planar_frame;
- }
- if ((wrote_size = write(fd, data, size)) != size)
- {
- LOG_E("Could not write to %s (%d != %d).", szFilename, wrote_size, size);
- goto exit_ccap_save_planar_frame;
- }
- wrote_size = size;
- exit_ccap_save_planar_frame:
- if (fd >= 0)
- close(fd);
- return wrote_size;
- }
- #endif
- static void ccap_grabber(void *parameter)
- {
- rt_err_t ret;
- ccap_grabber_param_t psGrabberParam = (ccap_grabber_param_t)parameter;
- ccap_grabber_context sGrabberContext;
- rt_device_t psDevCcap = RT_NULL;
- rt_device_t psDevLcd = RT_NULL;
- rt_tick_t last, now;
- rt_bool_t bDrawDirect;
- rt_memset((void *)&sGrabberContext, 0, sizeof(ccap_grabber_context));
- psDevLcd = rt_device_find(psGrabberParam->devname_lcd);
- if (psDevLcd == RT_NULL)
- {
- LOG_E("Can't find %s", psGrabberParam->devname_lcd);
- goto exit_ccap_grabber;
- }
- /* Get LCD Info */
- ret = rt_device_control(psDevLcd, RTGRAPHIC_CTRL_GET_INFO, &sGrabberContext.sLcdInfo);
- if (ret != RT_EOK)
- {
- LOG_E("Can't get LCD info %s", psGrabberParam->devname_lcd);
- goto exit_ccap_grabber;
- }
- /* Check panel type */
- if (rt_device_control(psDevLcd, RTGRAPHIC_CTRL_PAN_DISPLAY, (void *)sGrabberContext.sLcdInfo.framebuffer) == RT_EOK)
- {
- /* Sync-type LCD panel, will draw to VRAM directly. */
- int pixfmt = RTGRAPHIC_PIXEL_FORMAT_RGB565;
- bDrawDirect = RT_TRUE;
- rt_device_control(psDevLcd, RTGRAPHIC_CTRL_SET_MODE, (void *)&pixfmt);
- }
- else
- {
- /* MPU-type LCD panel, draw to shadow RAM, then flush. */
- bDrawDirect = RT_FALSE;
- }
- ret = rt_device_control(psDevLcd, RTGRAPHIC_CTRL_GET_INFO, &sGrabberContext.sLcdInfo);
- if (ret != RT_EOK)
- {
- LOG_E("Can't get LCD info %s", psGrabberParam->devname_lcd);
- goto exit_ccap_grabber;
- }
- LOG_I("LCD Type: %s-type", bDrawDirect ? "Sync" : "MPU");
- LOG_I("LCD Width: %d", sGrabberContext.sLcdInfo.width);
- LOG_I("LCD Height: %d", sGrabberContext.sLcdInfo.height);
- LOG_I("LCD bpp:%d", sGrabberContext.sLcdInfo.bits_per_pixel);
- LOG_I("LCD pixel format:%d", sGrabberContext.sLcdInfo.pixel_format);
- LOG_I("LCD frame buffer@0x%08x", sGrabberContext.sLcdInfo.framebuffer);
- LOG_I("LCD frame buffer size:%d", sGrabberContext.sLcdInfo.smem_len);
- sGrabberContext.semFrameEnd = rt_sem_create(psGrabberParam->devname_ccap, 0, RT_IPC_FLAG_FIFO);
- if (sGrabberContext.semFrameEnd == RT_NULL)
- {
- LOG_E("Can't allocate sem resource %s", psGrabberParam->devname_ccap);
- goto exit_ccap_grabber;
- }
- /* initial ccap & sensor*/
- psDevCcap = ccap_sensor_init(&sGrabberContext, psGrabberParam);
- if (psDevCcap == RT_NULL)
- {
- LOG_E("Can't init %s and %s", psGrabberParam->devname_ccap, psGrabberParam->devname_sensor);
- goto exit_ccap_grabber;
- }
- /* Start to capture */
- if (rt_device_control(psDevCcap, CCAP_CMD_START_CAPTURE, RT_NULL) != RT_EOK)
- {
- LOG_E("Can't start %s", psGrabberParam->devname_ccap);
- goto exit_ccap_grabber;
- }
- /* open lcd */
- ret = rt_device_open(psDevLcd, 0);
- if (ret != RT_EOK)
- {
- LOG_E("Can't open %s", psGrabberParam->devname_lcd);
- goto exit_ccap_grabber;
- }
- last = now = rt_tick_get();
- while (1)
- {
- if (sGrabberContext.semFrameEnd)
- {
- rt_sem_take(sGrabberContext.semFrameEnd, RT_WAITING_FOREVER);
- }
- if (!bDrawDirect)
- {
- //MPU type
- struct rt_device_rect_info sRectInfo;
- /* Update fullscreen region. */
- sRectInfo.x = 0;
- sRectInfo.y = 0;
- sRectInfo.height = sGrabberContext.sLcdInfo.height;
- sRectInfo.width = sGrabberContext.sLcdInfo.width;
- rt_device_control(psDevLcd, RTGRAPHIC_CTRL_RECT_UPDATE, &sRectInfo);
- }
- else if (!DEF_GRID_VIEW)
- {
- int i32FBSize = sGrabberContext.sLcdInfo.width * sGrabberContext.sLcdInfo.height * (sGrabberContext.sLcdInfo.bits_per_pixel >> 3);
- int i32VRAMPiece = sGrabberContext.sLcdInfo.smem_len / i32FBSize;
- ccap_config sCcapConfig = {0};
- uint32_t u32BufPtr = (uint32_t)sGrabberContext.sCcapConfig.sPipeInfo_Packet.pu8FarmAddr
- + (sGrabberContext.u32FrameEnd % i32VRAMPiece) * i32FBSize;
- /* Pan to valid frame address. */
- rt_device_control(psDevLcd, RTGRAPHIC_CTRL_PAN_DISPLAY, (void *)u32BufPtr);
- sCcapConfig.sPipeInfo_Packet.pu8FarmAddr = sGrabberContext.sCcapConfig.sPipeInfo_Packet.pu8FarmAddr
- + ((sGrabberContext.u32FrameEnd + 1) % i32VRAMPiece) * i32FBSize ;
- #if DEF_ENABLE_PLANAR_PIPE
- sCcapConfig.sPipeInfo_Planar.pu8FarmAddr = sGrabberContext.sCcapConfig.sPipeInfo_Planar.pu8FarmAddr;
- sCcapConfig.sPipeInfo_Planar.u32Width = sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32Width;
- sCcapConfig.sPipeInfo_Planar.u32Height = sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32Height;
- sCcapConfig.sPipeInfo_Planar.u32PixFmt = sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32PixFmt;
- #endif
- rt_device_control(psDevCcap, CCAP_CMD_SET_BASEADDR, &sCcapConfig);
- #if DEF_ENABLE_PLANAR_PIPE
- {
- int OpModeShutter = 1;
- /* One-shot mode, trigger next frame */
- rt_device_control(psDevCcap, CCAP_CMD_SET_OPMODE, &OpModeShutter);
- }
- #endif
- }
- sGrabberContext.u32FrameEnd++;
- /* FPS */
- now = rt_tick_get();
- if ((now - last) >= (DEF_DURATION * 1000))
- {
- #if DEF_ENABLE_PLANAR_PIPE
- {
- uint32_t u32Factor = 0;
- if (sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32PixFmt == CCAP_PAR_PLNFMT_YUV420)
- u32Factor = 3;
- else if (sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32PixFmt == CCAP_PAR_PLNFMT_YUV422)
- u32Factor = 4;
- if (u32Factor > 0)
- {
- ccap_save_planar_frame(psGrabberParam->thread_name, now, (const void *)sGrabberContext.sCcapConfig.sPipeInfo_Planar.pu8FarmAddr, sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32Width * sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32Height * u32Factor / 2);
- }
- }
- #endif
- LOG_I("%s: %d FPS", psGrabberParam->devname_ccap, sGrabberContext.u32FrameEnd / DEF_DURATION);
- sGrabberContext.u32FrameEnd = 0;
- last = now;
- }
- }
- exit_ccap_grabber:
- ccap_sensor_fini(rt_device_find(psGrabberParam->devname_ccap), rt_device_find(psGrabberParam->devname_sensor));
- if (psDevLcd != RT_NULL)
- rt_device_close(psDevLcd);
- return;
- }
- static void ccap_grabber_create(ccap_grabber_param_t psGrabberParam)
- {
- rt_thread_t ccap_thread = rt_thread_find(psGrabberParam->thread_name);
- if (ccap_thread == RT_NULL)
- {
- ccap_thread = rt_thread_create(psGrabberParam->thread_name,
- ccap_grabber,
- psGrabberParam,
- THREAD_STACK_SIZE,
- THREAD_PRIORITY,
- THREAD_TIMESLICE);
- if (ccap_thread != RT_NULL)
- rt_thread_startup(ccap_thread);
- }
- }
- int ccap_demo(void)
- {
- #if defined(BSP_USING_CCAP0)
- static ccap_grabber_param ccap0_grabber_param = {"grab0", "ccap0", "sensor0", "lcd"};
- ccap_grabber_create(&ccap0_grabber_param);
- #endif
- #if defined(BSP_USING_CCAP1)
- static ccap_grabber_param ccap1_grabber_param = {"grab1", "ccap1", "sensor1", "lcd"};
- ccap_grabber_create(&ccap1_grabber_param);
- #endif
- return 0;
- }
- MSH_CMD_EXPORT(ccap_demo, camera capture demo);
- //INIT_ENV_EXPORT(ccap_demo);
- #endif
|