initial upload
[apps/native/smart-surveillance-camera.git] / src / controller_mv.c
1  /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <glib.h>
18 #include <stdlib.h>
19 #include <mv_common.h>
20 #include <mv_surveillance.h>
21 #include "controller.h"
22 #include "controller_mv.h"
23 #include "log.h"
24
25 #define VIDEO_STREAM_ID 0
26 #define THRESHOLD_SIZE_REGION 100
27
28 struct __mv_data {
29         mv_surveillance_event_trigger_h mv_trigger_handle;
30         movement_detected_cb movement_detected_cb;
31         void *movement_detected_cb_data;
32 };
33
34 static struct __mv_data *mv_data = NULL;
35
36 static const char *__mv_err_to_str(mv_error_e err)
37 {
38         const char *err_str;
39         switch (err) {
40         case MEDIA_VISION_ERROR_NONE:
41                 err_str = "MEDIA_VISION_ERROR_NONE";
42                 break;
43         case MEDIA_VISION_ERROR_NOT_SUPPORTED:
44                 err_str = "MEDIA_VISION_ERROR_NOT_SUPPORTED";
45                 break;
46         case MEDIA_VISION_ERROR_MSG_TOO_LONG:
47                 err_str = "MEDIA_VISION_ERROR_MSG_TOO_LONG";
48                 break;
49         case MEDIA_VISION_ERROR_NO_DATA:
50                 err_str = "MEDIA_VISION_ERROR_NO_DATA";
51                 break;
52         case MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE:
53                 err_str = "MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE";
54                 break;
55         case MEDIA_VISION_ERROR_OUT_OF_MEMORY:
56                 err_str = "MEDIA_VISION_ERROR_OUT_OF_MEMORY";
57                 break;
58         case MEDIA_VISION_ERROR_INVALID_PARAMETER:
59                 err_str = "MEDIA_VISION_ERROR_INVALID_PARAMETER";
60                 break;
61         case MEDIA_VISION_ERROR_INVALID_OPERATION:
62                 err_str = "MEDIA_VISION_ERROR_INVALID_OPERATION";
63                 break;
64         case MEDIA_VISION_ERROR_PERMISSION_DENIED:
65                 err_str = "MEDIA_VISION_ERROR_PERMISSION_DENIED";
66                 break;
67         case MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT:
68                 err_str = "MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT";
69                 break;
70         case MEDIA_VISION_ERROR_INTERNAL:
71                 err_str = "MEDIA_VISION_ERROR_INTERNAL";
72                 break;
73         case MEDIA_VISION_ERROR_INVALID_DATA:
74                 err_str = "MEDIA_VISION_ERROR_INVALID_DATA";
75                 break;
76         case MEDIA_VISION_ERROR_INVALID_PATH:
77                 err_str = "MEDIA_VISION_ERROR_INVALID_PATH";
78                 break;
79         default:
80                 err_str = "Unknown Error";
81                 break;
82         }
83
84         return err_str;
85 }
86
87 static void __movement_detected_event_cb(mv_surveillance_event_trigger_h trigger, mv_source_h source, int video_stream_id, mv_surveillance_result_h event_result, void *data)
88 {
89         int ret = 0;
90         int horizontal = 0;
91         int vertical = 0;
92         int result[MV_RESULT_LENGTH_MAX] = {0, };
93         int result_count = 0;
94         int result_index = 0;
95         int valid_area_sum = 0;
96         int i;
97         size_t move_regions_num = 0;
98         mv_rectangle_s *regions = NULL;
99
100         ret_if(!trigger);
101         ret_if(!event_result);
102         ret_if(!mv_data);
103
104         ret = mv_surveillance_get_result_value(event_result, MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS, &move_regions_num);
105         retm_if(ret, "failed to mv_surveillance_get_result_value for %s - [%s]", MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS, __mv_err_to_str(ret));
106
107         regions = malloc(sizeof(mv_rectangle_s) * move_regions_num);
108         ret = mv_surveillance_get_result_value(event_result, MV_SURVEILLANCE_MOVEMENT_REGIONS, regions);
109         retm_if(ret, "failed to mv_surveillance_get_result_value for %s - [%s]", MV_SURVEILLANCE_MOVEMENT_REGIONS, __mv_err_to_str(ret));
110
111         for (i = 0; i < move_regions_num; i++) {
112                 // _D("region[%u] - position[%d x %d], witdh[%d], height[%d]", i, regions[i].point.x, regions[i].point.y, regions[i].width, regions[i].height);
113                 // _D("region[%u] - area[%d]", i, regions[i].width * regions[i].height);
114
115                 if (regions[i].width * regions[i].height < THRESHOLD_SIZE_REGION || result_count >= MV_RESULT_COUNT_MAX)
116                         continue;
117
118                 result[result_index] = regions[i].point.x * 99 / IMAGE_WIDTH;
119                 result[result_index + 1] = regions[i].point.y * 99 / IMAGE_HEIGHT;
120                 result[result_index + 2] = regions[i].width * 99 / IMAGE_WIDTH;
121                 result[result_index + 3] = regions[i].height * 99 / IMAGE_HEIGHT;
122
123                 result_count++;
124                 result_index = result_count * 4;
125
126                 valid_area_sum += regions[i].width * regions[i].height;
127         }
128
129         for (i = 0; i < move_regions_num; i++) {
130                 if (regions[i].width * regions[i].height < THRESHOLD_SIZE_REGION)
131                         continue;
132
133                 //offset 은 움직임의 중심 좌표가 화면의 중심으로 부터 얼마나 벗어났는지의 값으로 -160 ~ 160, -120 ~ 120 의 값을 갖는다.
134                 int x_offset = (regions[i].point.x + regions[i].width / 2) - (IMAGE_WIDTH / 2);
135                 int y_offset = (regions[i].point.y + regions[i].height / 2) - (IMAGE_HEIGHT / 2);
136                 int area = regions[i].width * regions[i].height;
137
138                 // offset 값에 움직임 크기의 상대값(비율)을 곱한 다음, 모두 더해서 최종 offset 값을 구한다.
139                 // 최종값의 범위는 offset 값의 범위와 같아야 한다.
140                 horizontal += (int) x_offset * area / valid_area_sum;
141                 vertical += (int) y_offset * area / valid_area_sum;
142         }
143         free(regions);
144
145         mv_data->movement_detected_cb(horizontal, vertical, result, result_count, mv_data->movement_detected_cb_data);
146 }
147
148 void controller_mv_push_source(mv_source_h source)
149 {
150         int ret = 0;
151         ret_if(!source);
152
153         ret = mv_surveillance_push_source(source, VIDEO_STREAM_ID);
154         if (ret)
155                 _E("failed to mv_surveillance_push_source() - [%s]", __mv_err_to_str(ret));
156
157         mv_destroy_source(source);
158 }
159
160 mv_source_h controller_mv_create_source(
161                 unsigned char *buffer, unsigned int size,
162                 unsigned int width, unsigned int height, mv_colorspace_e colorspace)
163 {
164         mv_source_h source = NULL;
165         int ret = 0;
166
167         retv_if(!buffer, NULL);
168
169         ret = mv_create_source(&source);
170         retvm_if(ret, NULL, "failed to mv_create_source - [%s]", __mv_err_to_str(ret));
171
172         ret = mv_source_fill_by_buffer(source, buffer, size, width, height, colorspace);
173         if (ret) {
174                 _E("failed to fill source - %d", ret);
175
176                 if (source)
177                         mv_destroy_source(source);
178
179                 return NULL;
180         }
181
182         return source;
183 }
184
185 int controller_mv_set_movement_detection_event_cb(movement_detected_cb movement_detected_cb, void *user_data)
186 {
187         int ret = 0;
188         mv_engine_config_h engine_cfg = NULL;
189
190         if (movement_detected_cb == NULL)
191                 return -1;
192
193         if (mv_data != NULL) {
194                 mv_data->movement_detected_cb = movement_detected_cb;
195                 mv_data->movement_detected_cb_data = user_data;
196                 return 0;
197         }
198
199         mv_data = malloc(sizeof(struct __mv_data));
200         if (mv_data == NULL) {
201                 _E("Failed to allocate media vision data");
202                 return -1;
203         }
204         memset(mv_data, 0, sizeof(struct __mv_data));
205
206         ret = mv_create_engine_config(&engine_cfg);
207         if (ret) {
208                 _E("failed to subsmv_create_engine_configs() - %s", __mv_err_to_str(ret));
209                 goto ERROR;
210         }
211
212         mv_engine_config_set_int_attribute(engine_cfg, MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESHOLD, 50); /* 10 is default value [0 ~ 255] */
213
214         ret = mv_surveillance_event_trigger_create(MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED, &mv_data->mv_trigger_handle);
215         if (ret) {
216                 _E("failed to mv_surveillance_event_trigger_create - [%s]", __mv_err_to_str(ret));
217                 goto ERROR;
218         }
219
220         ret = mv_surveillance_subscribe_event_trigger(mv_data->mv_trigger_handle, VIDEO_STREAM_ID, engine_cfg, __movement_detected_event_cb, mv_data);
221
222         if (ret) {
223                 _E("failed to subscribe %s - %s", MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED, __mv_err_to_str(ret));
224                 goto ERROR;
225         }
226
227         if (engine_cfg)
228                 mv_destroy_engine_config(engine_cfg);
229
230         mv_data->movement_detected_cb = movement_detected_cb;
231         mv_data->movement_detected_cb_data = user_data;
232
233         return 0;
234
235 ERROR:
236         if (engine_cfg)
237                 mv_destroy_engine_config(engine_cfg);
238
239         if (mv_data->mv_trigger_handle)
240                 mv_surveillance_event_trigger_destroy(mv_data->mv_trigger_handle);
241
242         free(mv_data);
243         mv_data = NULL;
244
245         return -1;
246 }
247
248 void controller_mv_unset_movement_detection_event_cb(void)
249 {
250         if (mv_data == NULL)
251                 return;
252
253         if (mv_data->mv_trigger_handle)
254                 mv_surveillance_event_trigger_destroy(mv_data->mv_trigger_handle);
255
256         free(mv_data);
257         mv_data = NULL;
258 }