1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <sys/ioctl.h>
5
6 #include "HaasLog.h"
7 #include "ak_common.h"
8 #include "ak_common_video.h"
9 #include "ak_log.h"
10 #include "ak_mem.h"
11 #include "ak_thread.h"
12 #include "ak_venc.h"
13 #include "ak_vi.h"
14 #include "ak_vpss.h"
15 #include "camera_ioctl.h"
16 #include "dev_info.h"
17 #include "minIni.h"
18 #include "os_drv.h"
19 #include "py/mperrno.h"
20 #include "py/mphal.h"
21 #include "py/nlr.h"
22 #include "py/objlist.h"
23 #include "py/objstr.h"
24 #include "py/runtime.h"
25 #include "py/runtime0.h"
26 #include "py/stream.h"
27 #include "usb_s_uvc_ioctl.h"
28 #include "videocommon.h"
29
30 #define ISP_USE_DMA (0)
31 #define ISP_CFG_FILE "/etc/config/anyka_app.ini"
32
33 struct camera_ctx_t {
34 int main_width;
35 int main_height;
36 int sub_width;
37 int sub_height;
38 int media_type;
39 int codec;
40 };
41
42 static struct camera_ctx_t cctx = {
43 .main_width = CAMERA_MAIN_CHN_DEFAULT_WIDTH,
44 .main_height = CAMERA_MAIN_CHN_DEFAULT_HEIGHT,
45 .sub_width = CAMERA_SUB_CHN_DEFAULT_WIDTH,
46 .sub_height = CAMERA_SUB_CHN_DEFAULT_HEIGHT,
47 .codec = -1,
48 .media_type = VIDEO_MEDIA_TYPE_YUV,
49 };
50
51 #if ISP_USE_DMA
dma_pool_init(void)52 static int dma_pool_init(void)
53 {
54 int vi_dma_size = 14336; // 18406, unit in KB
55 int venc_dma_size = 12288; // 12000, unit in KB
56 int osd_dma_size = 300 << 10;
57
58 ak_mem_dma_pool_create(MODULE_ID_VI,
59 vi_dma_size << 10); /* 300KB left for OSD and audio*/
60 ak_mem_dma_pool_create(MODULE_ID_VENC, venc_dma_size << 10);
61 ak_mem_dma_pool_create(MODULE_ID_OSD, osd_dma_size);
62 ak_mem_dma_pool_activate();
63
64 return 0;
65 }
66 #endif
67
get_isp_cfg_path(int dev,char * buf,int size)68 static int get_isp_cfg_path(int dev, char *buf, int size)
69 {
70 if (dev) {
71 ini_gets("isp_cfg", "isp_path_b", 0, buf, size, ISP_CFG_FILE);
72 } else {
73 ini_gets("isp_cfg", "isp_path_a", 0, buf, size, ISP_CFG_FILE);
74 }
75
76 return 0;
77 }
78
get_isp_ae_init_para(struct vpss_isp_ae_init_info * ae_init_info)79 static int get_isp_ae_init_para(struct vpss_isp_ae_init_info *ae_init_info)
80 {
81 ae_init_info->d_gain = ini_getl("isp_cfg", "d_gain", 0, ISP_CFG_FILE);
82 ae_init_info->a_gain = ini_getl("isp_cfg", "a_gain", 0, ISP_CFG_FILE);
83 ae_init_info->exp_time = ini_getl("isp_cfg", "exp_time", 0, ISP_CFG_FILE);
84 ae_init_info->isp_d_gain =
85 ini_getl("isp_cfg", "isp_d_gain", 0, ISP_CFG_FILE);
86
87 return 0;
88 }
89
camera_set_ircut(int fd,int status_level)90 static int camera_set_ircut(int fd, int status_level)
91 {
92 int ret = 0;
93 int mode = IRCUT_MODE_DAY;
94 int feed_status = CAMERA_IRFEED_GPIO_STATUS_DAY;
95
96 if (status_level != 0) {
97 feed_status = CAMERA_IRFEED_GPIO_STATUS_NIGHT;
98 mode = IRCUT_MODE_NIGHT;
99 }
100
101 ret |= ioctl(fd, IO_CAMERA_IRCUT_GPIO_SET, &mode);
102 ret |= ioctl(fd, IO_CAMERA_IRFEED_GPIO_SET, &feed_status);
103
104 return ret;
105 }
106
vi_para_init(int camera_idx,int frame_rate)107 static int vi_para_init(int camera_idx, int frame_rate)
108 {
109 int ircut_level = 0; // 0:day, 1:night
110 enum ak_vi_daynight_mode mode = VI_MODE_DAY_OUTDOOR;
111 int frame_depth = 2;
112 int data_type = VI_DATA_TYPE_YUV420SP;
113
114 if (cctx.media_type == VIDEO_MEDIA_TYPE_YUV) {
115 data_type = VI_DATA_TYPE_YUV420P;
116 }
117
118 /*
119 * step 1: open video input device
120 */
121 if (ak_vi_open(camera_idx) != 0) {
122 LOG_E("%s, open vi dev(%d) fail\n", __func__, camera_idx);
123 return -1;
124 }
125
126 #if !QUICK_START
127 /*
128 * step 2: load isp config
129 */
130 char isp_cfg_path[128];
131 if (get_isp_cfg_path(camera_idx, isp_cfg_path, sizeof(isp_cfg_path)) != 0) {
132 LOG_E("%s, get dev(%d) isp cfg fail\n", __func__, camera_idx);
133 ak_vi_close(camera_idx);
134 return -1;
135 }
136 if (ak_vi_load_sensor_cfg(camera_idx, isp_cfg_path) != 0) {
137 LOG_E("%s, load vi dev(%d) sensor cfg fail\n", __func__, camera_idx);
138 ak_vi_close(camera_idx);
139 return -1;
140 }
141
142 // get ae info from sensor
143 struct vpss_isp_ae_init_info ae_init_info;
144 ak_vpss_get_sensor_ae_info(camera_idx, &ae_init_info);
145 if (ae_init_info.exp_time == 0) {
146 // load init ae info
147 get_isp_ae_init_para(&ae_init_info);
148 }
149 // set ae info to isp
150 ak_vpss_set_ae_init_info(camera_idx, &ae_init_info);
151
152 /*
153 * step 3: set isp work mode
154 */
155 if (mode == VI_MODE_NIGHTTIME) {
156 ircut_level = 1;
157 }
158
159 const char *ircut_dev[2] = { "/dev/ircut", "/dev/ircut1" };
160 int fd = open(ircut_dev[camera_idx], O_RDWR);
161 camera_set_ircut(fd, ircut_level);
162 close(fd);
163 ak_vi_switch_mode(camera_idx, mode);
164 #endif
165
166 /*
167 * step 4: get sensor support max resolution
168 */
169 RECTANGLE_S res; // max sensor resolution
170 if (ak_vi_get_sensor_resolution(camera_idx, &res) != 0) {
171 LOG_E("%s, get vi dev(%d) sensor resolution fail\n", __func__,
172 camera_idx);
173 ak_vi_close(camera_idx);
174 return -1;
175 }
176
177 /*
178 * step 5: set vi working parameters
179 * default parameters: 20fps, day mode, auto frame-control
180 */
181 VI_DEV_ATTR dev_attr;
182 memset(&dev_attr, 0, sizeof(dev_attr));
183 dev_attr.dev_id = camera_idx;
184 dev_attr.crop.left = 0;
185 dev_attr.crop.top = 0;
186 dev_attr.crop.width = res.width;
187 dev_attr.crop.height = res.height;
188 dev_attr.max_width = cctx.main_width;
189 dev_attr.max_height = cctx.main_height;
190 dev_attr.data_type = data_type;
191 dev_attr.sub_max_width = cctx.sub_width;
192 dev_attr.sub_max_height = cctx.sub_height;
193 dev_attr.frame_rate = frame_rate;
194
195 if (ak_vi_set_dev_attr(camera_idx, &dev_attr) != 0) {
196 LOG_E("%s, set vi dev(%d) dev attr fail\n", __func__, camera_idx);
197 ak_vi_close(camera_idx);
198 return -1;
199 }
200
201 /*
202 * step 5: set channel attribute
203 */
204 // ak_print_normal_ex(MODULE_ID_VI, "vi device set main channel\n");
205 VI_CHN_ATTR chn_attr;
206 memset(&chn_attr, 0, sizeof(chn_attr));
207 chn_attr.chn_id = VIDEO_CHN0;
208 chn_attr.res.width = cctx.main_width;
209 chn_attr.res.height = cctx.main_height;
210 chn_attr.frame_depth = frame_depth;
211 chn_attr.frame_rate = frame_rate;
212 if (ak_vi_set_chn_attr(VIDEO_CHN0, &chn_attr) != 0) {
213 LOG_E("%s, set vi dev(%d) chn0 attr fail\n", __func__, camera_idx);
214 ak_vi_close(camera_idx);
215 return -1;
216 }
217
218 memset(&chn_attr, 0, sizeof(chn_attr));
219 chn_attr.chn_id = VIDEO_CHN1;
220 chn_attr.res.width = cctx.sub_width;
221 chn_attr.res.height = cctx.sub_height;
222 chn_attr.frame_depth = frame_depth;
223 chn_attr.frame_rate = frame_rate;
224 if (ak_vi_set_chn_attr(VIDEO_CHN1, &chn_attr) != 0) {
225 LOG_E("%s, set vi dev(%d) chn1 attr fail\n", __func__, camera_idx);
226 ak_vi_close(camera_idx);
227 return -1;
228 }
229
230 /*
231 * step 6: enable vi channel
232 */
233 if (ak_vi_enable_chn(VIDEO_CHN0) != 0) {
234 LOG_E("%s, enable vi dev(%d) chn0 attr fail\n", __func__, camera_idx);
235 ak_vi_close(camera_idx);
236 return -1;
237 }
238
239 if (ak_vi_enable_chn(VIDEO_CHN1) != 0) {
240 LOG_E("%s, enable vi dev(%d) chn1 attr fail\n", __func__, camera_idx);
241 ak_vi_disable_chn(VIDEO_CHN0);
242 ak_vi_close(camera_idx);
243 return -1;
244 }
245
246 return 0;
247 }
248
py_video_camera_open(int camera_idx,int frame_rate)249 int py_video_camera_open(int camera_idx, int frame_rate)
250 {
251 do {
252 cctx.codec = -1;
253 sdk_run_config config;
254 memset(&config, 0, sizeof(config));
255 config.mem_trace_flag = SDK_RUN_NORMAL;
256
257 if (ak_sdk_init(&config) != 0)
258 break;
259
260 /* LOG_LEVEL_NORMAL for debug */
261 // ak_print_set_level(MODULE_ID_ALL, LOG_LEVEL_ERROR);
262 // ak_print_set_syslog_level(MODULE_ID_ALL, LOG_LEVEL_ERROR);
263 ak_print_set_level(MODULE_ID_ALL, LOG_LEVEL_NORMAL);
264 ak_print_set_syslog_level(MODULE_ID_ALL, LOG_LEVEL_NORMAL);
265
266 #if ISP_USE_DMA
267 dma_pool_init();
268 #endif
269
270 if (vi_para_init(camera_idx, frame_rate) != 0)
271 break;
272
273 if (ak_vi_enable_dev(camera_idx) != 0) {
274 ak_vi_disable_chn(VIDEO_CHN0);
275 ak_vi_disable_chn(VIDEO_CHN1);
276 ak_vi_close(camera_idx);
277 LOG_E("%s, enable vi dev(%d) fail\n", __func__, camera_idx);
278 break;
279 }
280
281 return 0;
282
283 } while (0);
284
285 /* process failure of sdk */
286 #if ISP_USE_DMA
287 ak_mem_dma_pool_exit();
288 #endif
289 ak_sdk_exit();
290
291 return -1;
292 }
293
py_video_camera_close(int camera_idx)294 int py_video_camera_close(int camera_idx)
295 {
296 ak_vi_disable_chn(VIDEO_CHN0);
297 ak_vi_disable_chn(VIDEO_CHN1);
298 ak_vi_disable_dev(camera_idx);
299 ak_vi_close(camera_idx);
300 #if ISP_USE_DMA
301 ak_mem_dma_pool_exit();
302 #endif
303 if (cctx.codec >= 0) {
304 ak_venc_close(cctx.codec);
305 cctx.codec = -1;
306 }
307 ak_sdk_exit();
308
309 return 0;
310 }
311
py_video_camera_frame_get(isp_frame_t * frame)312 int py_video_camera_frame_get(isp_frame_t *frame)
313 {
314 if (ak_vi_get_frame(VIDEO_CHN0, frame) != 0) {
315 LOG_E("%s, get frame fail\n", __func__);
316 return -1;
317 }
318
319 return 0;
320 }
321
py_video_camera_frame_release(isp_frame_t * frame)322 int py_video_camera_frame_release(isp_frame_t *frame)
323 {
324 ak_vi_release_frame(VIDEO_CHN0, frame);
325 return 0;
326 }
327
save_data(const char * path,const char * extension,char * buf,unsigned int len)328 static int save_data(const char *path, const char *extension, char *buf,
329 unsigned int len)
330 {
331 FILE *fd = NULL;
332 struct ak_date date;
333 char time_str[32] = { 0 };
334 char file_path[64] = { 0 };
335
336 /* construct file name */
337 ak_get_localdate(&date);
338 ak_date_to_string(&date, time_str);
339 snprintf(file_path, sizeof(file_path), "/mnt/sdcard/%s_%s.%s", path,
340 time_str, extension);
341
342 /*
343 * open appointed file to save YUV data
344 * save main channel yuv here
345 */
346 fd = fopen(file_path, "wb+");
347 if (fd == NULL) {
348 LOG_E("%s, save file fail, fd:%d\n", __func__, fd);
349 return -1;
350 }
351
352 do {
353 len -= fwrite(buf, 1, len, fd);
354 } while (len != 0);
355
356 fclose(fd);
357
358 return 0;
359 }
360
py_video_camera_config_set(int width,int height,int media_type)361 int py_video_camera_config_set(int width, int height, int media_type)
362 {
363 int ret = 0;
364
365 if (cctx.media_type != media_type) {
366 cctx.media_type = media_type;
367 ret = 1;
368 }
369
370 if (height != 0 && cctx.main_height != height) {
371 cctx.main_height = height;
372 ret = 1;
373 }
374
375 if (width != 0 && cctx.main_width != width) {
376 cctx.main_width = width;
377 ret = 1;
378 }
379
380 return ret;
381 }
382
py_video_camera_config_get(int * width,int * height,int * media_type)383 int py_video_camera_config_get(int *width, int *height, int *media_type)
384 {
385 if (width)
386 *width = cctx.main_width;
387 if (height)
388 *height = cctx.main_height;
389 if (media_type)
390 *media_type = cctx.media_type;
391
392 return 0;
393 }
394
py_video_camera_save(isp_frame_t * frame,int pic_type,const char * path)395 int py_video_camera_save(isp_frame_t *frame, int pic_type, const char *path)
396 {
397 int ret;
398
399 if (pic_type != VIDEO_MEDIA_TYPE_YUV) {
400 struct video_stream video_str;
401 if (cctx.codec < 0) {
402 cctx.codec =
403 py_venc_init(cctx.main_width, cctx.main_height, 1, pic_type);
404 if (cctx.codec < 0) {
405 LOG_E("%s, open venc fail, fd:%d\n", __func__, cctx.codec);
406 return -1;
407 ;
408 }
409 }
410
411 memset(&video_str, 0, sizeof(video_str));
412 ret = ak_venc_encode_frame(cctx.codec, frame->vi_frame.data,
413 frame->vi_frame.len, NULL, &video_str);
414 if (ret) {
415 ak_venc_close(cctx.codec);
416 cctx.codec = -1;
417 LOG_E("%s, encode fail, ret:%d\n", __func__, ret);
418 return -1;
419 }
420 ret = save_data(path, "jpg", video_str.data, video_str.len);
421 ak_venc_release_stream(cctx.codec, &video_str);
422 } else {
423 ret = save_data(path, "yuv", frame->vi_frame.data, frame->vi_frame.len);
424 }
425
426 return ret;
427 }