ccap_saver.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  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.saver"
  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_FRAME_WIDTH 640
  25. #define DEF_FRAME_HEIGHT 480
  26. typedef struct
  27. {
  28. char *thread_name;
  29. char *devname_ccap;
  30. char *devname_sensor;
  31. } ccap_grabber_param;
  32. typedef ccap_grabber_param *ccap_grabber_param_t;
  33. typedef struct
  34. {
  35. ccap_config sCcapConfig;
  36. uint32_t u32CurFBPointer;
  37. uint32_t u32FrameEnd;
  38. rt_sem_t semFrameEnd;
  39. } ccap_grabber_context;
  40. typedef ccap_grabber_context *ccap_grabber_context_t;
  41. static void nu_ccap_event_hook(void *pvData, uint32_t u32EvtMask)
  42. {
  43. ccap_grabber_context_t psGrabberContext = (ccap_grabber_context_t)pvData;
  44. if (u32EvtMask & NU_CCAP_FRAME_END)
  45. {
  46. rt_sem_release(psGrabberContext->semFrameEnd);
  47. }
  48. if (u32EvtMask & NU_CCAP_ADDRESS_MATCH)
  49. {
  50. LOG_I("Address matched");
  51. }
  52. if (u32EvtMask & NU_CCAP_MEMORY_ERROR)
  53. {
  54. LOG_E("Access memory error");
  55. }
  56. }
  57. static rt_device_t ccap_sensor_init(ccap_grabber_context_t psGrabberContext, ccap_grabber_param_t psGrabberParam)
  58. {
  59. rt_err_t ret;
  60. ccap_view_info_t psViewInfo;
  61. sensor_mode_info *psSensorModeInfo;
  62. rt_device_t psDevSensor = RT_NULL;
  63. rt_device_t psDevCcap = RT_NULL;
  64. ccap_config_t psCcapConfig = &psGrabberContext->sCcapConfig;
  65. psDevCcap = rt_device_find(psGrabberParam->devname_ccap);
  66. if (psDevCcap == RT_NULL)
  67. {
  68. LOG_E("Can't find %s", psGrabberParam->devname_ccap);
  69. goto exit_ccap_sensor_init;
  70. }
  71. psDevSensor = rt_device_find(psGrabberParam->devname_sensor);
  72. if (psDevSensor == RT_NULL)
  73. {
  74. LOG_E("Can't find %s", psGrabberParam->devname_sensor);
  75. goto exit_ccap_sensor_init;
  76. }
  77. /* Packet pipe for preview */
  78. psCcapConfig->sPipeInfo_Packet.u32Width = DEF_FRAME_WIDTH;
  79. psCcapConfig->sPipeInfo_Packet.u32Height = DEF_FRAME_HEIGHT;
  80. psCcapConfig->sPipeInfo_Packet.pu8FarmAddr = rt_malloc_align(psCcapConfig->sPipeInfo_Packet.u32Height * psCcapConfig->sPipeInfo_Packet.u32Width * 2, 32);
  81. if (psCcapConfig->sPipeInfo_Packet.pu8FarmAddr == RT_NULL)
  82. {
  83. LOG_E("Can't malloc");
  84. goto exit_ccap_sensor_init;
  85. }
  86. psCcapConfig->sPipeInfo_Packet.u32PixFmt = CCAP_PAR_OUTFMT_RGB565;
  87. psCcapConfig->u32Stride_Packet = psCcapConfig->sPipeInfo_Packet.u32Width;
  88. /* Planar pipe for encoding */
  89. psCcapConfig->sPipeInfo_Planar.u32Width = psCcapConfig->sPipeInfo_Packet.u32Width;
  90. psCcapConfig->sPipeInfo_Planar.u32Height = psCcapConfig->sPipeInfo_Packet.u32Height;
  91. psCcapConfig->sPipeInfo_Planar.pu8FarmAddr = rt_malloc_align(psCcapConfig->sPipeInfo_Planar.u32Height * psCcapConfig->sPipeInfo_Planar.u32Width * 2, 32);
  92. if (psCcapConfig->sPipeInfo_Planar.pu8FarmAddr == RT_NULL)
  93. {
  94. LOG_E("Can't malloc");
  95. goto exit_ccap_sensor_init;
  96. }
  97. psCcapConfig->sPipeInfo_Planar.u32PixFmt = CCAP_PAR_PLNFMT_YUV422;
  98. psCcapConfig->u32Stride_Planar = psCcapConfig->sPipeInfo_Planar.u32Width;
  99. LOG_I("Packet.FarmAddr@0x%08X", psCcapConfig->sPipeInfo_Packet.pu8FarmAddr);
  100. LOG_I("Packet.FarmWidth: %d", psCcapConfig->sPipeInfo_Packet.u32Width);
  101. LOG_I("Packet.FarmHeight: %d", psCcapConfig->sPipeInfo_Packet.u32Height);
  102. LOG_I("Planar.FarmAddr@0x%08X", psCcapConfig->sPipeInfo_Planar.pu8FarmAddr);
  103. LOG_I("Planar.FarmWidth: %d", psCcapConfig->sPipeInfo_Planar.u32Width);
  104. LOG_I("Planar.FarmHeight: %d", psCcapConfig->sPipeInfo_Planar.u32Height);
  105. /* open CCAP */
  106. ret = rt_device_open(psDevCcap, 0);
  107. if (ret != RT_EOK)
  108. {
  109. LOG_E("Can't open %s", psGrabberParam->devname_ccap);
  110. goto exit_ccap_sensor_init;
  111. }
  112. /* Find suit mode for packet pipe */
  113. if (psCcapConfig->sPipeInfo_Packet.pu8FarmAddr != RT_NULL)
  114. {
  115. /* Check view window of packet pipe */
  116. psViewInfo = &psCcapConfig->sPipeInfo_Packet;
  117. if ((rt_device_control(psDevSensor, CCAP_SENSOR_CMD_GET_SUIT_MODE, (void *)&psViewInfo) != RT_EOK)
  118. || (psViewInfo == RT_NULL))
  119. {
  120. LOG_E("Can't get suit mode for packet.");
  121. goto fail_ccap_init;
  122. }
  123. }
  124. /* Find suit mode for planner pipe */
  125. if (psCcapConfig->sPipeInfo_Planar.pu8FarmAddr != RT_NULL)
  126. {
  127. int recheck = 1;
  128. if (psViewInfo != RT_NULL)
  129. {
  130. if ((psCcapConfig->sPipeInfo_Planar.u32Width <= psViewInfo->u32Width) ||
  131. (psCcapConfig->sPipeInfo_Planar.u32Height <= psViewInfo->u32Height))
  132. recheck = 0;
  133. }
  134. if (recheck)
  135. {
  136. /* Check view window of planner pipe */
  137. psViewInfo = &psCcapConfig->sPipeInfo_Planar;
  138. /* Find suit mode */
  139. if ((rt_device_control(psDevSensor, CCAP_SENSOR_CMD_GET_SUIT_MODE, (void *)&psViewInfo) != RT_EOK)
  140. || (psViewInfo == RT_NULL))
  141. {
  142. LOG_E("Can't get suit mode for planner.");
  143. goto exit_ccap_sensor_init;
  144. }
  145. }
  146. }
  147. /* Set cropping rectangle */
  148. psCcapConfig->sRectCropping.x = 0;
  149. psCcapConfig->sRectCropping.y = 0;
  150. psCcapConfig->sRectCropping.width = psViewInfo->u32Width;
  151. psCcapConfig->sRectCropping.height = psViewInfo->u32Height;
  152. /* ISR Hook */
  153. psCcapConfig->pfnEvHndler = nu_ccap_event_hook;
  154. psCcapConfig->pvData = (void *)psGrabberContext;
  155. /* Get Suitable mode. */
  156. psSensorModeInfo = (sensor_mode_info *)psViewInfo;
  157. /* Feed CCAP configuration */
  158. ret = rt_device_control(psDevCcap, CCAP_CMD_CONFIG, (void *)psCcapConfig);
  159. if (ret != RT_EOK)
  160. {
  161. LOG_E("Can't feed configuration %s", psGrabberParam->devname_ccap);
  162. goto fail_ccap_init;
  163. }
  164. {
  165. int i32SenClk = psSensorModeInfo->u32SenClk;
  166. /* speed up pixel clock */
  167. if (rt_device_control(psDevCcap, CCAP_CMD_SET_SENCLK, (void *)&i32SenClk) != RT_EOK)
  168. {
  169. LOG_E("Can't feed setting.");
  170. goto fail_ccap_init;
  171. }
  172. }
  173. /* Initial CCAP sensor */
  174. if (rt_device_open(psDevSensor, 0) != RT_EOK)
  175. {
  176. LOG_E("Can't open sensor.");
  177. goto fail_sensor_init;
  178. }
  179. /* Feed settings to sensor */
  180. if (rt_device_control(psDevSensor, CCAP_SENSOR_CMD_SET_MODE, (void *)psSensorModeInfo) != RT_EOK)
  181. {
  182. LOG_E("Can't feed setting.");
  183. goto fail_sensor_init;
  184. }
  185. ret = rt_device_control(psDevCcap, CCAP_CMD_SET_PIPES, (void *)psViewInfo);
  186. if (ret != RT_EOK)
  187. {
  188. LOG_E("Can't set pipes %s", psGrabberParam->devname_ccap);
  189. goto fail_ccap_init;
  190. }
  191. return psDevCcap;
  192. fail_sensor_init:
  193. if (psDevSensor)
  194. rt_device_close(psDevSensor);
  195. fail_ccap_init:
  196. if (psDevCcap)
  197. rt_device_close(psDevCcap);
  198. exit_ccap_sensor_init:
  199. psDevCcap = psDevSensor = RT_NULL;
  200. return psDevCcap;
  201. }
  202. static void ccap_sensor_fini(rt_device_t psDevCcap, rt_device_t psDevSensor)
  203. {
  204. if (psDevSensor)
  205. rt_device_close(psDevSensor);
  206. if (psDevCcap)
  207. rt_device_close(psDevCcap);
  208. }
  209. static int ccap_save_frame(char *szFilename, const void *data, size_t size)
  210. {
  211. int fd;
  212. int wrote_size = 0;
  213. fd = open(szFilename, O_WRONLY | O_CREAT);
  214. if (fd < 0)
  215. {
  216. LOG_E("Could not open %s for writing.", szFilename);
  217. goto exit_ccap_save_planar_frame;
  218. }
  219. if ((wrote_size = write(fd, data, size)) != size)
  220. {
  221. LOG_E("Could not write to %s (%d != %d).", szFilename, wrote_size, size);
  222. goto exit_ccap_save_planar_frame;
  223. }
  224. wrote_size = size;
  225. LOG_I("Output %s", szFilename);
  226. exit_ccap_save_planar_frame:
  227. if (fd >= 0)
  228. close(fd);
  229. return wrote_size;
  230. }
  231. static void ccap_grabber(void *parameter)
  232. {
  233. ccap_grabber_param_t psGrabberParam = (ccap_grabber_param_t)parameter;
  234. ccap_grabber_context sGrabberContext;
  235. rt_device_t psDevCcap = RT_NULL;
  236. rt_memset((void *)&sGrabberContext, 0, sizeof(ccap_grabber_context));
  237. sGrabberContext.semFrameEnd = rt_sem_create(psGrabberParam->devname_ccap, 0, RT_IPC_FLAG_FIFO);
  238. if (sGrabberContext.semFrameEnd == RT_NULL)
  239. {
  240. LOG_E("Can't allocate sem resource %s", psGrabberParam->devname_ccap);
  241. goto exit_ccap_grabber;
  242. }
  243. /* initial ccap & sensor*/
  244. psDevCcap = ccap_sensor_init(&sGrabberContext, psGrabberParam);
  245. if (psDevCcap == RT_NULL)
  246. {
  247. LOG_E("Can't init %s and %s", psGrabberParam->devname_ccap, psGrabberParam->devname_sensor);
  248. goto exit_ccap_grabber;
  249. }
  250. /* Start to capture */
  251. if (rt_device_control(psDevCcap, CCAP_CMD_START_CAPTURE, RT_NULL) != RT_EOK)
  252. {
  253. LOG_E("Can't start %s", psGrabberParam->devname_ccap);
  254. goto exit_ccap_grabber;
  255. }
  256. while (1)
  257. {
  258. if (sGrabberContext.semFrameEnd)
  259. {
  260. rt_sem_take(sGrabberContext.semFrameEnd, RT_WAITING_FOREVER);
  261. }
  262. sGrabberContext.u32FrameEnd++;
  263. LOG_I("%s Grabbed %d", psGrabberParam->devname_ccap, sGrabberContext.u32FrameEnd);
  264. if (sGrabberContext.u32FrameEnd == 30)
  265. {
  266. char szFilename[64];
  267. uint32_t u32Factor = 0;
  268. LOG_I("%s Capturing %d", psGrabberParam->devname_ccap, sGrabberContext.u32FrameEnd);
  269. if (sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32PixFmt == CCAP_PAR_PLNFMT_YUV420)
  270. {
  271. u32Factor = 3;
  272. rt_snprintf(szFilename, sizeof(szFilename), "/%08d_%dx%d.yuv420p",
  273. rt_tick_get(),
  274. sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32Width,
  275. sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32Height);
  276. }
  277. else if (sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32PixFmt == CCAP_PAR_PLNFMT_YUV422)
  278. {
  279. u32Factor = 4;
  280. rt_snprintf(szFilename, sizeof(szFilename), "/%08d_%s_%dx%d.yuv422p",
  281. rt_tick_get(),
  282. psGrabberParam->devname_ccap,
  283. sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32Width,
  284. sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32Height);
  285. }
  286. if (u32Factor > 0)
  287. {
  288. /* Save YUV422 or YUV420 frame from packet pipe*/
  289. ccap_save_frame(szFilename, (const void *)sGrabberContext.sCcapConfig.sPipeInfo_Planar.pu8FarmAddr, sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32Width * sGrabberContext.sCcapConfig.sPipeInfo_Planar.u32Height * u32Factor / 2);
  290. }
  291. /* Save RGB565 frame from packet pipe*/
  292. rt_snprintf(szFilename, sizeof(szFilename), "/%08d_%s_%dx%d.rgb565",
  293. rt_tick_get(),
  294. psGrabberParam->devname_ccap,
  295. sGrabberContext.sCcapConfig.sPipeInfo_Packet.u32Width,
  296. sGrabberContext.sCcapConfig.sPipeInfo_Packet.u32Height);
  297. ccap_save_frame(szFilename, (const void *)sGrabberContext.sCcapConfig.sPipeInfo_Packet.pu8FarmAddr, sGrabberContext.sCcapConfig.sPipeInfo_Packet.u32Width * sGrabberContext.sCcapConfig.sPipeInfo_Packet.u32Height * 2);
  298. break;
  299. }
  300. }
  301. exit_ccap_grabber:
  302. ccap_sensor_fini(rt_device_find(psGrabberParam->devname_ccap), rt_device_find(psGrabberParam->devname_sensor));
  303. return;
  304. }
  305. static void ccap_grabber_create(ccap_grabber_param_t psGrabberParam)
  306. {
  307. rt_thread_t ccap_thread = rt_thread_find(psGrabberParam->thread_name);
  308. if (ccap_thread == RT_NULL)
  309. {
  310. ccap_thread = rt_thread_create(psGrabberParam->thread_name,
  311. ccap_grabber,
  312. psGrabberParam,
  313. THREAD_STACK_SIZE,
  314. THREAD_PRIORITY,
  315. THREAD_TIMESLICE);
  316. if (ccap_thread != RT_NULL)
  317. rt_thread_startup(ccap_thread);
  318. }
  319. }
  320. int ccap_saver(void)
  321. {
  322. #if defined(BSP_USING_CCAP0)
  323. static ccap_grabber_param ccap0_grabber_param = {"grab0", "ccap0", "sensor0"};
  324. ccap_grabber_create(&ccap0_grabber_param);
  325. #endif
  326. #if defined(BSP_USING_CCAP1)
  327. static ccap_grabber_param ccap1_grabber_param = {"grab1", "ccap1", "sensor1"};
  328. ccap_grabber_create(&ccap1_grabber_param);
  329. #endif
  330. return 0;
  331. }
  332. MSH_CMD_EXPORT(ccap_saver, camera saver demo);
  333. #endif