ccap_demo.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2022-8-16 Wayne First version
  10. *
  11. ******************************************************************************/
  12. #include <rtthread.h>
  13. #if defined(BSP_USING_CCAP)
  14. #include "drv_ccap.h"
  15. #include <dfs_posix.h>
  16. #define DBG_ENABLE
  17. #define DBG_LEVEL DBG_LOG
  18. #define DBG_SECTION_NAME "ccap.demo"
  19. #define DBG_COLOR
  20. #include <rtdbg.h>
  21. #define THREAD_PRIORITY 5
  22. #define THREAD_STACK_SIZE 4096
  23. #define THREAD_TIMESLICE 5
  24. #define DEF_CROP_PACKET_RECT
  25. #define DEF_ENABLE_PLANAR_PIPE 0
  26. #define DEF_DURATION 10
  27. #if defined(BSP_USING_CCAP0) && defined(BSP_USING_CCAP1)
  28. #define DEF_GRID_VIEW 1
  29. #elif defined(BSP_USING_CCAP0) || defined(BSP_USING_CCAP1)
  30. #define DEF_GRID_VIEW 0
  31. #endif
  32. typedef struct
  33. {
  34. char *thread_name;
  35. char *devname_ccap;
  36. char *devname_sensor;
  37. char *devname_lcd;
  38. } ccap_grabber_param;
  39. typedef ccap_grabber_param *ccap_grabber_param_t;
  40. typedef struct
  41. {
  42. ccap_config sCcapConfig;
  43. struct rt_device_graphic_info sLcdInfo;
  44. uint32_t u32CurFBPointer;
  45. uint32_t u32FrameEnd;
  46. rt_sem_t semFrameEnd;
  47. } ccap_grabber_context;
  48. typedef ccap_grabber_context *ccap_grabber_context_t;
  49. static void nu_ccap_event_hook(void *pvData, uint32_t u32EvtMask)
  50. {
  51. ccap_grabber_context_t psGrabberContext = (ccap_grabber_context_t)pvData;
  52. if (u32EvtMask & NU_CCAP_FRAME_END)
  53. {
  54. rt_sem_release(psGrabberContext->semFrameEnd);
  55. }
  56. if (u32EvtMask & NU_CCAP_ADDRESS_MATCH)
  57. {
  58. LOG_I("Address matched");
  59. }
  60. if (u32EvtMask & NU_CCAP_MEMORY_ERROR)
  61. {
  62. LOG_E("Access memory error");
  63. }
  64. }
  65. static rt_device_t ccap_sensor_init(ccap_grabber_context_t psGrabberContext, ccap_grabber_param_t psGrabberParam)
  66. {
  67. rt_err_t ret;
  68. ccap_view_info_t psViewInfo;
  69. sensor_mode_info *psSensorModeInfo;
  70. rt_device_t psDevSensor = RT_NULL;
  71. rt_device_t psDevCcap = RT_NULL;
  72. struct rt_device_graphic_info *psLcdInfo = &psGrabberContext->sLcdInfo;
  73. ccap_config_t psCcapConfig = &psGrabberContext->sCcapConfig;
  74. psDevCcap = rt_device_find(psGrabberParam->devname_ccap);
  75. if (psDevCcap == RT_NULL)
  76. {
  77. LOG_E("Can't find %s", psGrabberParam->devname_ccap);
  78. goto exit_ccap_sensor_init;
  79. }
  80. psDevSensor = rt_device_find(psGrabberParam->devname_sensor);
  81. if (psDevSensor == RT_NULL)
  82. {
  83. LOG_E("Can't find %s", psGrabberParam->devname_sensor);
  84. goto exit_ccap_sensor_init;
  85. }
  86. /* Packet pipe for preview */
  87. if (DEF_GRID_VIEW)
  88. {
  89. psCcapConfig->sPipeInfo_Packet.u32Width = psLcdInfo->width / 2;
  90. psCcapConfig->sPipeInfo_Packet.u32Height = psLcdInfo->height / 2;
  91. psCcapConfig->sPipeInfo_Packet.u32PixFmt = (psLcdInfo->pixel_format == RTGRAPHIC_PIXEL_FORMAT_RGB565) ? CCAP_PAR_OUTFMT_RGB565 : 0;
  92. psCcapConfig->u32Stride_Packet = psLcdInfo->width;
  93. if (!rt_strcmp(psGrabberParam->devname_ccap, "ccap1"))
  94. psCcapConfig->sPipeInfo_Packet.pu8FarmAddr = psLcdInfo->framebuffer + (psCcapConfig->sPipeInfo_Packet.u32Width * 2);
  95. else
  96. psCcapConfig->sPipeInfo_Packet.pu8FarmAddr = psLcdInfo->framebuffer;
  97. }
  98. else
  99. {
  100. psCcapConfig->sPipeInfo_Packet.pu8FarmAddr = psLcdInfo->framebuffer;
  101. psCcapConfig->sPipeInfo_Packet.u32Height = psLcdInfo->height;
  102. psCcapConfig->sPipeInfo_Packet.u32Width = psLcdInfo->width;
  103. psCcapConfig->sPipeInfo_Packet.u32PixFmt = (psLcdInfo->pixel_format == RTGRAPHIC_PIXEL_FORMAT_RGB565) ? CCAP_PAR_OUTFMT_RGB565 : 0;
  104. psCcapConfig->u32Stride_Packet = psLcdInfo->width;
  105. }
  106. /* Planar pipe for encoding */
  107. #if DEF_ENABLE_PLANAR_PIPE
  108. psCcapConfig->sPipeInfo_Planar.u32Width = psLcdInfo->width / 2;
  109. psCcapConfig->sPipeInfo_Planar.u32Height = psLcdInfo->height / 2;
  110. psCcapConfig->sPipeInfo_Planar.pu8FarmAddr = rt_malloc_align(psCcapConfig->sPipeInfo_Planar.u32Height * psCcapConfig->sPipeInfo_Planar.u32Width * 2, 32);
  111. psCcapConfig->sPipeInfo_Planar.u32PixFmt = CCAP_PAR_PLNFMT_YUV420; //CCAP_PAR_PLNFMT_YUV422;
  112. psCcapConfig->u32Stride_Planar = psCcapConfig->sPipeInfo_Planar.u32Width;
  113. if (psCcapConfig->sPipeInfo_Planar.pu8FarmAddr == RT_NULL)
  114. {
  115. psCcapConfig->sPipeInfo_Planar.u32Height = 0;
  116. psCcapConfig->sPipeInfo_Planar.u32Width = 0;
  117. psCcapConfig->sPipeInfo_Planar.u32PixFmt = 0;
  118. psCcapConfig->u32Stride_Planar = 0;
  119. }
  120. LOG_I("Planar.FarmAddr@0x%08X", psCcapConfig->sPipeInfo_Planar.pu8FarmAddr);
  121. LOG_I("Planar.FarmWidth: %d", psCcapConfig->sPipeInfo_Planar.u32Width);
  122. LOG_I("Planar.FarmHeight: %d", psCcapConfig->sPipeInfo_Planar.u32Height);
  123. #endif
  124. /* open CCAP */
  125. ret = rt_device_open(psDevCcap, 0);
  126. if (ret != RT_EOK)
  127. {
  128. LOG_E("Can't open %s", psGrabberParam->devname_ccap);
  129. goto exit_ccap_sensor_init;
  130. }
  131. /* Find suit mode for packet pipe */
  132. if (psCcapConfig->sPipeInfo_Packet.pu8FarmAddr != RT_NULL)
  133. {
  134. /* Check view window of packet pipe */
  135. psViewInfo = &psCcapConfig->sPipeInfo_Packet;
  136. if ((rt_device_control(psDevSensor, CCAP_SENSOR_CMD_GET_SUIT_MODE, (void *)&psViewInfo) != RT_EOK)
  137. || (psViewInfo == RT_NULL))
  138. {
  139. LOG_E("Can't get suit mode for packet.");
  140. goto fail_ccap_init;
  141. }
  142. }
  143. /* Find suit mode for planner pipe */
  144. if (psCcapConfig->sPipeInfo_Planar.pu8FarmAddr != RT_NULL)
  145. {
  146. int recheck = 1;
  147. if (psViewInfo != RT_NULL)
  148. {
  149. if ((psCcapConfig->sPipeInfo_Planar.u32Width <= psViewInfo->u32Width) ||
  150. (psCcapConfig->sPipeInfo_Planar.u32Height <= psViewInfo->u32Height))
  151. recheck = 0;
  152. }
  153. if (recheck)
  154. {
  155. /* Check view window of planner pipe */
  156. psViewInfo = &psCcapConfig->sPipeInfo_Planar;
  157. /* Find suit mode */
  158. if ((rt_device_control(psDevSensor, CCAP_SENSOR_CMD_GET_SUIT_MODE, (void *)&psViewInfo) != RT_EOK)
  159. || (psViewInfo == RT_NULL))
  160. {
  161. LOG_E("Can't get suit mode for planner.");
  162. goto exit_ccap_sensor_init;
  163. }
  164. }
  165. }
  166. #if defined(DEF_CROP_PACKET_RECT)
  167. /* Set cropping rectangle */
  168. if (psViewInfo->u32Width >= psCcapConfig->sPipeInfo_Packet.u32Width)
  169. {
  170. /* sensor.width >= preview.width */
  171. psCcapConfig->sRectCropping.x = (psViewInfo->u32Width - psCcapConfig->sPipeInfo_Packet.u32Width) / 2;
  172. psCcapConfig->sRectCropping.width = psCcapConfig->sPipeInfo_Packet.u32Width;
  173. }
  174. else
  175. {
  176. /* sensor.width < preview.width */
  177. psCcapConfig->sRectCropping.x = 0;
  178. psCcapConfig->sRectCropping.width = psViewInfo->u32Width;
  179. }
  180. if (psViewInfo->u32Height >= psCcapConfig->sPipeInfo_Packet.u32Height)
  181. {
  182. /* sensor.height >= preview.height */
  183. psCcapConfig->sRectCropping.y = (psViewInfo->u32Height - psCcapConfig->sPipeInfo_Packet.u32Height) / 2;
  184. psCcapConfig->sRectCropping.height = psCcapConfig->sPipeInfo_Packet.u32Height;
  185. }
  186. else
  187. {
  188. /* sensor.height < preview.height */
  189. psCcapConfig->sRectCropping.y = 0;
  190. psCcapConfig->sRectCropping.height = psViewInfo->u32Height;
  191. }
  192. #else
  193. /* Set cropping rectangle */
  194. psCcapConfig->sRectCropping.x = 0;
  195. psCcapConfig->sRectCropping.y = 0;
  196. psCcapConfig->sRectCropping.width = psViewInfo->u32Width;
  197. psCcapConfig->sRectCropping.height = psViewInfo->u32Height;
  198. #endif
  199. /* ISR Hook */
  200. psCcapConfig->pfnEvHndler = nu_ccap_event_hook;
  201. psCcapConfig->pvData = (void *)psGrabberContext;
  202. /* Get Suitable mode. */
  203. psSensorModeInfo = (sensor_mode_info *)psViewInfo;
  204. /* Feed CCAP configuration */
  205. ret = rt_device_control(psDevCcap, CCAP_CMD_CONFIG, (void *)psCcapConfig);
  206. if (ret != RT_EOK)
  207. {
  208. LOG_E("Can't feed configuration %s", psGrabberParam->devname_ccap);
  209. goto fail_ccap_init;
  210. }
  211. {
  212. int i32SenClk = psSensorModeInfo->u32SenClk;
  213. if (DEF_GRID_VIEW && DEF_ENABLE_PLANAR_PIPE)
  214. i32SenClk = 45000000; /* Bandwidth limitation: Slow down sensor clock */
  215. /* speed up pixel clock */
  216. if (rt_device_control(psDevCcap, CCAP_CMD_SET_SENCLK, (void *)&i32SenClk) != RT_EOK)
  217. {
  218. LOG_E("Can't feed setting.");
  219. goto fail_ccap_init;
  220. }
  221. }
  222. /* Initial CCAP sensor */
  223. if (rt_device_open(psDevSensor, 0) != RT_EOK)
  224. {
  225. LOG_E("Can't open sensor.");
  226. goto fail_sensor_init;
  227. }
  228. /* Feed settings to sensor */
  229. if (rt_device_control(psDevSensor, CCAP_SENSOR_CMD_SET_MODE, (void *)psSensorModeInfo) != RT_EOK)
  230. {
  231. LOG_E("Can't feed setting.");
  232. goto fail_sensor_init;
  233. }
  234. ret = rt_device_control(psDevCcap, CCAP_CMD_SET_PIPES, (void *)psViewInfo);
  235. if (ret != RT_EOK)
  236. {
  237. LOG_E("Can't set pipes %s", psGrabberParam->devname_ccap);
  238. goto fail_ccap_init;
  239. }
  240. return psDevCcap;
  241. fail_sensor_init:
  242. if (psDevSensor)
  243. rt_device_close(psDevSensor);
  244. fail_ccap_init:
  245. if (psDevCcap)
  246. rt_device_close(psDevCcap);
  247. exit_ccap_sensor_init:
  248. psDevCcap = psDevSensor = RT_NULL;
  249. return psDevCcap;
  250. }
  251. static void ccap_sensor_fini(rt_device_t psDevCcap, rt_device_t psDevSensor)
  252. {
  253. if (psDevSensor)
  254. rt_device_close(psDevSensor);
  255. if (psDevCcap)
  256. rt_device_close(psDevCcap);
  257. }
  258. #if DEF_ENABLE_PLANAR_PIPE
  259. static int ccap_save_planar_frame(char *name, rt_tick_t timestamp, const void *data, size_t size)
  260. {
  261. int fd;
  262. char szFilename[32];
  263. int wrote_size = 0;
  264. rt_snprintf(szFilename, sizeof(szFilename), "/%s-%08d.yuv", name, timestamp);
  265. fd = open(szFilename, O_WRONLY | O_CREAT);
  266. if (fd < 0)
  267. {
  268. LOG_E("Could not open %s for writing.", szFilename);
  269. goto exit_ccap_save_planar_frame;
  270. }
  271. if ((wrote_size = write(fd, data, size)) != size)
  272. {
  273. LOG_E("Could not write to %s (%d != %d).", szFilename, wrote_size, size);
  274. goto exit_ccap_save_planar_frame;
  275. }
  276. wrote_size = size;
  277. exit_ccap_save_planar_frame:
  278. if (fd >= 0)
  279. close(fd);
  280. return wrote_size;
  281. }
  282. #endif
  283. static void ccap_grabber(void *parameter)
  284. {
  285. rt_err_t ret;
  286. ccap_grabber_param_t psGrabberParam = (ccap_grabber_param_t)parameter;
  287. ccap_grabber_context sGrabberContext;
  288. rt_device_t psDevCcap = RT_NULL;
  289. rt_device_t psDevLcd = RT_NULL;
  290. rt_tick_t last, now;
  291. rt_bool_t bDrawDirect;
  292. rt_memset((void *)&sGrabberContext, 0, sizeof(ccap_grabber_context));
  293. psDevLcd = rt_device_find(psGrabberParam->devname_lcd);
  294. if (psDevLcd == RT_NULL)
  295. {
  296. LOG_E("Can't find %s", psGrabberParam->devname_lcd);
  297. goto exit_ccap_grabber;
  298. }
  299. /* Get LCD Info */
  300. ret = rt_device_control(psDevLcd, RTGRAPHIC_CTRL_GET_INFO, &sGrabberContext.sLcdInfo);
  301. if (ret != RT_EOK)
  302. {
  303. LOG_E("Can't get LCD info %s", psGrabberParam->devname_lcd);
  304. goto exit_ccap_grabber;
  305. }
  306. /* Check panel type */
  307. if (rt_device_control(psDevLcd, RTGRAPHIC_CTRL_PAN_DISPLAY, (void *)sGrabberContext.sLcdInfo.framebuffer) == RT_EOK)
  308. {
  309. /* Sync-type LCD panel, will draw to VRAM directly. */
  310. int pixfmt = RTGRAPHIC_PIXEL_FORMAT_RGB565;
  311. bDrawDirect = RT_TRUE;
  312. rt_device_control(psDevLcd, RTGRAPHIC_CTRL_SET_MODE, (void *)&pixfmt);
  313. }
  314. else
  315. {
  316. /* MPU-type LCD panel, draw to shadow RAM, then flush. */
  317. bDrawDirect = RT_FALSE;
  318. }
  319. ret = rt_device_control(psDevLcd, RTGRAPHIC_CTRL_GET_INFO, &sGrabberContext.sLcdInfo);
  320. if (ret != RT_EOK)
  321. {
  322. LOG_E("Can't get LCD info %s", psGrabberParam->devname_lcd);
  323. goto exit_ccap_grabber;
  324. }
  325. LOG_I("LCD Type: %s-type", bDrawDirect ? "Sync" : "MPU");
  326. LOG_I("LCD Width: %d", sGrabberContext.sLcdInfo.width);
  327. LOG_I("LCD Height: %d", sGrabberContext.sLcdInfo.height);
  328. LOG_I("LCD bpp:%d", sGrabberContext.sLcdInfo.bits_per_pixel);
  329. LOG_I("LCD pixel format:%d", sGrabberContext.sLcdInfo.pixel_format);
  330. LOG_I("LCD frame buffer@0x%08x", sGrabberContext.sLcdInfo.framebuffer);
  331. LOG_I("LCD frame buffer size:%d", sGrabberContext.sLcdInfo.smem_len);
  332. sGrabberContext.semFrameEnd = rt_sem_create(psGrabberParam->devname_ccap, 0, RT_IPC_FLAG_FIFO);
  333. if (sGrabberContext.semFrameEnd == RT_NULL)
  334. {
  335. LOG_E("Can't allocate sem resource %s", psGrabberParam->devname_ccap);
  336. goto exit_ccap_grabber;
  337. }
  338. /* initial ccap & sensor*/
  339. psDevCcap = ccap_sensor_init(&sGrabberContext, psGrabberParam);
  340. if (psDevCcap == RT_NULL)
  341. {
  342. LOG_E("Can't init %s and %s", psGrabberParam->devname_ccap, psGrabberParam->devname_sensor);
  343. goto exit_ccap_grabber;
  344. }
  345. /* Start to capture */
  346. if (rt_device_control(psDevCcap, CCAP_CMD_START_CAPTURE, RT_NULL) != RT_EOK)
  347. {
  348. LOG_E("Can't start %s", psGrabberParam->devname_ccap);
  349. goto exit_ccap_grabber;
  350. }
  351. /* open lcd */
  352. ret = rt_device_open(psDevLcd, 0);
  353. if (ret != RT_EOK)
  354. {
  355. LOG_E("Can't open %s", psGrabberParam->devname_lcd);
  356. goto exit_ccap_grabber;
  357. }
  358. last = now = rt_tick_get();
  359. while (1)
  360. {
  361. if (sGrabberContext.semFrameEnd)
  362. {
  363. rt_sem_take(sGrabberContext.semFrameEnd, RT_WAITING_FOREVER);
  364. }
  365. if (!bDrawDirect)
  366. {
  367. //MPU type
  368. struct rt_device_rect_info sRectInfo;
  369. /* Update fullscreen region. */
  370. sRectInfo.x = 0;
  371. sRectInfo.y = 0;
  372. sRectInfo.height = sGrabberContext.sLcdInfo.height;
  373. sRectInfo.width = sGrabberContext.sLcdInfo.width;
  374. rt_device_control(psDevLcd, RTGRAPHIC_CTRL_RECT_UPDATE, &sRectInfo);
  375. }
  376. else if (!DEF_GRID_VIEW)
  377. {
  378. int i32FBSize = sGrabberContext.sLcdInfo.width * sGrabberContext.sLcdInfo.height * (sGrabberContext.sLcdInfo.bits_per_pixel >> 3);
  379. int i32VRAMPiece = sGrabberContext.sLcdInfo.smem_len / i32FBSize;
  380. ccap_config sCcapConfig = {0};
  381. uint32_t u32BufPtr = (uint32_t)sGrabberContext.sCcapConfig.sPipeInfo_Packet.pu8FarmAddr
  382. + (sGrabberContext.u32FrameEnd % i32VRAMPiece) * i32FBSize;
  383. /* Pan to valid frame address. */
  384. rt_device_control(psDevLcd, RTGRAPHIC_CTRL_PAN_DISPLAY, (void *)u32BufPtr);
  385. sCcapConfig.sPipeInfo_Packet.pu8FarmAddr = sGrabberContext.sCcapConfig.sPipeInfo_Packet.pu8FarmAddr
  386. + ((sGrabberContext.u32FrameEnd + 1) % i32VRAMPiece) * i32FBSize ;
  387. #if DEF_ENABLE_PLANAR_PIPE
  388. sCcapConfig.sPipeInfo_Planar.pu8FarmAddr = sGrabberContext.sCcapConfig.sPipeInfo_Planar.pu8FarmAddr;
  389. sCcapConfig.sPipeInfo_Planar.u32Width = sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32Width;
  390. sCcapConfig.sPipeInfo_Planar.u32Height = sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32Height;
  391. sCcapConfig.sPipeInfo_Planar.u32PixFmt = sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32PixFmt;
  392. #endif
  393. rt_device_control(psDevCcap, CCAP_CMD_SET_BASEADDR, &sCcapConfig);
  394. #if DEF_ENABLE_PLANAR_PIPE
  395. {
  396. int OpModeShutter = 1;
  397. /* One-shot mode, trigger next frame */
  398. rt_device_control(psDevCcap, CCAP_CMD_SET_OPMODE, &OpModeShutter);
  399. }
  400. #endif
  401. }
  402. sGrabberContext.u32FrameEnd++;
  403. /* FPS */
  404. now = rt_tick_get();
  405. if ((now - last) >= (DEF_DURATION * 1000))
  406. {
  407. #if DEF_ENABLE_PLANAR_PIPE
  408. {
  409. uint32_t u32Factor = 0;
  410. if (sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32PixFmt == CCAP_PAR_PLNFMT_YUV420)
  411. u32Factor = 3;
  412. else if (sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32PixFmt == CCAP_PAR_PLNFMT_YUV422)
  413. u32Factor = 4;
  414. if (u32Factor > 0)
  415. {
  416. 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);
  417. }
  418. }
  419. #endif
  420. LOG_I("%s: %d FPS", psGrabberParam->devname_ccap, sGrabberContext.u32FrameEnd / DEF_DURATION);
  421. sGrabberContext.u32FrameEnd = 0;
  422. last = now;
  423. }
  424. }
  425. exit_ccap_grabber:
  426. ccap_sensor_fini(rt_device_find(psGrabberParam->devname_ccap), rt_device_find(psGrabberParam->devname_sensor));
  427. if (psDevLcd != RT_NULL)
  428. rt_device_close(psDevLcd);
  429. return;
  430. }
  431. static void ccap_grabber_create(ccap_grabber_param_t psGrabberParam)
  432. {
  433. rt_thread_t ccap_thread = rt_thread_find(psGrabberParam->thread_name);
  434. if (ccap_thread == RT_NULL)
  435. {
  436. ccap_thread = rt_thread_create(psGrabberParam->thread_name,
  437. ccap_grabber,
  438. psGrabberParam,
  439. THREAD_STACK_SIZE,
  440. THREAD_PRIORITY,
  441. THREAD_TIMESLICE);
  442. if (ccap_thread != RT_NULL)
  443. rt_thread_startup(ccap_thread);
  444. }
  445. }
  446. int ccap_demo(void)
  447. {
  448. #if defined(BSP_USING_CCAP0)
  449. static ccap_grabber_param ccap0_grabber_param = {"grab0", "ccap0", "sensor0", "lcd"};
  450. ccap_grabber_create(&ccap0_grabber_param);
  451. #endif
  452. #if defined(BSP_USING_CCAP1)
  453. static ccap_grabber_param ccap1_grabber_param = {"grab1", "ccap1", "sensor1", "lcd"};
  454. ccap_grabber_create(&ccap1_grabber_param);
  455. #endif
  456. return 0;
  457. }
  458. MSH_CMD_EXPORT(ccap_demo, camera capture demo);
  459. //INIT_ENV_EXPORT(ccap_demo);
  460. #endif