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 }