xref: /OK3568_Linux_fs/external/camera_engine_rkaiq/rkaiq_3A_server/rkaiq_3A_server.cpp (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <getopt.h> /* getopt_long() */
5 #include <fcntl.h> /* low-level i/o */
6 #include <inttypes.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <sys/ioctl.h>
10 #include <pthread.h>
11 
12 #include <linux/videodev2.h>
13 #include "uAPI2/rk_aiq_user_api2_sysctl.h"
14 #include "common/mediactl/mediactl.h"
15 
16 #define CLEAR(x) memset(&(x), 0, sizeof(x))
17 #define DBG(...) do { if(!silent) printf("DBG: " __VA_ARGS__);} while(0)
18 #define ERR(...) do { fprintf(stderr, "ERR: " __VA_ARGS__); } while (0)
19 
20 
21 /* Private v4l2 event */
22 #define CIFISP_V4L2_EVENT_STREAM_START  \
23                     (V4L2_EVENT_PRIVATE_START + 1)
24 #define CIFISP_V4L2_EVENT_STREAM_STOP   \
25                     (V4L2_EVENT_PRIVATE_START + 2)
26 
27 #define RKAIQ_FILE_PATH_LEN                       64
28 #define RKAIQ_FLASH_NUM_MAX                       2
29 
30 /* 1 vicap + 2 mipi + 1 bridge + 1 redundance */
31 #define MAX_MEDIA_NODES                           16
32 
33 #define IQ_PATH "/etc/iqfiles/"
34 
35 static int silent = 0;
36 static int width = 2688;
37 static int height = 1520;
38 static int has_mul_cam = 0;
39 
40 struct rkaiq_media_info {
41     char sd_isp_path[RKAIQ_FILE_PATH_LEN];
42     char vd_params_path[RKAIQ_FILE_PATH_LEN];
43     char vd_stats_path[RKAIQ_FILE_PATH_LEN];
44     char mainpath[RKAIQ_FILE_PATH_LEN];
45     char sensor_entity_name[32];
46 
47     char mdev_path[32];
48     int available;
49     rk_aiq_sys_ctx_t* aiq_ctx;
50 
51     pthread_t pid;
52 };
53 
54 static struct rkaiq_media_info media_infos[MAX_MEDIA_NODES];
55 
errno_exit(const char * s)56 static void errno_exit(const char *s)
57 {
58     ERR("%s error %d, %s\n", s, errno, strerror(errno));
59     exit(EXIT_FAILURE);
60 }
61 
xioctl(int fh,int request,void * arg)62 static int xioctl(int fh, int request, void *arg)
63 {
64     int r;
65 
66     do {
67         r = ioctl(fh, request, arg);
68     } while (-1 == r && EINTR == errno);
69 
70     return r;
71 }
72 
73 
rkaiq_get_devname(struct media_device * device,const char * name,char * dev_name)74 static int rkaiq_get_devname(struct media_device *device, const char *name, char *dev_name)
75 {
76     const char *devname;
77     struct media_entity *entity =  NULL;
78 
79     entity = media_get_entity_by_name(device, name, strlen(name));
80     if (!entity)
81         return -1;
82 
83     devname = media_entity_get_devname(entity);
84 
85     if (!devname) {
86         fprintf(stderr, "can't find %s device path!", name);
87         return -1;
88     }
89 
90     strncpy(dev_name, devname, RKAIQ_FILE_PATH_LEN);
91 
92     DBG("get %s devname: %s\n", name, dev_name);
93 
94     return 0;
95 }
96 
rkaiq_get_media_info(struct rkaiq_media_info * media_info)97 int rkaiq_get_media_info(struct rkaiq_media_info *media_info)
98 {
99     struct media_device *device = NULL;
100     const char *sensor_name;
101     int ret;
102 
103     device = media_device_new (media_info->mdev_path);
104     if (!device)
105         return -ENOMEM;
106     /* Enumerate entities, pads and links. */
107     ret = media_device_enumerate (device);
108     if (ret)
109         return ret;
110     if (!ret) {
111         /* Try rkisp */
112         ret = rkaiq_get_devname(device, "rkisp-isp-subdev",
113                                 media_info->sd_isp_path);
114         ret |= rkaiq_get_devname(device, "rkisp-input-params",
115                                 media_info->vd_params_path);
116         ret |= rkaiq_get_devname(device, "rkisp-statistics",
117                                 media_info->vd_stats_path);
118         ret |= rkaiq_get_devname(device, "rkisp_mainpath",
119                                 media_info->mainpath);
120     }
121     if (ret) {
122         fprintf(stderr, "Cound not find rkisp dev names, skipped %s\n", media_info->mdev_path);
123         media_device_unref (device);
124         return ret;
125     }
126 
127     sensor_name = rk_aiq_uapi2_sysctl_getBindedSnsEntNmByVd(media_info->mainpath);
128     if (sensor_name == NULL || strlen(sensor_name) == 0) {
129         fprintf(stderr, "ERR: No sensor attached to %s\n", media_info->mdev_path);
130         media_device_unref (device);
131         return -EINVAL;
132     }
133 
134     strcpy(media_info->sensor_entity_name, sensor_name);
135 
136     media_device_unref (device);
137 
138     return ret;
139 }
140 
init_engine(struct rkaiq_media_info * media_info)141 static void init_engine(struct rkaiq_media_info *media_info)
142 {
143     int index;
144 
145     media_info->aiq_ctx = rk_aiq_uapi2_sysctl_init(media_info->sensor_entity_name,
146                                                   IQ_PATH, NULL, NULL);
147     if (has_mul_cam)
148         rk_aiq_uapi2_sysctl_setMulCamConc(media_info->aiq_ctx, 1);
149 
150     if (rk_aiq_uapi2_sysctl_prepare(media_info->aiq_ctx,
151             width, height, RK_AIQ_WORKING_MODE_NORMAL)) {
152         ERR("rkaiq engine prepare failed !\n");
153         exit(-1);
154     }
155 }
156 
start_engine(struct rkaiq_media_info * media_info)157 static void start_engine(struct rkaiq_media_info *media_info)
158 {
159     DBG("device manager start\n");
160     rk_aiq_uapi2_sysctl_start(media_info->aiq_ctx);
161     if (media_info->aiq_ctx == NULL) {
162         ERR("rkisp_init engine failed\n");
163         exit(-1);
164     } else {
165         DBG("rkisp_init engine succeed\n");
166     }
167 }
168 
stop_engine(struct rkaiq_media_info * media_info)169 static void stop_engine(struct rkaiq_media_info *media_info)
170 {
171     rk_aiq_uapi2_sysctl_stop(media_info->aiq_ctx, false);
172 }
173 
deinit_engine(struct rkaiq_media_info * media_info)174 static void deinit_engine(struct rkaiq_media_info *media_info)
175 {
176     rk_aiq_uapi2_sysctl_deinit(media_info->aiq_ctx);
177 }
178 
179 // blocked func
wait_stream_event(int fd,unsigned int event_type,int time_out_ms)180 static int wait_stream_event(int fd, unsigned int event_type, int time_out_ms)
181 {
182     int ret;
183     struct v4l2_event event;
184 
185     CLEAR(event);
186 
187     do {
188         /*
189          * xioctl instead of poll.
190          * Since poll() cannot wait for input before stream on,
191          * it will return an error directly. So, use ioctl to
192          * dequeue event and block until sucess.
193          */
194         ret = xioctl(fd, VIDIOC_DQEVENT, &event);
195         if (ret == 0 && event.type == event_type)
196             return 0;
197     } while (true);
198 
199     return -1;
200 
201 }
202 
subscrible_stream_event(struct rkaiq_media_info * media_info,int fd,bool subs)203 static int subscrible_stream_event(struct rkaiq_media_info *media_info, int fd, bool subs)
204 {
205     struct v4l2_event_subscription sub;
206     int ret = 0;
207 
208     CLEAR(sub);
209     sub.type = CIFISP_V4L2_EVENT_STREAM_START;
210     ret = xioctl(fd,
211                  subs ? VIDIOC_SUBSCRIBE_EVENT : VIDIOC_UNSUBSCRIBE_EVENT,
212                  &sub);
213     if (ret) {
214         ERR("can't subscribe %s start event!\n", media_info->vd_params_path);
215         exit(EXIT_FAILURE);
216     }
217 
218     CLEAR(sub);
219     sub.type = CIFISP_V4L2_EVENT_STREAM_STOP;
220     ret = xioctl(fd,
221                  subs ? VIDIOC_SUBSCRIBE_EVENT : VIDIOC_UNSUBSCRIBE_EVENT,
222                  &sub);
223     if (ret) {
224         ERR("can't subscribe %s stop event!\n", media_info->vd_params_path);
225     }
226 
227     DBG("subscribe events from %s success !\n", media_info->vd_params_path);
228 
229     return 0;
230 }
231 
parse_args(int argc,char ** argv)232 void parse_args(int argc, char **argv)
233 {
234    int c;
235    int digit_optind = 0;
236 
237    while (1) {
238        int this_option_optind = optind ? optind : 1;
239        int option_index = 0;
240        static struct option long_options[] = {
241            {"silent",    no_argument,       0, 's' },
242            {"help",      no_argument,       0, 'h' },
243            {0,           0,                 0,  0  }
244        };
245 
246        c = getopt_long(argc, argv, "sh", long_options, &option_index);
247        if (c == -1)
248            break;
249 
250        switch (c) {
251        case 'w':
252            width = atoi(optarg);
253            break;
254        case 'h':
255            height = atoi(optarg);
256            break;
257        case 's':
258            silent = 1;
259            break;
260        case '?':
261            ERR("Usage: %s to start 3A engine\n"
262                "         --silent,  optional, subpress debug log\n",
263                argv[0]);
264            exit(-1);
265 
266        default:
267            ERR("?? getopt returned character code %c ??\n", c);
268        }
269    }
270 }
271 
engine_thread(void * arg)272 void *engine_thread(void *arg)
273 {
274     int ret = 0;
275     int isp_fd;
276     unsigned int stream_event = -1;
277     struct rkaiq_media_info *media_info;
278 
279     media_info = (struct rkaiq_media_info *) arg;
280 
281     isp_fd = open(media_info->vd_params_path, O_RDWR);
282     if (isp_fd < 0) {
283         ERR("open %s failed %s\n", media_info->vd_params_path, strerror(errno));
284         return NULL;
285     }
286 
287     init_engine(media_info);
288     subscrible_stream_event(media_info, isp_fd, true);
289 
290     for (;;) {
291         start_engine(media_info);
292         DBG("%s: wait stream start event...\n", media_info->mdev_path);
293         wait_stream_event(isp_fd, CIFISP_V4L2_EVENT_STREAM_START, -1);
294         DBG("%s: wait stream start event success ...\n", media_info->mdev_path);
295 
296         DBG("%s: wait stream stop event...\n", media_info->mdev_path);
297         wait_stream_event(isp_fd, CIFISP_V4L2_EVENT_STREAM_STOP, -1);
298         DBG("%s: wait stream stop event success ...\n", media_info->mdev_path);
299 
300         stop_engine(media_info);
301     }
302 
303     subscrible_stream_event(media_info, isp_fd, false);
304     deinit_engine(media_info);
305     close(isp_fd);
306 
307     return NULL;
308 }
309 
main(int argc,char ** argv)310 int main(int argc, char **argv)
311 {
312     int ret, i;
313     int threads = 0;
314 
315     /* Line buffered so that printf can flash every line if redirected to
316      * no-interactive device.
317      */
318     setlinebuf(stdout);
319 
320     parse_args(argc, argv);
321 
322     for (i = 0; i < MAX_MEDIA_NODES; i++) {
323         sprintf(media_infos[i].mdev_path, "/dev/media%d", i);
324         if (rkaiq_get_media_info(&media_infos[i])) {
325             ERR("Bad media topology for: %s\n", media_infos[i].mdev_path);
326             media_infos[i].available = 0;
327             continue;
328         }
329         media_infos[i].available = 1;
330         threads++;
331     }
332 
333     if (threads > 1)
334         has_mul_cam = 1;
335 
336     for (i = 0; i < MAX_MEDIA_NODES; i++) {
337         if (!media_infos[i].available)
338             continue;
339         ret = pthread_create(&media_infos[i].pid, NULL, engine_thread, &media_infos[i]);
340         if (ret) {
341             media_infos[i].pid = 0;
342             ERR("Failed to create camera engine thread for: %s\n", media_infos[i].mdev_path);
343             errno_exit("Create thread failed");
344         }
345     }
346 
347     for (i = 0; i < MAX_MEDIA_NODES; i++) {
348         if (!media_infos[i].available || media_infos[i].pid == 0)
349             continue;
350         pthread_join(media_infos[i].pid, NULL);
351     }
352 
353     return 0;
354 }
355