MediaVision Surveillance feature : initial version 01/53101/3 accepted/tizen/mobile/20151204.062557 accepted/tizen/tv/20151204.062627 accepted/tizen/wearable/20151204.062657 submit/tizen/20151204.043134
authorSeokHoon Lee <andy.shlee@samsung.com>
Tue, 1 Dec 2015 07:40:12 +0000 (16:40 +0900)
committerSeokHoon Lee <andy.shlee@samsung.com>
Fri, 4 Dec 2015 02:44:41 +0000 (11:44 +0900)
Signed-off-by: SeokHoon Lee <andy.shlee@samsung.com>
Change-Id: I4f6596a891c7bda729b70bd026026c224974fdc3

40 files changed:
AUTHORS
CMakeLists.txt
doc/mediavision_doc.h
include/mv_surveillance.h [new file with mode: 0644]
include/mv_surveillance_private.h [new file with mode: 0644]
media-vision-config.json
mv_surveillance/CMakeLists.txt [new file with mode: 0644]
mv_surveillance/surveillance/CMakeLists.txt [new file with mode: 0644]
mv_surveillance/surveillance/include/EventDefs.h [new file with mode: 0644]
mv_surveillance/surveillance/include/EventManager.h [new file with mode: 0644]
mv_surveillance/surveillance/include/EventResult.h [new file with mode: 0644]
mv_surveillance/surveillance/include/EventTrigger.h [new file with mode: 0644]
mv_surveillance/surveillance/include/EventTriggerMovementDetection.h [new file with mode: 0644]
mv_surveillance/surveillance/include/EventTriggerPersonAppearance.h [new file with mode: 0644]
mv_surveillance/surveillance/include/EventTriggerPersonRecognition.h [new file with mode: 0644]
mv_surveillance/surveillance/include/HoGDetector.h [new file with mode: 0644]
mv_surveillance/surveillance/include/SurveillanceHelper.h [new file with mode: 0644]
mv_surveillance/surveillance/include/mv_absdiff.h [new file with mode: 0644]
mv_surveillance/surveillance/include/mv_apply_mask.h [new file with mode: 0644]
mv_surveillance/surveillance/include/mv_mask_buffer.h [new file with mode: 0644]
mv_surveillance/surveillance/include/mv_surveillance_open.h [new file with mode: 0644]
mv_surveillance/surveillance/src/EventManager.cpp [new file with mode: 0644]
mv_surveillance/surveillance/src/EventTrigger.cpp [new file with mode: 0644]
mv_surveillance/surveillance/src/EventTriggerMovementDetection.cpp [new file with mode: 0644]
mv_surveillance/surveillance/src/EventTriggerPersonAppearance.cpp [new file with mode: 0644]
mv_surveillance/surveillance/src/EventTriggerPersonRecognition.cpp [new file with mode: 0644]
mv_surveillance/surveillance/src/HoGDetector.cpp [new file with mode: 0644]
mv_surveillance/surveillance/src/SurveillanceHelper.cpp [new file with mode: 0644]
mv_surveillance/surveillance/src/mv_absdiff.c [new file with mode: 0644]
mv_surveillance/surveillance/src/mv_apply_mask.c [new file with mode: 0644]
mv_surveillance/surveillance/src/mv_mask_buffer.c [new file with mode: 0644]
mv_surveillance/surveillance/src/mv_surveillance_open.cpp [new file with mode: 0644]
mv_surveillance/surveillance_lic/CMakeLists.txt [new file with mode: 0644]
mv_surveillance/surveillance_lic/include/mv_surveillance_lic.h [new file with mode: 0644]
mv_surveillance/surveillance_lic/src/mv_surveillance_lic.c [new file with mode: 0644]
packaging/capi-media-vision.spec
src/mv_surveillance.c [new file with mode: 0644]
test/testsuites/CMakeLists.txt
test/testsuites/surveillance/CMakeLists.txt [new file with mode: 0644]
test/testsuites/surveillance/surveillance_test_suite.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index 14ccbda..c096057 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,4 +1,3 @@
-ByungWook Jang <bw.jang at samsung dot com>
 Tae-Young Chung <ty83.chung at samsung dot com>
 Oleg Kopysov <o.kopysov at samsung dot com>
 Ievgen Vagin <i.vagin at samsung dot com>
@@ -6,3 +5,4 @@ Anton Artyukh <a.artyukh at samsung dot com>
 Yaroslav Zatsikha <y.zatsikha at samsung dot com>
 Sergii Rudenko <s.rudenko at samsung dot com>
 SeokHoon Lee <andy.shlee at samsung dot com>
+Heechul Jeon <heechul.jeon at samsung dot com>
index 8452d0a..2ec1ac7 100644 (file)
@@ -19,6 +19,8 @@ option(MEDIA_VISION_IMAGE_LICENSE_PORT
        "Turn on building of licensed port of the image module (if OFF - open port will be built)." OFF)
 option(MEDIA_VISION_FACE_LICENSE_PORT
        "Turn on building of licensed port of the face module (if OFF - open port will be built)." OFF)
+option(MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+       "Turn on building of licensed port of the surveillance module (if OFF - open port will be built)." OFF)
 
 set(MV_COMMON_LIB_NAME "mv_common")
 set(MV_BARCODE_DETECTOR_LIB_NAME "mv_barcode_detector" CACHE STRING
@@ -29,6 +31,8 @@ set(MV_IMAGE_LIB_NAME "mv_image" CACHE STRING
        "Name of the library will be built for image module (without extension).")
 set(MV_FACE_LIB_NAME "mv_face" CACHE STRING
        "Name of the library will be built for barcode generating module (without extension).")
+set(MV_SURVEILLANCE_LIB_NAME "mv_surveillance" CACHE STRING
+       "Name of the library will be built for surveillance module (without extension).")
 
 
 SET(INC_DIR "${PROJECT_SOURCE_DIR}/include")
@@ -64,12 +68,20 @@ else()
     SET(INC_FACE "${PROJECT_SOURCE_DIR}/mv_face/face/include")
 endif()
 
+if(MEDIA_VISION_SURVEILLANCE_LICENSE_PORT)
+    add_definitions(-DMEDIA_VISION_SURVEILLANCE_LICENSE_PORT)
+    SET(INC_SURVEILLANCE "${PROJECT_SOURCE_DIR}/mv_surveillance/surveillance_lic/include")
+else()
+    SET(INC_SURVEILLANCE "${PROJECT_SOURCE_DIR}/mv_surveillance/surveillance/include")
+endif()
+
 INCLUDE_DIRECTORIES(${INC_DIR}
                     ${INC_COMMON}
                     ${INC_BARCODE_DETECTOR}
                     ${INC_BARCODE_GENERATOR}
                     ${INC_FACE}
-                    ${INC_IMAGE})
+                    ${INC_IMAGE}
+                    ${INC_SURVEILLANCE})
 
 SET(dependents "dlog capi-media-tool capi-system-info capi-appfw-application")
 SET(pc_dependents "dlog")
@@ -100,6 +112,7 @@ ADD_SUBDIRECTORY(mv_common)
 ADD_SUBDIRECTORY(mv_barcode)
 ADD_SUBDIRECTORY(mv_image)
 ADD_SUBDIRECTORY(mv_face)
+ADD_SUBDIRECTORY(mv_surveillance)
 
 aux_source_directory(src SOURCES)
 ADD_LIBRARY(${fw_name} SHARED ${SOURCES})
@@ -109,7 +122,8 @@ TARGET_LINK_LIBRARIES(${fw_name} ${MV_COMMON_LIB_NAME}
                                  ${MV_BARCODE_GENERATOR_LIB_NAME}
                                  ${MV_IMAGE_LIB_NAME}
                                  ${MV_FACE_LIB_NAME}
-                                 ${${fw_name}_LDFLAGS})
+                                 ${${fw_name}_LDFLAGS}
+                                 ${MV_SURVEILLANCE_LIB_NAME})
 
 SET_TARGET_PROPERTIES(${fw_name}
      PROPERTIES
index b7ab18d..8402b85 100644 (file)
  * * Face detection, recognition, and tracking;\n
  * * Barcode detection and generation;\n
  * * Flat Image detection, recognition and tracking;\n
- * * Flat Image features extraction.
+ * * Flat Image features extraction;\n
+ * * Surveillance: movement detection, person appearance/disappearance,
+ *   person recognition.
  *
  * @defgroup    CAPI_MEDIA_VISION_COMMON_MODULE Media Vision Common
  * @ingroup     CAPI_MEDIA_VISION_MODULE
  * @brief  Common functions and enumerations used in
  *         @ref CAPI_MEDIA_VISION_FACE_MODULE,
- *         @ref CAPI_MEDIA_VISION_IMAGE_MODULE and
+ *         @ref CAPI_MEDIA_VISION_IMAGE_MODULE,
+ *         @ref CAPI_MEDIA_VISION_SURVEILLANCE_MODULE and
  *         @ref CAPI_MEDIA_VISION_BARCODE_MODULE submodules.
  * @section CAPI_MEDIA_VISION_COMMON_MODULE_HEADER Required Header
  *      \#include <mv_common.h>
  * For QR codes it is possible to specify error correction code and encoding
  * mode (see @ref mv_barcode_qr_mode_e). Generation to file supports several
  * formats (see @ref mv_barcode_image_format_e).
+ *
+ * @defgroup    CAPI_MEDIA_VISION_SURVEILLANCE_MODULE Media Vision Surveillance
+ * @ingroup     CAPI_MEDIA_VISION_MODULE
+ * @brief Video surveillance module.
+ * @section CAPI_MEDIA_VISION_SURVEILLANCE_MODULE_HEADER Required Header
+ *      \#include <mv_surveillance.h>
+ *
+ * @section CAPI_MEDIA_VISION_SURVEILLANCE_MODULE_FEATURE Related Features
+ * This API is related with the following features:\n
+ *  - http://tizen.org/feature/vision.image_recognition\n
+ *  - http://tizen.org/feature/vision.face_recognition\n
+ *
+ * It is recommended to design feature related codes in your application for
+ * reliability.\n
+ * You can check if a device supports the related features for this API by using
+ * @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of
+ * your application.\n
+ * To ensure your application is only running on the device with specific
+ * features, please define the features in your manifest file using the manifest
+ * editor in the SDK.\n
+ * More details on featuring your application can be found from
+ * <a href="https://developer.tizen.org/development/tools/native-tools/manifest-text-editor#feature">
+ *   <b>Feature Element</b>.
+ * </a>
+ *
+ * @section CAPI_MEDIA_VISION_SURVEILLANCE_MODULE_OVERVIEW Overview
+ * @ref CAPI_MEDIA_VISION_SURVEILLANCE_MODULE provides functionality can be
+ * utilized for creation of video surveillance systems. The main idea underlying
+ * surveillance is event subscription model. By default, supported event types
+ * are described in @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES section.
+ * @ref mv_surveillance_subscribe_event_trigger() function has to be used to
+ * create subscription to the particular event trigger. Triggers are handled by
+ * @ref mv_surveillance_event_trigger_h type. Such type handlers can be created
+ * with @ref mv_surveillance_event_trigger_create() function and destroyed with
+ * @ref mv_surveillance_event_trigger_destroy() function. Once event trigger
+ * subscription is created, corresponding @ref mv_surveillance_event_occurred_cb
+ * callback will be invoked each time when event is detected, i.e. trigger is
+ * activated. @ref mv_surveillance_result_h event detection result handler will
+ * be passed to the callback together with identifier of the video stream where
+ * event was detected and @ref mv_source_h handler containing frame in which
+ * detection was performed. It is possible to retrieve specific to event type
+ * result values using @ref mv_surveillance_result_h handler. In the
+ * @ref mv_surveillance_get_result_value() function documentation can be found
+ * detailed description of result values retrieving. Following table contains
+ * general events and corresponding event detection results can be obtained by
+ * this approach:
+ * <table>
+ * <tr>
+ *     <td><b>Event</b></td>
+ *     <td><b>Event result values</b></td>
+ * </tr>
+ * <tr>
+ *     <td>@ref MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED</td>
+ *     <td>
+ *         @ref MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS;<br>
+ *         @ref MV_SURVEILLANCE_MOVEMENT_REGIONS
+ *     </td>
+ * </tr>
+ * <tr>
+ *     <td>@ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED</td>
+ *     <td>
+ *         @ref MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER;<br>
+ *         @ref MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER;<br>
+ *         @ref MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER;<br>
+ *         @ref MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS;<br>
+ *         @ref MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS;<br>
+ *         @ref MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS
+ *     </td>
+ * </tr>
+ * <tr>
+ *     <td>@ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED</td>
+ *     <td>
+ *         @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER;<br>
+ *         @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS;<br>
+ *         @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS;<br>
+ *         @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES
+ *     </td>
+ * </tr>
+ * </table>
+ * Before subscription of the event trigger with
+ * @ref mv_surveillance_subscribe_event_trigger() call it is possible to create
+ * @ref mv_engine_config_h handle and configurate following attributes:
+ * - @ref MV_SURVEILLANCE_SKIP_FRAMES_COUNT to setup number of frames will be
+     ignored by event trigger;
+ * - @ref MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESHOLD to specify sensitivity of
+ *   the @ref MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED event detection;
+ * - @ref MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH to specify the file
+ *   where face recognition model to be used for recognition is stored.
+ *
+ * Created engine config has to be used as a parameter of
+ * @ref mv_surveillance_subscribe_event_trigger() to apply the configuration. If
+ * NULL will be passed instead of valid @ref mv_engine_config_h handle, then
+ * default attribute values will be used for subsriptions.
+ * To make surveillance system work with video sequences
+ * @ref mv_surveillance_push_source() function has to
+ * be used for each frame in the sequence in the correct order. Multiple video
+ * sources can be supported by the system. To distinguish different video
+ * sources unique stream identifier has to be assigned to each subscription.
+ * Then, particular identifier can be passed as a parameter to the
+ * @ref mv_surveillance_push_source() function. After pushing the source to the
+ * surveillance system, it will notify all triggers which were subscribed to
+ * process frames coming from video stream which source has been pushed.
+ * If trigger(s) is(are) activated on the source, then corresponding callback(s)
+ * of @ref mv_surveillance_event_occurred_cb type will be called.
+ * Additionally, region where event detection will be performed by the triggers
+ * can be set with @ref mv_surveillance_set_event_trigger_roi() function and
+ * gotten with @ref mv_surveillance_get_event_trigger_roi(). ROI is specified
+ * independently for the each event trigger, so it is possible to detect events
+ * of different types in the different parts of the incoming frames.
+ * Event trigger subscription can be stopped any time using
+ * @ref mv_surveillance_unsubscribe_event_trigger() function. Additionally,
+ * @ref mv_surveillance_foreach_supported_event_type() and
+ * @ref mv_surveillance_foreach_event_result_name() functions can be found
+ * useful if it is required to obtain supported event types list or result
+ * value names list dynamically.
+ *
+ * @defgroup    CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES Media Vision Surveillance Event Types
+ * @ingroup     CAPI_MEDIA_VISION_SURVEILLANCE_MODULE
+ * @brief Event types supported by the Surveillance module.
  */
 
 #endif  /* __TIZEN_MEDIAVISION_DOC_H__ */
diff --git a/include/mv_surveillance.h b/include/mv_surveillance.h
new file mode 100644 (file)
index 0000000..f17c77b
--- /dev/null
@@ -0,0 +1,1154 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_MEDIAVISION_SURVEILLANCE_H__
+#define __TIZEN_MEDIAVISION_SURVEILLANCE_H__
+
+#include <mv_common.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @file  mv_surveillance.h
+ * @brief This file contains the Media Vision Surveillance API.
+ */
+
+/**
+ * @addtogroup CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES
+ * @{
+ */
+
+/**
+ * @brief Name of the movement detection event type.
+ * @details This is common event for a movement detection. When this event
+ *          occurs @ref mv_surveillance_result_h allowed from callback can be
+ *          used to get number of regions where movement has been detected and
+ *          their positions. Out parameters (can be accessed in the
+ *          @ref mv_surveillance_event_occurred_cb callback using
+ *          @ref mv_surveillance_get_result_value() function):
+ *          * @ref MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS - the number
+ *            of regions where movement has been detected;\n
+ *          * @ref MV_SURVEILLANCE_MOVEMENT_REGIONS - the set
+ *            of rectangular regions where movement has been detected.
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED \
+                "MV_SURVEILLANCE_EVENT_MOVEMENT_DETECTED"
+
+/**
+ * @brief Name of the event result value that contains number of regions where
+ *        movement was detected.
+ * @details This event result value can be accessed after event triggers of
+ *          @ref MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED type activation.
+ *          Result value is of @c size_t type, so has to be casted as in the
+ *          following example:
+ *          @code{.c}
+ *          void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ *                                 mv_source_h source,
+ *                                 int video_stream_id,
+ *                                 mv_surveillance_result_h event_result,
+ *                                 void *user_data)
+ *          {
+ *              const char *event_type = NULL;
+ *              int err = mv_surveillance_get_event_trigger_type(trigger,
+ *                                                               event_type);
+ *              if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ *              if (0 == strncmp(event_type,
+ *                               MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED,
+ *                               255))
+ *              {
+ *                  size_t move_regions_num = 0;
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS,
+ *                            &move_regions_num);
+ *                  if (MEDIA_VISION_ERROR_NONE != err)
+ *                      return;
+ *
+ *                  // Do something with number of regions where movement
+ *                  // was detected...
+ *              }
+ *          }
+ *          @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS \
+                "NUMBER_OF_MOVEMENT_REGIONS"
+
+/**
+ * @brief Name of the event result value that contains rectangular regions where
+ *        movement was detected.
+ * @details This event result value can be accessed after event triggers of
+ *          @ref MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED type activation.
+ *          Result value is of @a mv_rectangle_s array type, so has to be casted
+ *          as in the following example:
+ *          @code{.c}
+ *          void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ *                                 mv_source_h source,
+ *                                 int video_stream_id,
+ *                                 mv_surveillance_result_h event_result,
+ *                                 void *user_data)
+ *          {
+ *              const char *event_type = NULL;
+ *              int err = mv_surveillance_get_event_trigger_type(trigger,
+ *                                                               event_type);
+ *              if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ *              if (0 == strncmp(event_type,
+ *                               MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED,
+ *                               255))
+ *              {
+ *                  size_t move_regions_num = 0;
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS,
+ *                            &move_regions_num);
+ *
+ *                  if (MEDIA_VISION_ERROR_NONE != err || 0 == move_regions_num)
+ *                      return;
+ *
+ *                  mv_rectangle_s *regions =
+ *                            (mv_rectangle_s*)
+ *                            malloc(sizeof(mv_rectangle_s) * move_regions_num);
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_MOVEMENT_REGIONS,
+ *                            regions);
+ *
+ *                  // Do something with movement regions...
+ *
+ *                  free (regions);
+ *              }
+ *          }
+ *          @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_MOVEMENT_REGIONS "MOVEMENT_REGIONS"
+
+/**
+ * @brief Name of the person appearance/disappearance event type.
+ * @details This is common event for a person appearing (disappearing).
+ *          The result will be:
+ *          * a number of persons, which were appeared and their positions;\n
+ *          * a number of persons, which were tracked and their positions;\n
+ *          * a number of persons, which were disappeared and their last
+ *            positions.\n
+ *          For the first time when a source is loaded, a result should contain
+ *          all detected persons (detection will be made using face detection
+ *          API). Next time when the source should be loaded, the previously
+ *          detected persons will be tracked and new persons will be detected.
+ *          For the previously detected persons their locations will be updated.
+ *          Out parameters (can be accessed in the
+ *          @ref mv_surveillance_event_occurred_cb callback using
+ *          @ref mv_surveillance_get_result_value() function):
+ *          * @ref MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER - the number
+ *            of persons which were appeared;\n
+ *          * @ref MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS - the locations
+ *            of persons which were appeared;\n
+ *          * @ref MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER - the number
+ *            of persons which were tracked;\n
+ *          * @ref MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS - the locations
+ *            of persons which were tracked;\n
+ *          * @ref MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER - the number
+ *            of persons which were disappeared;\n
+ *          * @ref MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS - the locations
+ *            of persons which were disappeared.
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED \
+                "MV_SURVEILLANCE_EVENT_PERSON_APPEARED_DISAPEARED"
+
+/**
+ * @brief Name of the event result value that contains number
+ *        of persons that have been appeared.
+ * @details This event result value can be accessed after event triggers of
+ *          @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED type
+ *          activation. Result value is of @c size_t type, so has to be casted
+ *          as in the following example:
+ *          @code{.c}
+ *          void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ *                                 mv_source_h source,
+ *                                 int video_stream_id,
+ *                                 mv_surveillance_result_h event_result,
+ *                                 void *user_data)
+ *          {
+ *              const char *event_type = NULL;
+ *              int err = mv_surveillance_get_event_trigger_type(trigger,
+ *                                                               event_type);
+ *              if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ *              if (0 == strncmp(event_type,
+ *                               MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ *                               255))
+ *              {
+ *                  size_t appear_person_num = 0;
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER,
+ *                            &appear_person_num);
+ *                  if (MEDIA_VISION_ERROR_NONE != err)
+ *                      return;
+ *
+ *                  // Do something with number of appeared persons...
+ *              }
+ *          }
+ *          @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER \
+                "NUMBER_OF_APPEARED_PERSONS"
+
+/**
+ * @brief Name of the event result value that contains number
+ *        of persons that have been disappeared.
+ * @details This event result value can be accessed after event triggers of
+ *          @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED type
+ *          activation. Result value is of @c size_t type, so has to be casted
+ *          as in the following example:
+ *          @code{.c}
+ *          void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ *                                 mv_source_h source,
+ *                                 int video_stream_id,
+ *                                 mv_surveillance_result_h event_result,
+ *                                 void *user_data)
+ *          {
+ *              const char *event_type = NULL;
+ *              int err = mv_surveillance_get_event_trigger_type(trigger,
+ *                                                               event_type);
+ *              if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ *              if (0 == strncmp(event_type,
+ *                               MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ *                               255))
+ *              {
+ *                  size_t disappear_person_num = 0;
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER,
+ *                            &disappear_person_num);
+ *                  if (MEDIA_VISION_ERROR_NONE != err)
+ *                      return;
+ *
+ *                  // Do something with number of disappeared persons...
+ *              }
+ *          }
+ *          @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER \
+                "NUMBER_OF_DISAPPEARED_PERSONS"
+
+/**
+ * @brief Name of the event result value that contains number
+ *        of persons that have been tracked.
+ * @details This event result value can be accessed after event triggers of
+ *          @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED type
+ *          activation. Result value is of @c size_t type, so has to be casted
+ *          as in the following example:
+ *          @code{.c}
+ *          void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ *                                 mv_source_h source,
+ *                                 int video_stream_id,
+ *                                 mv_surveillance_result_h event_result,
+ *                                 void *user_data)
+ *          {
+ *              const char *event_type = NULL;
+ *              int err = mv_surveillance_get_event_trigger_type(trigger,
+ *                                                               event_type);
+ *              if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ *              if (0 == strncmp(event_type,
+ *                               MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ *                               255))
+ *              {
+ *                  size_t tracked_person_num = 0;
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER,
+ *                            &tracked_person_num);
+ *                  if (MEDIA_VISION_ERROR_NONE != err)
+ *                      return;
+ *
+ *                  // Do something with number of tracked persons...
+ *              }
+ *          }
+ *          @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER \
+                "NUMBER_OF_TRACKED_PERSONS"
+
+/**
+ * @brief Name of the event result value that contains a set of rectangular
+ *        locations where appearances of the persons were detected.
+ * @details This event result value can be accessed after event triggers of
+ *          @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED type
+ *          activation. Result value is of @a mv_rectangle_s array type, so has
+ *          to be casted as in the following example:
+ *          @code{.c}
+ *          void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ *                                 mv_source_h source,
+ *                                 int video_stream_id,
+ *                                 mv_surveillance_result_h event_result,
+ *                                 void *user_data)
+ *          {
+ *              const char *event_type = NULL;
+ *              int err = mv_surveillance_get_event_trigger_type(trigger,
+ *                                                               event_type);
+ *              if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ *              if (0 == strncmp(event_type,
+ *                               MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ *                               255))
+ *              {
+ *                  size_t appear_person_num = 0;
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER,
+ *                            &appear_person_num);
+ *
+ *                  if (MEDIA_VISION_ERROR_NONE != err ||
+ *                      0 == appear_person_num) return;
+ *
+ *                  mv_rectangle_s *appear_locations =
+ *                            (mv_rectangle_s*)
+ *                            malloc(sizeof(mv_rectangle_s) * appear_person_num);
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS,
+ *                            appear_locations);
+ *
+ *                  // Do something with locations where persons were
+ *                  // appeared...
+ *
+ *                  free (appear_locations);
+ *              }
+ *          }
+ *          @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS \
+                "APPEARED_PERSONS_LOCATIONS"
+
+/**
+ * @brief Name of the event result value that contains a set of rectangular
+ *        locations where disappearances of the persons were detected.
+ * @details This event result value can be accessed after event triggers of
+ *          @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED type
+ *          activation. Result value is of @a mv_rectangle_s array type, so has
+ *          to be casted as in the following example:
+ *          @code{.c}
+ *          void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ *                                 mv_source_h source,
+ *                                 int video_stream_id,
+ *                                 mv_surveillance_result_h event_result,
+ *                                 void *user_data)
+ *          {
+ *              const char *event_type = NULL;
+ *              int err = mv_surveillance_get_event_trigger_type(trigger,
+ *                                                               event_type);
+ *              if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ *              if (0 == strncmp(event_type,
+ *                               MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ *                               255))
+ *              {
+ *                  size_t disappear_person_num = 0;
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER,
+ *                            &disappear_person_num);
+ *
+ *                  if (MEDIA_VISION_ERROR_NONE != err ||
+ *                      0 == disappear_person_num) return;
+ *
+ *                  mv_rectangle_s *disappear_locations =
+ *                            (mv_rectangle_s*)
+ *                            malloc(sizeof(mv_rectangle_s) * disappear_person_num);
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS,
+ *                            disappear_locations);
+ *
+ *                  // Do something with locations where persons were
+ *                  // disappeared...
+ *
+ *                  free (disappear_locations);
+ *              }
+ *          }
+ *          @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS \
+                "DISAPPEARED_PERSONS_LOCATIONS"
+
+/**
+ * @brief Name of the event result value that contains a set of rectangular
+ *        locations where persons were tracked.
+ * @details This event result value can be accessed after event triggers of
+ *          @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED type
+ *          activation. Result value is of @a mv_rectangle_s array type, so has
+ *          to be casted as in the following example:
+ *          @code{.c}
+ *          void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ *                                 mv_source_h source,
+ *                                 int video_stream_id,
+ *                                 mv_surveillance_result_h event_result,
+ *                                 void *user_data)
+ *          {
+ *              const char *event_type = NULL;
+ *              int err = mv_surveillance_get_event_trigger_type(trigger,
+ *                                                               event_type);
+ *              if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ *              if (0 == strncmp(event_type,
+ *                               MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+ *                               255))
+ *              {
+ *                  size_t tracked_person_num = 0;
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER,
+ *                            &tracked_person_num);
+ *
+ *                  if (MEDIA_VISION_ERROR_NONE != err || 0 == tracked_person_num)
+ *                      return;
+ *
+ *                  mv_rectangle_s *track_locations =
+ *                            (mv_rectangle_s*)
+ *                            malloc(sizeof(mv_rectangle_s) * tracked_person_num);
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS,
+ *                            track_locations);
+ *
+ *                  // Do something with locations where persons were tracked...
+ *
+ *                  free (track_locations);
+ *              }
+ *          }
+ *          @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS \
+                "TRACKED_PERSONS_LOCATIONS"
+
+/**
+ * @brief Name of the person recognition event type.
+ *
+ * @details This is common event for a person recognizing. The result will be
+ *          a number of persons, which were recognized, their positions (face
+ *          locations), labels and confidences of the recognition models (see
+ *          documentation for @ref mv_face_recognize() in
+ *          @ref CAPI_MEDIA_VISION_FACE_MODULE). When one subscribes to this
+ *          event, the engine configuration must be filled by path to the saved
+ *          face recognition model. These path should be set using
+ *          @ref mv_engine_config_set_string_attribute() as attribute named
+ *          @ref MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH.
+ *          See documentation for face recognition in
+ *          @ref CAPI_MEDIA_VISION_FACE_MODULE and for engine configuration in
+ *          @ref CAPI_MEDIA_VISION_COMMON_MODULE for details. Out parameters
+ *          (can be accessed in the @ref mv_surveillance_event_occurred_cb
+ *          callback using @ref mv_surveillance_get_result_value() function):
+ *          * @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER - the number
+ *            of persons which were recognized;\n
+ *          * @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS - the locations
+ *            of persons which were recognized;\n
+ *          * @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS - the labels of
+ *            persons which were recognized;\n
+ *          * @ref MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES -
+ *            the confidences values that persons were recognized correctly.
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED \
+                "MV_SURVEILLANCE_EVENT_PERSON_RECOGNIZED"
+
+/**
+ * @brief Name of the event result value that contains number of locations where
+ *        faces were recognized.
+ * @details This event result value can be accessed after event triggers of
+ *          @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED type activation.
+ *          Result value is of @c size_t type, so has to be casted as in
+ *          the following example:
+ *          @code{.c}
+ *          void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ *                                 mv_source_h source,
+ *                                 int video_stream_id,
+ *                                 mv_surveillance_result_h event_result,
+ *                                 void *user_data)
+ *          {
+ *              const char *event_type = NULL;
+ *              int err = mv_surveillance_get_event_trigger_type(trigger,
+ *                                                               event_type);
+ *              if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ *              if (0 == strncmp(event_type,
+ *                               MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED,
+ *                               255))
+ *              {
+ *                  size_t rec_person_num = 0;
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER,
+ *                            &rec_person_num);
+ *                  if (MEDIA_VISION_ERROR_NONE != err)
+ *                      return;
+ *
+ *                  // Do something with number of recognized persons...
+ *              }
+ *          }
+ *          @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER \
+                "NUMBER_OF_PERSONS"
+
+/**
+ * @brief Name of the event result value that contains a set of rectangular
+ *        locations where person faces were recognized.
+ * @details This event result value can be accessed after event triggers of
+ *          @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED type activation.
+ *          Result value is of @a mv_rectangle_s array type, so has to be casted
+ *          as in the following example:
+ *          @code{.c}
+ *          void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ *                                 mv_source_h source,
+ *                                 int video_stream_id,
+ *                                 mv_surveillance_result_h event_result,
+ *                                 void *user_data)
+ *          {
+ *              const char *event_type = NULL;
+ *              int err = mv_surveillance_get_event_trigger_type(trigger,
+ *                                                               event_type);
+ *              if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ *              if (0 == strncmp(event_type,
+ *                               MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED,
+ *                               255))
+ *              {
+ *                  size_t rec_person_num = 0;
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER,
+ *                            &rec_person_num);
+ *                  if (MEDIA_VISION_ERROR_NONE != err || 0 == rec_person_num)
+ *                      return;
+ *
+ *                  mv_rectangle_s *locations =
+ *                            (mv_rectangle_s*)
+ *                            malloc(sizeof(mv_rectangle_s) * rec_person_num);
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS,
+ *                            locations);
+ *
+ *                  // Do something with locations...
+ *
+ *                  free (locations);
+ *              }
+ *          }
+ *          @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS \
+                "PERSONS_LOCATIONS"
+
+/**
+ * @brief Name of the event result value that contains a set of labels that
+ *        correspond to the recognized persons.
+ * @details This event result value can be accessed after event triggers of
+ *          @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED type activation.
+ *          Result value is of integers array type, so has to be casted
+ *          as in the following example:
+ *          @code{.c}
+ *          void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ *                                 mv_source_h source,
+ *                                 int video_stream_id,
+ *                                 mv_surveillance_result_h event_result,
+ *                                 void *user_data)
+ *          {
+ *              const char *event_type = NULL;
+ *              int err = mv_surveillance_get_event_trigger_type(trigger,
+ *                                                               event_type);
+ *              if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ *              if (0 == strncmp(event_type,
+ *                               MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED,
+ *                               255))
+ *              {
+ *                  size_t rec_person_num = 0;
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER,
+ *                            &rec_person_num);
+ *                  if (MEDIA_VISION_ERROR_NONE != err || 0 == rec_person_num)
+ *                      return;
+ *
+ *                  int *labels =
+ *                            (int*)malloc(sizeof(int) * rec_person_num);
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS,
+ *                            labels);
+ *
+ *                  // Do something with labels...
+ *
+ *                  free (labels);
+ *              }
+ *          }
+ *          @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS \
+                "PERSONS_LABELS"
+
+/**
+ * @brief Name of the event result value that contains a set of confidence
+ *        values that correspond to the recognized persons.
+ * @details This event result value can be accessed after event triggers of
+ *          @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED type activation.
+ *          Result value is of doubles array type, so has to be casted
+ *          as in the following example:
+ *          @code{.c}
+ *          void event_occurred_cb(mv_surveillance_event_trigger_h trigger,
+ *                                 mv_source_h source,
+ *                                 int video_stream_id,
+ *                                 mv_surveillance_result_h event_result,
+ *                                 void *user_data)
+ *          {
+ *              const char *event_type = NULL;
+ *              int err = mv_surveillance_get_event_trigger_type(trigger,
+ *                                                               event_type);
+ *              if (MEDIA_VISION_ERROR_NONE != err) return;
+ *
+ *              if (0 == strncmp(event_type,
+ *                               MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED,
+ *                               255))
+ *              {
+ *                  size_t rec_person_num = 0;
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER,
+ *                            &rec_person_num);
+ *                  if (MEDIA_VISION_ERROR_NONE != err || 0 == rec_person_num)
+ *                      return;
+ *
+ *                  double *confidences =
+ *                            (double*)malloc(sizeof(double) * rec_person_num);
+ *                  err = mv_surveillance_get_result_value(
+ *                            event_result,
+ *                            MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES,
+ *                            confidences);
+ *
+ *                  // Do something with confidences...
+ *
+ *                  free (confidences);
+ *              }
+ *          }
+ *          @endcode
+ *
+ * @since_tizen 3.0
+ */
+#define MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES \
+                "PERSONS_CONFIDENCES"
+
+/**
+ * @}
+ */
+
+/**
+ * @addtogroup CAPI_MEDIA_VISION_SURVEILLANCE_MODULE
+ * @{
+ */
+
+/**
+ * @brief Defines MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH to set face
+ *        recognition model file path. It is an attribute of the engine
+ *        configuration.
+ * @details This value HAS TO BE set in engine configuration before subscription
+ *          on @ref MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED event trigger
+ *
+ * @since_tizen 3.0
+ * @see mv_engine_config_set_string_attribute()
+ * @see mv_engine_config_get_string_attribute()
+ */
+#define MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH \
+                "MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH"
+
+/**
+ * @brief Defines MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESOLD to set movement
+ *        detection threshold. It is an attribute of the engine configuration.
+ * @details This value might be set in engine configuration before subscription
+ *          on @ref MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED event trigger
+ *          to specify sensitivity of the movement detector. This value has to
+ *          be integer in 0..255 range where 255 means that no movements will
+ *          be detected, and 0 means that all frame changes will be interpreted
+ *          as movements. Default value is 10.
+ *
+ * @since_tizen 3.0
+ * @see mv_engine_config_set_int_attribute()
+ * @see mv_engine_config_get_int_attribute()
+ */
+#define MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESHOLD \
+                "MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESHOLD"
+
+/**
+ * @brief Defines MV_SURVEILLANCE_SKIP_FRAMES_COUNT to set how many frames
+ *        will be skipped during push source. It is an attribute of the engine
+ *        configuration.
+ * @details This integer value might be set in engine configuration to specify
+ *          number of @ref mv_surveillance_push_source() function calls will be
+ *          ignored by subscription of the event trigger. Default value is 0.
+ *          It means that no frames will be skipped and all
+ *          @ref mv_surveillance_push_source() function calls will be processed.
+ *
+ * @since_tizen 3.0
+ * @see mv_engine_config_set_int_attribute()
+ * @see mv_engine_config_get_int_attribute()
+ */
+#define MV_SURVEILLANCE_SKIP_FRAMES_COUNT "MV_SURVEILLANCE_SKIP_FRAMES_COUNT"
+
+/**
+ * @brief The handle to event trigger.
+ *
+ * @since_tizen 3.0
+ * @remarks See supported event types and their descriptions in
+ *          @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ *          section.
+ *          Also the list of supported events can be obtained using
+ *          @ref mv_surveillance_foreach_supported_event_type() function
+ */
+typedef void *mv_surveillance_event_trigger_h;
+
+/**
+ * @brief The handle to event trigger activation result.
+ * @details Result is a handle to the output values which are specific for each event.
+ *          See the output values names in the event types descriptions located
+ *          in @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ *          section.
+ *          Result values can be gotten by @ref mv_surveillance_get_result_value()
+ *          function one by one in order specified in the event description (
+ *          the same order of event value names is supported by
+ *          @ref mv_surveillance_foreach_event_result_name() function).
+ *          This pointer will be destroyed when
+ *          @ref mv_surveillance_event_occurred_cb passed.
+ *
+ * @since_tizen 3.0
+ */
+typedef void *mv_surveillance_result_h;
+
+/**
+ * @brief Called when event trigger activation has been detected.
+ *
+ * @since_tizen 3.0
+ * @remarks Handle @a event_result is valid only inside callback
+ * @param [in] trigger            The event trigger handle
+ * @param [in] source             The handle to the media source
+ * @param [in] video_stream_id    The identifier of the video source where event
+ *                                has been detected
+ * @param [in] event_result       The event result passed from the
+ *                                @ref mv_surveillance_subscribe_event_trigger()
+ * @param [in] user_data          The user data passed from the
+ *                                @ref mv_surveillance_subscribe_event_trigger()
+ *                                function
+ *
+ * @pre Callback can be invoked only after
+ *      @ref mv_surveillance_subscribe_event_trigger()
+ *      was called for particular event trigger.
+ *
+ * @see mv_surveillance_subscribe_event_trigger()
+ * @see mv_surveillance_unsubscribe_event_trigger()
+ */
+typedef void (*mv_surveillance_event_occurred_cb)(
+        mv_surveillance_event_trigger_h trigger,
+        mv_source_h source,
+        int video_stream_id,
+        mv_surveillance_result_h event_result,
+        void *user_data);
+
+/**
+ * @brief Called to get the information once for each supported event type.
+ *
+ * @since_tizen 3.0
+ * @remarks Don't release memory of @a event_type
+ * @param [in] event_type    Character string containing name of the event type
+ * @param [in] user_data     The user data passed from the
+ *                           @ref mv_surveillance_foreach_supported_event_type()
+ *                           function
+ * @return @c true to continue with the next iteration of the loop, \n
+ *         otherwise @c false to break out of the loop
+ *
+ * @pre mv_surveillance_foreach_supported_event_type() will invoke this callback
+ * @see mv_surveillance_foreach_supported_event_type()
+ */
+typedef bool (*mv_surveillance_event_type_cb)(
+        const char *event_type,
+        void *user_data);
+
+/**
+ * @brief Called to get the result name from the triggered event.
+ *
+ * @since_tizen 3.0
+ * @remarks Don't release memory of @a value_name
+ * @param [in] name         Character string containing the name of value that
+ *                          can be obtained from @ref mv_surveillance_result_h
+ *                          handle by @ref mv_surveillance_get_result_value()
+ *                          function
+ * @param [in] user_data    The user data passed from the
+ *                          @ref mv_surveillance_foreach_event_result_name()
+ *                          function
+ * @return @c true to continue with the next iteration of the loop, \n
+ *         otherwise @c false to break out of the loop
+ *
+ * @pre mv_surveillance_foreach_event_result_name() will invoke this
+ *      callback
+ * @see mv_surveillance_foreach_event_result_name()
+ */
+typedef bool (*mv_surveillance_event_result_name_cb)(
+        const char *name,
+        void *user_data);
+
+/**
+ * @brief Creates surveillance event trigger handle.
+ *
+ * @since_tizen 3.0
+ * @remarks List of supported event types can be obtained by
+ *          @ref mv_surveillance_foreach_supported_event_type function
+ * @remarks You must release @a trigger by using
+ *          @ref mv_surveillance_event_trigger_destroy()
+ * @param [in]  event_type    Name of the event type to be supported by the
+ *                            @a trigger
+ * @param [out] trigger       A new handle to the event trigger
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_trigger_destroy()
+ * @see mv_surveillance_foreach_supported_event_type()
+ */
+int mv_surveillance_event_trigger_create(
+        const char *event_type,
+        mv_surveillance_event_trigger_h *trigger);
+
+/**
+ * @brief Destroys the surveillance event trigger handle and releases all its
+ *        resources.
+ *
+ * @since_tizen 3.0
+ * @param [in] trigger    The handle to the event trigger to be destroyed
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_trigger_create
+ */
+int mv_surveillance_event_trigger_destroy(
+        mv_surveillance_event_trigger_h trigger);
+
+/**
+ * @brief Gets the surveillance event trigger type as character string.
+ *
+ * @since_tizen 3.0
+ * @remarks The @a event_type should be freed using free()
+ * @param [in]  trigger       The handle to the event trigger
+ * @param [out] event_type    The pointer to the character string which will be
+ *                            filled by textual name of the event type
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre Event trigger has to be created by
+ *      @ref mv_surveillance_event_trigger_create() function
+ */
+int mv_surveillance_get_event_trigger_type(
+        mv_surveillance_event_trigger_h trigger,
+        char **event_type);
+
+/**
+ * @brief Sets ROI (Region Of Interest) to the event trigger.
+ * @details When ROI is set for the event trigger, then event check for this
+ *          @a triger will be performed only inside the polygonal region
+ *          determined by @a roi parameter.
+ *          If this method has been never called for the @a trigger, then event
+ *          will be checked for the whole input frame (event check is performed
+ *          for each @ref mv_surveillance_push_source() function call).
+ *          It is possible to change the ROI between
+ *          @ref mv_surveillance_push_source() calls.
+ *
+ * @since_tizen 3.0
+ * @param [in] trigger             The handle to the event trigger
+ * @param [in] number_of_points    The number of ROI points
+ * @param [in] roi                 The input array with ROI points
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre Event trigger has to be created by
+ *      @ref mv_surveillance_event_trigger_create() function
+ *
+ * @see mv_surveillance_event_trigger_h
+ * @see mv_surveillance_get_event_trigger_roi()
+ */
+int mv_surveillance_set_event_trigger_roi(
+        mv_surveillance_event_trigger_h trigger,
+        int number_of_points,
+        mv_point_s *roi);
+
+/**
+ * @brief Gets ROI (Region Of Interest) from the event trigger.
+ *
+ * @since_tizen 3.0
+ * @remark If @ref mv_surveillance_set_event_trigger_roi() has been never
+ *         called for @a trigger, then @a number_of_points output value will be
+ *         zero and @a roi pointer will be not changed.
+ * @param [in]  trigger             The handle to the event trigger
+ * @param [out] number_of_points    The number of ROI points
+ * @param [out] roi                 The output array with ROI points
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre Event trigger has to be created by
+ *      @ref mv_surveillance_event_trigger_create() function
+ *
+ * @post Memory for @a roi array must be released
+ *
+ * @see mv_surveillance_event_trigger_h
+ * @see mv_surveillance_set_event_trigger_roi()
+ */
+int mv_surveillance_get_event_trigger_roi(
+        mv_surveillance_event_trigger_h trigger,
+        int *number_of_points,
+        mv_point_s **roi);
+
+/**
+ * @brief Subscribes @a trigger to process sources pushed from video identified
+ *        by @a video_stream_id.
+ * @details When @a trigger is subscribed, then each time when function
+ *          @ref mv_surveillance_push_source() is called for @a video_stream_id,
+ *          event occurrence is checked. If this check is successful,
+ *          @a callback is invoked. Details on occurred event can be obtained
+ *          using @ref mv_surveillance_result_h handle from @a callback.
+ *
+ * @since_tizen 3.0
+ * @remarks Use @ref mv_surveillance_unsubscribe_event_trigger() function for
+ *          the same @a trigger and @a video_stream_id parameters to stop
+ *          subscription.
+ * @param [in] trigger            The handle to the event trigger activating
+ *                                calls of the @a callback function
+ * @param [in] video_stream_id    The identifier of the video stream for which
+ *                                event trigger activation will be checked
+ * @param [in] engine_cfg         The engine configuration of the event
+ * @param [in] callback           Callback to be called each time when event
+ *                                occurrence is detected
+ * @param [in] user_data          The user data to be passed to the @a callback
+ *                                function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @post @ref mv_surveillance_event_occurred_cb will be called each time
+ *       @a trigger is activated after @ref mv_surveillance_push_source() call
+ *
+ * @see mv_surveillance_event_trigger_h
+ * @see mv_surveillance_unsubscribe_event_trigger()
+ * @see mv_surveillance_push_source()
+ */
+int mv_surveillance_subscribe_event_trigger(
+        mv_surveillance_event_trigger_h trigger,
+        int video_stream_id,
+        mv_engine_config_h engine_cfg,
+        mv_surveillance_event_occurred_cb callback,
+        void *user_data);
+
+/**
+ * @brief Unsubscribes @a trigger from the event and stop calling @a callback.
+ *
+ * @since_tizen 3.0
+ * @remarks To start handling trigger activation use
+            @ref mv_surveillance_subscribe_event_trigger().
+ * @param [in] trigger            The handle to the event trigger for which
+ *                                subscription will be stopped
+ * @param [in] video_stream_id    The identifier of the video source for which
+ *                                subscription will be stopped
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre To stop subscription it has to be created earlier with
+ *      @ref mv_surveillance_subscribe_event_trigger() function
+ *
+ * @see mv_surveillance_event_trigger_h
+ * @see mv_surveillance_subscribe_event_trigger()
+ */
+int mv_surveillance_unsubscribe_event_trigger(
+        mv_surveillance_event_trigger_h trigger,
+        int video_stream_id);
+
+/**
+ * @brief Pushes source to the surveillance system to detect events.
+ * @details mv_surveillance_event_occurred_cb() will be called when any
+ *          subscribing event detected.
+ *
+ * @since_tizen 3.0
+ * @remarks @ref mv_surveillance_set_event_trigger_roi() function can be used
+ *          to specify the polygon region where event can be detected only
+ * @param [in] source             The handle to the media source
+ * @param [in] video_stream_id    The identifier of video stream from which
+ *                                @a source is coming
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre To receive surveillance results, some event triggers has to be
+ *      subscribed by @ref mv_surveillance_subscribe_event_trigger() function
+ *      before @ref mv_surveillance_push_source() calls
+ * @pre Before calling of this method @a source has to be correctly filled.
+ *      @ref mv_source_fill_by_media_packet(), @ref mv_source_fill_by_buffer()
+ *      functions can be used to fill @a source
+ *
+ * @see mv_surveillance_event_trigger_h
+ * @see mv_surveillance_event_occurred_cb
+ * @see mv_surveillance_subscribe_event_trigger()
+ * @see mv_surveillance_unsubscribe_event_trigger()
+ */
+int mv_surveillance_push_source(
+        mv_source_h source,
+        int video_stream_id);
+
+/**
+ * @brief Starts traversing through list of supported event types.
+ *
+ * @since_tizen 3.0
+ * @remarks Supported event types and their descriptions can be found in
+ *          @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ *          section
+ * @param [in] callback     The callback function to be called for each
+ *                          supported event type
+ * @param [in] user_data    The user data to be passed to the @a callback
+ *                          function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_type_cb
+ * @see mv_surveillance_foreach_event_result_name()
+ */
+int mv_surveillance_foreach_supported_event_type(
+        mv_surveillance_event_type_cb callback,
+        void *user_data);
+
+/**
+ * @brief Starts traversing through list of supported event result value names.
+ *
+ * @since_tizen 3.0
+ * @remarks Supported event types, event result value names and their
+ *          descriptions can be found in
+ *          @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ *          section
+ * @param [in] event_type    The name of the event type for which result value
+ *                           names will be passed to the @a callback. Can be
+ *                           set @c NULL. If set @c NULL then all supported
+ *                           event result value names will be traversed
+ * @param [in] callback      The callback function to be called for each
+ *                           supported event result value name
+ * @param [in] user_data     The user data to be passed to the @a callback
+ *                           function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_result_name_cb
+ * @see mv_surveillance_foreach_supported_event_type()
+ * @see mv_surveillance_get_result_value()
+ */
+int mv_surveillance_foreach_event_result_name(
+        const char *event_type,
+        mv_surveillance_event_result_name_cb callback,
+        void *user_data);
+
+/**
+ * @brief Gets result value.
+ * @details See the output values names in the event types descriptions located
+ *          in @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ *          section.
+ *
+ * @since_tizen 3.0
+ * @remarks The name can be obtained by
+ *          @ref mv_surveillance_foreach_event_result_name function
+ * @param [in] result        The handle to the event result
+ * @param [in] name          The name of the value to be gotten
+ * @param [in, out] value    The pointer to variable which will be filled
+ *                           by result value. To find the type of @a value
+ *                           please refer to the
+ *                           @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES
+ *                           documentation section
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre Memory for value has to be allocated
+ *
+ * @see mv_surveillance_event_trigger_h
+ * @see mv_surveillance_event_occurred_cb
+ * @see mv_surveillance_subscribe_event_trigger()
+ * @see mv_surveillance_unsubscribe_event_trigger()
+ * @see mv_surveillance_foreach_supported_event_type()
+ * @see mv_surveillance_foreach_event_result_name()
+ */
+int mv_surveillance_get_result_value(
+        mv_surveillance_result_h result,
+        const char *name,
+        void *value);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_MEDIAVISION_SURVEILLANCE_H__ */
diff --git a/include/mv_surveillance_private.h b/include/mv_surveillance_private.h
new file mode 100644 (file)
index 0000000..4dc4bad
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_MEDIAVISION_SURVEILLANCE_PRIVATE_H__
+#define __TIZEN_MEDIAVISION_SURVEILLANCE_PRIVATE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include "mv_common.h"
+
+/**
+ * @brief Event trigger structure.
+ * @details See supported event types and their descriptions in
+ *          @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ *          section.
+ *          Also the list of supported events can be obtained using
+ *          @ref mv_surveillance_foreach_supported_event_type() function
+ *
+ * @since_tizen 3.0
+ */
+typedef struct
+{
+    unsigned int trigger_id;     /**< Unique event trigger identifier */
+    const char *event_type;      /**< Type of the event */
+    int number_of_roi_points;    /**< Number of ROI (Region of interest) points */
+    mv_point_s *roi;             /**< ROI points array */
+} mv_surveillance_event_trigger_s;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_MEDIAVISION_SURVEILLANCE_PRIVATE_H__ */
index 2f0b46c..207e575 100644 (file)
             "name"  : "MV_FACE_RECOGNITION_MODEL_TYPE",
             "type"  : "integer",
             "value" : 3
+        },
+        {
+            "name"  : "MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH",
+            "type"  : "string",
+            "value" : ""
+        },
+        {
+            "name"  : "MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESHOLD",
+            "type"  : "integer",
+            "value" : 10
+        },
+        {
+            "name"  : "MV_SURVEILLANCE_SKIP_FRAMES_COUNT",
+            "type"  : "integer",
+            "value" : 0
         }
     ]
 }
diff --git a/mv_surveillance/CMakeLists.txt b/mv_surveillance/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e6a0a44
--- /dev/null
@@ -0,0 +1,8 @@
+project(mv_surveillance_port)
+cmake_minimum_required(VERSION 2.6)
+
+if(MEDIA_VISION_SURVEILLANCE_LICENSE_PORT)
+    add_subdirectory(${PROJECT_SOURCE_DIR}/surveillance_lic) # Licensed port
+else()
+    add_subdirectory(${PROJECT_SOURCE_DIR}/surveillance) # Open port
+endif()
diff --git a/mv_surveillance/surveillance/CMakeLists.txt b/mv_surveillance/surveillance/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b7b5f03
--- /dev/null
@@ -0,0 +1,26 @@
+project(${MV_SURVEILLANCE_LIB_NAME})
+cmake_minimum_required(VERSION 2.6)
+
+set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG _DEBUG)
+
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${LIB_INSTALL_DIR})
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${LIB_INSTALL_DIR})
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+include_directories("${INC_DIR}")
+include_directories("${PROJECT_SOURCE_DIR}/include")
+include_directories("${PROJECT_SOURCE_DIR}/src")
+
+file(GLOB MV_SURVEILLANCE_INC_LIST "${PROJECT_SOURCE_DIR}/include/*.h")
+file(GLOB MV_SURVEILLANCE_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.cpp"
+                                   "${PROJECT_SOURCE_DIR}/src/*.c")
+
+if(FORCED_STATIC_BUILD)
+    add_library(${PROJECT_NAME} STATIC ${MV_SURVEILLANCE_INC_LIST} ${MV_SURVEILLANCE_SRC_LIST})
+else()
+    add_library(${PROJECT_NAME} SHARED ${MV_SURVEILLANCE_INC_LIST} ${MV_SURVEILLANCE_SRC_LIST})
+endif()
+
+target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME} ${MV_FACE_LIB_NAME})
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR})
diff --git a/mv_surveillance/surveillance/include/EventDefs.h b/mv_surveillance/surveillance/include/EventDefs.h
new file mode 100644 (file)
index 0000000..9d92ade
--- /dev/null
@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_DEFS_H__
+#define __MEDIA_VISION_EVENT_DEFS_H__
+
+/**
+ * @file  EventDefs.h
+ * @brief This file contains definitions for event triggers.
+ */
+
+#include <mv_common.h>
+
+#include <string>
+#include <vector>
+#include <list>
+#include <map>
+
+#include <opencv2/opencv.hpp>
+
+namespace mediavision {
+namespace surveillance {
+
+typedef std::map<std::string, std::vector<std::string> > EventTypesMap;
+typedef EventTypesMap::iterator EventTypesMapIter;
+typedef EventTypesMap::const_iterator EventTypesMapConstIter;
+
+typedef std::vector<std::string> StringVector;
+typedef StringVector::iterator StringIter;
+typedef StringVector::const_iterator StringConstIter;
+
+typedef std::vector<int> IntVector;
+typedef IntVector::iterator IntIter;
+typedef IntVector::const_iterator IntConstIter;
+
+typedef std::vector<double> DoubleVector;
+typedef DoubleVector::iterator DoubleIter;
+typedef DoubleVector::const_iterator DoubleConstIter;
+
+typedef std::vector<mv_rectangle_s> MVRectangles;
+typedef MVRectangles::iterator MVRectanglesIter;
+typedef MVRectangles::const_iterator MVRectanglesConstIter;
+
+typedef std::vector<cv::Rect> CVRectangles;
+typedef CVRectangles::iterator CVRectanglesIter;
+typedef CVRectangles::const_iterator CVRectanglesConstIter;
+
+typedef std::vector<mv_point_s> MVPoints;
+typedef MVPoints::iterator MVPointsIter;
+typedef MVPoints::const_iterator MVPointsConstIter;
+
+typedef std::vector<cv::Point> CVPoints;
+typedef std::vector<CVPoints> Contours;
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* __MEDIA_VISION_EVENT_DEFS_H__ */
diff --git a/mv_surveillance/surveillance/include/EventManager.h b/mv_surveillance/surveillance/include/EventManager.h
new file mode 100644 (file)
index 0000000..fd13f52
--- /dev/null
@@ -0,0 +1,190 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_MANAGER_H__
+#define __MEDIA_VISION_EVENT_MANAGER_H__
+
+/**
+ * @file  EventManager.h
+ * @brief This file contains functionality for event manager.
+ */
+
+#include "EventTrigger.h"
+#include "EventDefs.h"
+
+namespace mediavision {
+namespace surveillance {
+
+class EventManager;
+
+/**
+ * @class    EventManagerDestroyer
+ * @brief    This class contains event manager destroyer functionality.
+ *
+ * @since_tizen 3.0
+ */
+class EventManagerDestroyer {
+public:
+
+       /**
+        * @brief Default destructor.
+        *
+        * @since_tizen 3.0
+        */
+       ~EventManagerDestroyer();
+
+       /**
+        * @brief Initializes pointer to EventManager which will be destroyed.
+        *
+        * @since_tizen 3.0
+        * @param [in] pointer    The pointer to EventManager which will be destroyed
+        */
+       void initialize(EventManager *pointer);
+
+private:
+
+       EventManager *__pInstance;
+};
+
+/**
+ * @class    EventManager
+ * @brief    This class contains event manager functionality.
+ *
+ * @since_tizen 3.0
+ */
+
+class EventManager {
+public:
+
+       /**
+        * @brief Gets EventManager instance.
+        *
+        * @since_tizen 3.0
+        */
+       static EventManager& getInstance();
+
+       /**
+        * @brief Registers event.
+        *
+        * @since_tizen 3.0
+        * @param [in] eventTrigger     The event trigger to be register (NULL if internal)
+        * @param [in] triggerId        Unique event trigger identifier to be register
+        * @param [in] eventType        Type of the event
+        * @param [in] videoStreamId    Video stream identificator
+        * @param [in] engineCfg        The engine configuration for event trigger
+        * @param [in] callback         The callback to be called if event will be occured
+        * @param [in] user_data        The user data to be passed to the callback function
+        * @param [in] numberOfPoints    The number of ROI points
+        * @param [in] roi               The intput array with ROI points
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       int registerEvent(
+               mv_surveillance_event_trigger_h eventTrigger,
+               long int triggerId,
+               const char *eventType,
+               int videoStreamId,
+               mv_engine_config_h engineCfg,
+               mv_surveillance_event_occurred_cb callback,
+               void *user_data,
+               int numberOfPoints,
+               mv_point_s *roi);
+
+    /**
+     * @brief Unregisters event.
+     *
+     * @since_tizen 3.0
+     * @param [in] triggerId       Unique event trigger identifier to be
+     *                             unregister
+     * @param [in] videoStreamId   Video stream identifier for which event
+     *                             will be unregistered
+     * @return @c 0 on success, otherwise a negative error value
+     */
+    int unregisterEvent(long int triggerId, int videoStreamId);
+
+       /**
+        * @brief Pushes media source to run event triggers.
+        *
+        * @since_tizen 3.0
+        * @param [in] source           The media source to be pushed
+        * @param [in] videoStreamId    The video stream identificator for media source
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       int pushSource(mv_source_h source, int videoStreamId);
+
+       /**
+        * @brief Gets supported event types.
+        *
+        * @since_tizen 3.0
+        * @param [out] eventTypes    The supported event types
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       static int getSupportedEventTypes(StringVector& eventTypes);
+
+       /**
+        * @brief Gets all supported event result value names.
+        *
+        * @since_tizen 3.0
+        * @param [out] eventResValNames    The supported event result value names
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       static int getSupportedEventResultValueNames(StringVector& eventResValNames);
+
+       /**
+        * @brief Gets supported event result value names for an event type.
+        *
+        * @since_tizen 3.0
+        * @param [in]  eventTypeName       The name of the event type to return
+        *                                  result value names for
+        * @param [out] eventResValNames    The supported event result value names
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       static int getSupportedEventResultValueNames(
+               const std::string& eventTypeName,
+               StringVector& eventResValNames);
+
+private:
+
+       EventManager();
+
+       EventManager(const EventManager&);
+
+       EventManager& operator=(EventManager&);
+
+       ~EventManager();
+
+       static void setSupportedEventTypes();
+
+    EventTriggersIter isTriggerExists(EventTrigger *trigger, int videoStreamId);
+
+       friend class EventManagerDestroyer;
+
+private:
+
+       static EventManager *__pInstance;
+
+       static EventManagerDestroyer Destroyer;
+
+       static EventTypesMap SupportedEventTypes;
+
+private:
+
+       EventTriggersMap __eventTriggers;
+};
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* __MEDIA_VISION_EVENT_MANAGER_H__ */
diff --git a/mv_surveillance/surveillance/include/EventResult.h b/mv_surveillance/surveillance/include/EventResult.h
new file mode 100644 (file)
index 0000000..7ce8f45
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_RESULT_H__
+#define __MEDIA_VISION_EVENT_RESULT_H__
+
+/**
+ * @file  EventTrigger.h
+ * @brief This file contains interface for event trigger.
+ */
+
+namespace mediavision {
+namespace surveillance {
+
+/**
+ * @class    EventResult
+ * @brief    This class contains event result interface.
+ *
+ * @since_tizen 3.0
+ */
+class EventResult {
+public:
+       /**
+        * @brief Default destructor.
+        *
+        * @since_tizen 3.0
+        */
+       virtual ~EventResult() {}
+
+       /**
+        * @brief Gets result value.
+        *
+        * @since_tizen 3.0
+        * @param [in] valueName     The name of the value to be gotten
+        * @param [in, out] value    The pointer to variable which will be filled
+        *                           by result value
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       virtual int getResultValue(const char *valueName, void *value) const = 0;
+};
+
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* _MEDIA_VISION__EVENT_RESULT_H__ */
diff --git a/mv_surveillance/surveillance/include/EventTrigger.h b/mv_surveillance/surveillance/include/EventTrigger.h
new file mode 100644 (file)
index 0000000..d585195
--- /dev/null
@@ -0,0 +1,227 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_TRIGGER_H__
+#define __MEDIA_VISION_EVENT_TRIGGER_H__
+
+/**
+ * @file  EventTrigger.h
+ * @brief This file contains interface for event trigger.
+ */
+
+#include "EventDefs.h"
+
+#include <mv_surveillance.h>
+#include <mv_surveillance_private.h>
+
+#include <string>
+#include <map>
+#include <list>
+
+namespace mediavision {
+namespace surveillance {
+
+/**
+ * @class    EventTrigger
+ * @brief    This class contains event trigger interface.
+ *
+ * @since_tizen 3.0
+ */
+class EventTrigger {
+public:
+       /**
+        * @brief Default constructor.
+        *
+        * @since_tizen 3.0
+        * @param [in] eventTrigger      The event trigger to be register (NULL if internal)
+        * @param [in] triggerId         Unique event trigger identifier to be register
+        * @param [in] videoStreamId     Video stream identifier
+        * @param [in] callback          The callback to be called if event will be occured
+        * @param [in] user_data         The user data to be passed to the callback function
+        * @param [in] numberOfPoints    The number of ROI points
+        * @param [in] roi               The intput array with ROI points
+        */
+       EventTrigger(
+               mv_surveillance_event_trigger_h eventTrigger,
+               long int triggerId,
+               int videoStreamId,
+               mv_surveillance_event_occurred_cb callback,
+               void *userData,
+               int numberOfPoints,
+               mv_point_s *roi);
+
+       /**
+        * @brief Default destructor.
+        *
+        * @since_tizen 3.0
+        */
+       virtual ~EventTrigger();
+
+       /**
+        * @brief Parses engine configuration.
+        *
+        * @since_tizen 3.0
+        * @param [in] engineConfig    The engine configuration to be parsed
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       virtual int parseEngineConfig(mv_engine_config_h engineConfig) = 0;
+
+       /**
+        * @brief Pushes media source.
+        *
+        * @since_tizen 3.0
+        * @param [in] source        The media source to be parsed
+        * @param [in] graySource    The media source converted to gray scale
+        * @param [in] grayImage     The converted to gray scale source
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       virtual int pushSource(
+                                       mv_source_h source,
+                                       mv_source_h graySource,
+                                       const cv::Mat& grayImage) = 0;
+
+       /**
+        * @brief Gets event type.
+        *
+        * @since_tizen 3.0
+        * @return string with event type
+        */
+       virtual std::string getEventType() const = 0;
+
+       /**
+        * @brief Gets video stream identifier of event trigger.
+        *
+        * @since_tizen 3.0
+        * @return video stream identifier
+        */
+       int getVideoStreamId() const;
+
+       /**
+        * @brief Checks if callback with the identifier is subscribed.
+        *
+        * @since_tizen 3.0
+        * @return true if suscribed, false otherwise
+        */
+       bool isCallbackSubscribed(long int triggerId) const;
+
+       /**
+        * @brief Subscibes callback with unique identifier.
+        *
+        * @since_tizen 3.0
+        * @param [in] eventTrigger      The event trigger to be register (NULL if internal)
+        * @param [in] triggerId         Unique event trigger identifier to be subscribed
+        * @param [in] callback          The callback to be called if event will be occured
+        * @param [in] user_data         The user data to be passed to the callback function
+        * @param [in] numberOfPoints    The number of ROI points
+        * @param [in] roi               The intput array with ROI points
+        * @return @c true on success, false otherwise
+        */
+       bool subscribeCallback(
+                       mv_surveillance_event_trigger_h eventTrigger,
+                       long int triggerId,
+                       mv_surveillance_event_occurred_cb callback,
+                       void *userData,
+                       int numberOfPoints,
+                       mv_point_s *roi);
+
+       /**
+        * @brief Unsubscibes callback with unique identifier.
+        *
+        * @since_tizen 3.0
+        * @param [in] triggerId    Unique event trigger identifier to be unsubscribed
+        * @return @c true on success, false otherwise
+        */
+       bool unsubscribeCallback(long int triggerId);
+
+       /**
+        * @brief Checks if there are no subscribed callbacks.
+        *
+        * @since_tizen 3.0
+        * @return @c true at least one callback is subscribed, false otherwise
+        */
+       bool isCallbacksEmpty() const;
+
+       /**
+        * @brief Applies ROI (Region Of Interest) to input image.
+        *
+        * @since_tizen 3.0
+        * @param [in, out] image     The input image where ROI will be applied
+        * @param [in] imageWidth     The input image width
+        * @param [in] imageHeight    The input image height
+        * @param [in] scalePoints    True if ROI points must be scaled, false oterwise
+        * @param [in] scaleX         The scale for X ROI point coordinate
+        * @param [in] scaleY         The scale for Y ROI point coordinate
+        * @return @c true on success, false otherwise
+        */
+       int applyROIToImage(
+                       unsigned char *image,
+                       int imageWidth,
+                       int imageHeight,
+                       bool scalePoints = false,
+                       int scaleX = 1,
+                       int scaleY = 1);
+
+       /**
+        * @brief Comparison operator for equal case.
+        *
+        * @since_tizen 3.0
+        * @return true if event trigger is equal to other, false otherwise
+        */
+       virtual bool operator==(const EventTrigger& other) const;
+
+       /**
+        * @brief Comparison operator for not equal case.
+        *
+        * @since_tizen 3.0
+        * @return true if event trigger is not equal to other, false otherwise
+        */
+       virtual bool operator!=(const EventTrigger& other) const;
+
+protected:
+       struct CallbackData {
+               mv_surveillance_event_trigger_h eventTrigger;
+
+               mv_surveillance_event_occurred_cb callback;
+
+               void *userData;
+       };
+
+       typedef std::map<long int, CallbackData> CallbackDataMap;
+       typedef CallbackDataMap::const_iterator CallbackDataMapConstIter;
+       typedef CallbackDataMap::iterator CallbackDataMapIter;
+
+       typedef std::pair<long int, CallbackData> CallbackDataPair;
+
+protected:
+       static long int InternalTriggersCounter;
+
+protected:
+       int __videoStreamId;
+
+       MVPoints __roi;
+
+       CallbackDataMap __callbackDataMap;
+};
+
+typedef std::list<EventTrigger*> EventTriggers;
+typedef std::map<int, EventTriggers> EventTriggersMap;
+typedef EventTriggers::const_iterator EventTriggersConstIter;
+typedef EventTriggers::iterator EventTriggersIter;
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* __MEDIA_VISION_EVENT_TRIGGER_H__ */
diff --git a/mv_surveillance/surveillance/include/EventTriggerMovementDetection.h b/mv_surveillance/surveillance/include/EventTriggerMovementDetection.h
new file mode 100644 (file)
index 0000000..e3b57a9
--- /dev/null
@@ -0,0 +1,159 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_TRIGGER_MOVEMENT_DETECTION_H__
+#define __MEDIA_VISION_EVENT_TRIGGER_MOVEMENT_DETECTION_H__
+
+/**
+ * @file  EventTriggerMovementDetection.h
+ * @brief This file contains interface for movement detection events.
+ */
+
+#include "EventTrigger.h"
+
+#include "EventResult.h"
+#include "EventDefs.h"
+
+#include <opencv/cv.h>
+
+namespace mediavision {
+namespace surveillance {
+
+/**
+ * @class EventResultMovementDetection
+ * @brief This class contains movement detection event results.
+ *
+ * @since_tizen 3.0
+ */
+class EventResultMovementDetection : public EventResult {
+public:
+       /**
+        * @brief Gets result value.
+        *
+        * @since_tizen 3.0
+        * @param [in] valueName     The name of the value to be gotten
+        * @param [in, out] value    The pointer to variable which will be filled
+        *                           by result value
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       virtual int getResultValue(const char *valueName, void *value) const;
+
+public:
+       MVRectangles __movementRegions; /**< Regions where movements were detected */
+
+       cv::Mat __grayImage; /** Current gray image (only for internal usage) */
+};
+
+/**
+ * @class EventTriggerMovementDetection
+ * @brief This class contains movement detection events.
+ *
+ * @since_tizen 3.0
+ */
+class EventTriggerMovementDetection : public EventTrigger {
+public:
+       /**
+        * @brief Default constructor.
+        *
+        * @since_tizen 3.0
+        * @param [in] eventTrigger      The event trigger to be register (NULL if internal)
+        * @param [in] triggerId         Unique event trigger identifier to be register
+        * @param [in] videoStreamId     Video stream identifier
+        * @param [in] callback          The callback to be called if event will be occured
+        * @param [in] user_data         The user data to be passed to the callback function
+        * @param [in] numberOfPoints    The number of ROI points
+        * @param [in] roi               The intput array with ROI points
+        */
+       EventTriggerMovementDetection(
+               mv_surveillance_event_trigger_h eventTrigger,
+               long int triggerId,
+               int videoStreamId,
+               mv_surveillance_event_occurred_cb callback,
+               void *userData,
+               int numberOfPoints,
+               mv_point_s *roi);
+
+       /**
+        * @brief Default destructor.
+        *
+        * @since_tizen 3.0
+        */
+       virtual ~EventTriggerMovementDetection();
+
+       /**
+        * @brief Parses engine configuration.
+        *
+        * @since_tizen 3.0
+        * @param [in] engineConfig    The engine configuration to be parsed
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       virtual int parseEngineConfig(mv_engine_config_h engineConfig);
+
+       /**
+        * @brief Pushes media source.
+        *
+        * @since_tizen 3.0
+        * @param [in] source        The media source to be parsed
+        * @param [in] graySource    The media source converted to gray scale
+        * @param [in] grayImage     The converted to gray scale source
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       virtual int pushSource(
+                                       mv_source_h source,
+                                       mv_source_h graySource,
+                                       const cv::Mat& grayImage);
+
+       /**
+        * @brief Gets event type.
+        *
+        * @since_tizen 3.0
+        * @return string with event type
+        */
+       virtual std::string getEventType() const;
+
+       /**
+        * @brief Comparison operator for equal case.
+        *
+        * @since_tizen 3.0
+        * @return true if event trigger is equal to other, false otherwise
+        */
+       virtual bool operator==(const EventTriggerMovementDetection& other) const;
+
+       /**
+        * @brief Comparison operator for not equal case.
+        *
+        * @since_tizen 3.0
+        * @return true if event trigger is not equal to other, false otherwise
+        */
+       virtual bool operator!=(const EventTriggerMovementDetection& other) const;
+
+private:
+       static const cv::Mat __ERODE_KERNEL;
+
+       static const cv::Mat __DILATE_KERNEL;
+
+private:
+       cv::Mat __previousImage;
+
+       EventResultMovementDetection *__eventResult;
+
+       int __diffThreshold;
+};
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* __MEDIA_VISION_EVENT_TRIGGER_MOVEMENT_DETECTION_H__ */
diff --git a/mv_surveillance/surveillance/include/EventTriggerPersonAppearance.h b/mv_surveillance/surveillance/include/EventTriggerPersonAppearance.h
new file mode 100644 (file)
index 0000000..7aeecff
--- /dev/null
@@ -0,0 +1,211 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_TRIGGER_PERSON_APPEARANCE_H__
+#define __MEDIA_VISION_EVENT_TRIGGER_PERSON_APPEARANCE_H__
+
+/**
+ * @file  EventTriggerPersonAppearance.h
+ * @brief This file contains interface for person appeared / disapeared events.
+ */
+
+#include "EventTrigger.h"
+
+#include "EventResult.h"
+#include "EventDefs.h"
+#include "HoGDetector.h"
+
+#include <opencv/cv.h>
+
+namespace mediavision {
+namespace surveillance {
+
+/**
+ * @class EventResultPersonAppearance
+ * @brief This class contains person appeared / disapeared event results.
+ *
+ * @since_tizen 3.0
+ */
+class EventResultPersonAppearance : public EventResult {
+public:
+       /**
+        * @brief Gets result value.
+        *
+        * @since_tizen 3.0
+        * @param [in] valueName     The name of the value to be gotten
+        * @param [in, out] value    The pointer to variable which will be filled
+        *                           by result value
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       virtual int getResultValue(const char *valueName, void *value) const;
+
+public:
+       MVRectangles __appearedLocations; /**< Locations of persons which were appeared
+                                         first time*/
+
+       MVRectangles __trackedLocations; /**< Locations of persons which were tracked
+                                        from previous frame*/
+
+       MVRectangles __disappearedLocations; /**< Locations of persons which were
+                                            disappeared */
+};
+
+/**
+ * @class EventTriggerPersonAppearance
+ * @brief This class contains person appeared / disapeared events.
+ *
+ * @since_tizen 3.0
+ */
+class EventTriggerPersonAppearance : public EventTrigger {
+public:
+       /**
+        * @brief Default constructor.
+        *
+        * @since_tizen 3.0
+        * @param [in] eventTrigger      The event trigger to be register (NULL if internal)
+        * @param [in] triggerId         Unique event trigger identifier to be register
+        * @param [in] videoStreamId     Video stream identifier
+        * @param [in] callback          The callback to be called if event will be occured
+        * @param [in] user_data         The user data to be passed to the callback function
+        * @param [in] numberOfPoints    The number of ROI points
+        * @param [in] roi               The intput array with ROI points
+        */
+       EventTriggerPersonAppearance(
+               mv_surveillance_event_trigger_h eventTrigger,
+               long int triggerId,
+               int videoStreamId,
+               mv_surveillance_event_occurred_cb callback,
+               void *userData,
+               int numberOfPoints,
+               mv_point_s *roi);
+
+       /**
+        * @brief Default destructor.
+        *
+        * @since_tizen 3.0
+        */
+       virtual ~EventTriggerPersonAppearance();
+
+       /**
+        * @brief Parses engine configuration.
+        *
+        * @since_tizen 3.0
+        * @param [in] engineConfig    The engine configuration to be parsed
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       virtual int parseEngineConfig(mv_engine_config_h engineConfig);
+
+       /**
+        * @brief Pushes media source.
+        *
+        * @since_tizen 3.0
+        * @param [in] source        The media source to be parsed
+        * @param [in] graySource    The media source converted to gray scale
+        * @param [in] grayImage     The converted to gray scale source
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       virtual int pushSource(
+                                       mv_source_h source,
+                                       mv_source_h graySource,
+                                       const cv::Mat& grayImage);
+
+       /**
+        * @brief Gets event type.
+        *
+        * @since_tizen 3.0
+        * @return string with event type
+        */
+       virtual std::string getEventType() const;
+
+       /**
+        * @brief Comparison operator for equal case.
+        *
+        * @since_tizen 3.0
+        * @return true if event trigger is equal to other, false otherwise
+        */
+       virtual bool operator==(const EventTriggerPersonAppearance& other) const;
+
+       /**
+        * @brief Comparison operator for not equal case.
+        *
+        * @since_tizen 3.0
+        * @return true if event trigger is not equal to other, false otherwise
+        */
+       virtual bool operator!=(const EventTriggerPersonAppearance& other) const;
+
+private:
+       static void movementDetectedCB(
+               mv_surveillance_event_trigger_h event_trigger,
+               mv_source_h source,
+               int video_stream_id,
+               mv_surveillance_result_h event_result,
+               void *user_data);
+
+private:
+
+       void runCallbacks(mv_source_h source);
+
+private:
+
+       struct TrackedRectangle {
+               cv::Rect rect;
+
+               int framesCount;
+
+               TrackedRectangle(cv::Rect _rect, int _framesCount)
+               {
+                       rect = _rect;
+                       framesCount = _framesCount;
+               }
+       };
+
+       typedef std::list<TrackedRectangle> TrackedRectangles;
+       typedef TrackedRectangles::const_iterator TrackedRectanglesConstIter;
+       typedef TrackedRectangles::iterator TrackedRectanglesIter;
+
+private:
+       int __skipFramesCount;
+
+       int __frameCounter; /**< Counts frames on which detection has not be launched */
+
+       long int __movementDetectedEventId;
+
+       float __factorX;
+
+       float __factorY;
+
+       cv::Rect __rectToDetect;
+
+       cv::Rect __rectToDetectPrevious;
+
+       TrackedRectangles __trackedRects;
+
+       CVRectangles __appearedRects;
+
+       CVRectangles __disappearedRects;
+
+       modifiedcv::HOGDescriptor __hogClassifier; /**< Classifier to be used for full body
+                                                                                               person detection */
+
+       MVRectangles __detectedLocations;
+
+       EventResultPersonAppearance *__eventResult;
+};
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* __MEDIA_VISION_EVENT_TRIGGER_PERSON_APPEARANCE_H__ */
diff --git a/mv_surveillance/surveillance/include/EventTriggerPersonRecognition.h b/mv_surveillance/surveillance/include/EventTriggerPersonRecognition.h
new file mode 100644 (file)
index 0000000..cd3448e
--- /dev/null
@@ -0,0 +1,192 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_EVENT_TRIGGER_PERSON_RECOGNITION_H__
+#define __MEDIA_VISION_EVENT_TRIGGER_PERSON_RECOGNITION_H__
+
+/**
+ * @file  EventTriggerPersonRecognition.h
+ * @brief This file contains interface for person recognized events.
+ */
+
+#include <mv_face.h>
+
+#include "EventTrigger.h"
+
+#include "EventResult.h"
+#include "EventDefs.h"
+
+#include "EventTriggerPersonAppearance.h"
+
+namespace mediavision {
+namespace surveillance {
+
+/**
+ * @class EventResultPersonRecogniton
+ * @brief This class contains person recognized event results.
+ *
+ * @since_tizen 3.0
+ */
+class EventResultPersonRecognition : public EventResult {
+public:
+       /**
+        * @brief Gets result value.
+        *
+        * @since_tizen 3.0
+        * @param [in] valueName     The name of the value to be gotten
+        * @param [in, out] value    The pointer to variable which will be filled
+        *                           by result value
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       virtual int getResultValue(const char *valueName, void *value) const;
+
+public:
+       MVRectangles __locations; /**< Persons locations */
+
+       IntVector __faceLabels; /**< Persons face lables */
+
+       DoubleVector __confidences; /**< Persons face recognition confidences */
+};
+
+/**
+ * @class EventTriggerPersonRecognition
+ * @brief This class contains person recognized events.
+ *
+ * @since_tizen 3.0
+ */
+class EventTriggerPersonRecognition : public EventTrigger {
+public:
+       /**
+        * @brief Default constructor.
+        *
+        * @since_tizen 3.0
+        * @param [in] eventTrigger      The event trigger to be register (NULL if internal)
+        * @param [in] triggerId         Unique event trigger identifier to be register
+        * @param [in] videoStreamId     Video stream identifier
+        * @param [in] callback          The callback to be called if event will be occured
+        * @param [in] user_data         The user data to be passed to the callback function
+        * @param [in] numberOfPoints    The number of ROI points
+        * @param [in] roi               The intput array with ROI points
+        */
+       EventTriggerPersonRecognition(
+               mv_surveillance_event_trigger_h eventTrigger,
+               long int triggerId,
+               int videoStreamId,
+               mv_surveillance_event_occurred_cb callback,
+               void *userData,
+               int numberOfPoints,
+               mv_point_s *roi);
+
+       /**
+        * @brief Default destructor.
+        *
+        * @since_tizen 3.0
+        */
+       virtual ~EventTriggerPersonRecognition();
+
+       /**
+        * @brief Parses engine configuration.
+        *
+        * @since_tizen 3.0
+        * @param [in] engineConfig    The engine configuration to be parsed
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       virtual int parseEngineConfig(mv_engine_config_h engineConfig);
+
+       /**
+        * @brief Pushes media source.
+        *
+        * @since_tizen 3.0
+        * @param [in] source        The media source to be parsed
+        * @param [in] graySource    The media source converted to gray scale
+        * @param [in] grayImage     The converted to gray scale source
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       virtual int pushSource(
+                                       mv_source_h source,
+                                       mv_source_h graySource,
+                                       const cv::Mat& grayImage);
+
+       /**
+        * @brief Gets event type.
+        *
+        * @since_tizen 3.0
+        * @return string with event type
+        */
+       virtual std::string getEventType() const;
+
+       /**
+        * @brief Comparison operator for equal case.
+        *
+        * @since_tizen 3.0
+        * @return true if event trigger is equal to other, false otherwise
+        */
+       virtual bool operator==(const EventTriggerPersonRecognition& other) const;
+
+       /**
+        * @brief Comparison operator for not equal case.
+        *
+        * @since_tizen 3.0
+        * @return true if event trigger is not equal to other, false otherwise
+        */
+       virtual bool operator!=(const EventTriggerPersonRecognition& other) const;
+
+       /**
+        * @brief Sets event results.
+        *
+        * @since_tizen 3.0
+        * @param [in] faceLocation    The location of the face recognized on @a source.
+        * @param [in] faceLabel       The label that identifies face which was
+        *                             recognized in the @a source.
+        * @param [in] confidence      The confidence of the @a recognition_model
+        *                             that face has been recognized correctly
+        *                             (value from 0.0 to 1.0).
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       void setEventResults(
+               mv_rectangle_s faceLocation,
+               int faceLabel,
+               double confidence);
+
+private:
+       mv_face_recognition_model_h __faceRecognitionModel;
+
+       mv_source_h __lastFrame;
+
+       EventResultPersonRecognition *__eventResult;
+
+private:
+       static void faceDetectedCB(
+                                       mv_source_h source,
+                                       mv_engine_config_h engine_cfg,
+                                       mv_rectangle_s *faces_locations,
+                                       int number_of_faces,
+                                       void *user_data);
+
+       static void faceRecognizedCB(
+                                       mv_source_h source,
+                                       mv_face_recognition_model_h recognition_model,
+                                       mv_engine_config_h engine_cfg,
+                                       mv_rectangle_s *face_location,
+                                       const int *face_label,
+                                       double confidence,
+                                       void *user_data);
+};
+
+} /* surveillance */
+} /* mediaVision */
+
+#endif /* __MEDIA_VISION_EVENT_TRIGGER_PERSON_RECOGNITION_H__ */
diff --git a/mv_surveillance/surveillance/include/HoGDetector.h b/mv_surveillance/surveillance/include/HoGDetector.h
new file mode 100644 (file)
index 0000000..d4bb400
--- /dev/null
@@ -0,0 +1,194 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+
+#ifndef __MEDIA_VISION_HOGDETECTOR_H__
+#define __MEDIA_VISION_HOGDETECTOR_H__
+
+/**
+ * @file  HOGDetector.h
+ * @brief This file contains structure of HOG detector.
+ */
+
+#include "opencv2/core/core.hpp"
+#include "opencv2/objdetect/objdetect.hpp"
+
+#include <vector>
+
+namespace modifiedcv {
+
+using namespace cv;
+
+struct HOGDescriptor {
+       enum { L2Hys = 0 };
+       enum { DEFAULT_NLEVELS = 64 };
+
+       // default constructor
+       HOGDescriptor() :
+               winSize(64, 128),
+               blockSize(16, 16),
+               blockStride(8, 8),
+               cellSize(8, 8),
+               nbins(9),
+               derivAperture(1),
+               winSigma(-1),
+               histogramNormType(HOGDescriptor::L2Hys),
+               L2HysThreshold(0.2),
+               gammaCorrection(true),
+               nlevels(HOGDescriptor::DEFAULT_NLEVELS)
+       {}
+
+       // constructor
+       HOGDescriptor(
+               Size _winSize,
+               Size _blockSize,
+               Size _blockStride,
+               Size _cellSize,
+               int _nbins,
+               int _derivAperture = 1,
+               double _winSigma = -1.,
+               int _histogramNormType = L2Hys,
+               double _L2HysThreshold = 0.2,
+               bool _gammaCorrection = false,
+               int _nlevels = DEFAULT_NLEVELS) :
+               winSize(_winSize),
+               blockSize(_blockSize),
+               blockStride(_blockStride),
+               cellSize(_cellSize),
+               nbins(_nbins),
+               derivAperture(_derivAperture),
+               winSigma(_winSigma),
+               histogramNormType(_histogramNormType),
+               L2HysThreshold(_L2HysThreshold),
+               gammaCorrection(_gammaCorrection),
+               nlevels(_nlevels)
+       {}
+
+       // default destructor
+       virtual ~HOGDescriptor() {}
+
+       size_t getDescriptorSize() const;
+
+       bool checkDetectorSize() const;
+
+       double getWinSigma() const;
+
+       virtual void setSVMDetector(InputArray _svmdetector);
+
+       virtual void compute(
+               const Mat& img,
+               CV_OUT vector<float>& descriptors,
+               Size winStride = Size(),
+               Size padding = Size(),
+               const vector<Point>& locations = vector<Point>()) const;
+
+       //with found weights output
+       virtual void detect(
+               const Mat& img,
+               CV_OUT vector<Point>& foundLocations,
+               CV_OUT vector<double>& weights,
+               double hitThreshold = 0.,
+               Size winStride = Size(),
+               Size padding = Size(),
+               const vector<Point>& searchLocations = vector<Point>()) const;
+
+       //without found weights output
+       virtual void detect(
+               const Mat& img,
+               CV_OUT vector<Point>& foundLocations,
+               double hitThreshold = 0.,
+               Size winStride = Size(),
+               Size padding = Size(),
+               const vector<Point>& searchLocations = vector<Point>()) const;
+
+       //with result weights output
+       virtual void detectMultiScale(
+               const Mat& img,
+               CV_OUT vector<Rect>& foundLocations,
+               CV_OUT vector<double>& foundWeights,
+               double hitThreshold = 0,
+               Size winStride = Size(),
+               Size padding = Size(),
+               double scale = 1.05,
+               double finalThreshold = 2.0,
+               bool useMeanshiftGrouping = false) const;
+
+       //without found weights output
+       virtual void detectMultiScale(
+               const Mat& img,
+               CV_OUT vector<Rect>& foundLocations,
+               double hitThreshold = 0.,
+               Size winStride = Size(),
+               Size padding = Size(),
+               double scale = 1.05,
+               double finalThreshold = 2.0,
+               bool useMeanshiftGrouping = false) const;
+
+       virtual void computeGradient(
+               const Mat& img,
+               CV_OUT Mat& grad,
+               CV_OUT Mat& angleOfs,
+               Size paddingTL = Size(),
+               Size paddingBR = Size()) const;
+
+       void groupRectangles(
+               vector<cv::Rect>& rectList,
+               vector<double>& weights,
+               int groupThreshold,
+               double eps) const;
+
+       Size winSize;
+       Size blockSize;
+       Size blockStride;
+       Size cellSize;
+       int nbins;
+       int derivAperture;
+       double winSigma;
+       int histogramNormType;
+       double L2HysThreshold;
+       bool gammaCorrection;
+       vector<float> svmDetector;
+       int nlevels;
+};
+
+} /* modifiedcv */
+
+#endif /* __MEDIA_VISION_HOGDETECTOR_H__ */
diff --git a/mv_surveillance/surveillance/include/SurveillanceHelper.h b/mv_surveillance/surveillance/include/SurveillanceHelper.h
new file mode 100644 (file)
index 0000000..ffb6302
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_SURVEILLANCE_HELPER_H__
+#define __MEDIA_VISION_SURVEILLANCE_HELPER_H__
+
+/**
+ * @file  SurveillanceHelper.h
+ * @brief This file contains interface for surveillance helper.
+ */
+
+#include <mv_common.h>
+
+#include <opencv/cv.h>
+
+namespace mediavision {
+namespace surveillance {
+
+/**
+ * @class    SurveillanceHelper
+ * @brief    This class contains surveillance helper interface (common class for
+ *           surveillance module).
+ *
+ * @since_tizen 3.0
+ */
+class SurveillanceHelper {
+public:
+       /**
+        * @brief Converts mediavision source to cv::Mat in gray scale.
+        *
+        * @since_tizen 3.0
+        * @param [in] mvSource     The input media source handle
+        * @param [out] cvSource    The outut matrix with gray scaled image
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       static int convertSourceMV2GrayCV(mv_source_h mvSource, cv::Mat& cvSource);
+
+#ifdef ENABLE_NEON
+       /**
+        * @brief Converts mediavision source to cv::Mat in gray scale with NEON.
+        * @details Works only with RGB color space
+        *
+        * @since_tizen 3.0
+        * @param [in] mvSource     The input media source handle
+        * @param [out] cvSource    The outut matrix with gray scaled image
+        * @return @c 0 on success, otherwise a negative error value
+        */
+       static int convertSourceMVRGB2GrayCVNeon(mv_source_h mvSource, cv::Mat& cvSource);
+#endif
+
+};
+
+
+} /* surveillance */
+} /* mediavision */
+
+#endif /* __MEDIA_VISION_SURVEILLANCE_HELPER_H__ */
diff --git a/mv_surveillance/surveillance/include/mv_absdiff.h b/mv_surveillance/surveillance/include/mv_absdiff.h
new file mode 100644 (file)
index 0000000..1ad0a8a
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_MV_ABSDIFF_H__
+#define __MEDIA_VISION_MV_ABSDIFF_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief Absolute difference between two buffers.
+ * @details Works only with grayscale buffers.
+ *
+ * @since_tizen 3.0
+ * @remarks If NEON is enabled (ENABLE_NEON flag), then @a width has to be
+ *          multiple of 16
+ * @param [in] src1      The first input buffer.
+ * @param [in] src2      The second input buffer.
+ * @param [in] width     The ROI width. Must be the multiple of 16.
+ * @param [in] height    The ROI height.
+ * @param [in] stride    The stride.
+ * @param [out] dst      The output buffer.
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int mv_absdiff(
+               uint8_t *__restrict__ src1,
+               uint8_t *__restrict__ src2,
+               int width,
+               int height,
+               int stride,
+               uint8_t *__restrict__ dst);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MEDIA_VISION_MV_ABSDIFF_H__ */
+
diff --git a/mv_surveillance/surveillance/include/mv_apply_mask.h b/mv_surveillance/surveillance/include/mv_apply_mask.h
new file mode 100644 (file)
index 0000000..a639c03
--- /dev/null
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_MV_APPLY_MASK_H__
+#define __MEDIA_VISION_MV_APPLY_MASK_H__
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief Applies a binary mask to the input buffer.
+ * @details Works only with grayscale buffers.
+ *
+ * @since_tizen 3.0
+ * @remarks If NEON is enabled (ENABLE_NEON flag), then @a width has to be
+ *          multiple of 16
+ * @param [in] src_buffer     The source buffer.
+ * @param [in] mask           The mask, which should contain only values of 0 or 255.
+ * @param [in] width          The image width.
+ * @param [in] height         The image height.
+ * @param [in] stride         The stride.
+ * @param [out] dst_buffer    The destination buffer.
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int mv_apply_mask(
+               uint8_t *src_buffer,
+               uint8_t *__restrict mask,
+               int width,
+               int height,
+               int stride,
+               uint8_t *dst_buffer);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MEDIA_VISION_MV_APPLY_MASK_H__ */
+
diff --git a/mv_surveillance/surveillance/include/mv_mask_buffer.h b/mv_surveillance/surveillance/include/mv_mask_buffer.h
new file mode 100644 (file)
index 0000000..abc690f
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_MV_MASK_BUFFER_H__
+#define __MEDIA_VISION_MV_MASK_BUFFER_H__
+
+#include "mv_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief Gets mask buffer from buffer with known size.
+ * @details Mask buffer values: 0 ouside polygon and 255 inside polygon.
+ *
+ * @since_tizen 3.0
+ * @param [in] buffer_width     The buffer width
+ * @param [in] buffer_height    The buffer height
+ * @param [in] polygon          The array with polygon
+ * @param [in] points_number    The size of array with polygon
+ * @param [out] mask_buffer     The output mask buffer. mask_buffer size is
+ *                              the same as the buffer size in media source
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ *
+ * @post Free memory for mask_buffer.
+ */
+int mv_get_mask_buffer(
+               unsigned int buffer_width,
+               unsigned int buffer_height,
+               mv_point_s *polygon,
+               unsigned int points_number,
+               unsigned char **mask_buffer);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MEDIA_VISION_MV_MASK_BUFFER_H__ */
+
diff --git a/mv_surveillance/surveillance/include/mv_surveillance_open.h b/mv_surveillance/surveillance/include/mv_surveillance_open.h
new file mode 100644 (file)
index 0000000..e70c90b
--- /dev/null
@@ -0,0 +1,194 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MEDIA_VISION_SURVEILLANCE_OPEN_H__
+#define __MEDIA_VISION_SURVEILLANCE_OPEN_H__
+
+#include "mv_surveillance.h"
+#include "mv_surveillance_private.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @file  mv_surveillance_open.h
+ * @brief This file contains the Media Vision surveillance API
+ */
+
+/**
+ * @brief Allows to subscribe to the event and start calling @a callback
+ *        each time when the @a source is pushed using
+ *        @ref mv_surveillance_push_source_open() and event is detected.
+ *
+ * @since_tizen 3.0
+ * @remarks To stop handling triggering use
+ *          @ref mv_surveillance_unsubscribe_event_trigger_open().
+ * @param [in] event_trigger     The event trigger activating calls of the
+ *                               @a callback function
+ * @param [in] video_stream_id   The identifier of the video stream for which
+ *                               event trigger activation will be checked
+ * @param [in] engine_cfg        The engine configuration of the event
+ * @param [in] callback          Callback to be called each time when event
+ *                               occurrence is detected
+ * @param [in] user_data         The user data to be passed to the callback function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @post @ref mv_surveillance_event_occurred_cb
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_unsubscribe_event_trigger_open()
+ */
+int mv_surveillance_subscribe_event_trigger_open(
+               mv_surveillance_event_trigger_h event_trigger,
+               int video_stream_id,
+               mv_engine_config_h engine_cfg,
+               mv_surveillance_event_occurred_cb callback,
+               void *user_data);
+
+/**
+ * @brief Allows to unsubscribe from the event and stop calling @a callback.
+ *
+ * @since_tizen 3.0
+ * @remarks To start handling trigger activation use
+            @ref mv_surveillance_subscribe_event_trigger_open().
+ * @param [in] event_trigger     The event trigger for which subscription will
+ *                               be stopped
+ * @param [in] video_stream_id   The identifier of the video source for which
+ *                               subscription will be stopped
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @post @ref mv_surveillance_event_occurred_cb
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_subscribe_event_trigger_open()
+ */
+int mv_surveillance_unsubscribe_event_trigger_open(
+               mv_surveillance_event_trigger_h event_trigger,
+               int video_stream_id);
+
+/**
+ * @brief Allows to push source to the event trigger and start calling @a callback.
+ *
+ * @since_tizen 3.0
+ * @param [in] source             The handle to the media source
+ * @param [in] video_stream_id    The video stream, wthich will be updated
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_event_occurred_cb
+ * @see mv_surveillance_subscribe_event_trigger_open()
+ * @see mv_surveillance_unsubscribe_event_trigger_open()
+ */
+int mv_surveillance_push_source_open(
+               mv_source_h source,
+               int video_stream_id);
+
+/**
+ * @brief Starts traversing through list of supported event types.
+ *
+ * @since_tizen 3.0
+ * @remarks Supported event types and their descriptions can be found in
+ *          @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ *          section
+ * @param [in] callback     The callback function to be called for each
+ *                          supported event type
+ * @param [in] user_data    The user data to be passed to the @a callback
+ *                          function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_type_cb
+ * @see mv_surveillance_foreach_event_result_value_name_open()
+ */
+int mv_surveillance_foreach_event_type_open(
+               mv_surveillance_event_type_cb callback,
+               void *user_data);
+
+/**
+ * @brief Starts traversing through list of supported event result value names.
+ *
+ * @since_tizen 3.0
+ * @remarks Supported event types, event result value names and their
+ *          descriptions can be found in
+ *          @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ *          section
+ * @param [in] event_type    The name of the event type for which result value
+ *                           names will be passed to the @a callback. Can be
+ *                           set @c NULL. If set @c NULL then all supported
+ *                           event result value names will be traversed
+ * @param [in] callback      The callback function to be called for each
+ *                           supported event result value name
+ * @param [in] user_data     The user data to be passed to the @a callback
+ *                           function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_result_value_name_cb
+ * @see mv_surveillance_foreach_event_type_open()
+ * @see mv_surveillance_get_result_value_open()
+ */
+int mv_surveillance_foreach_event_result_value_name_open(
+               const char *event_type,
+               mv_surveillance_event_result_name_cb callback,
+               void *user_data);
+
+/**
+ * @brief Gets result value.
+ * @details See the output values names in the event types descriptions located
+ *          in /usr/share/config/capi-media-vision/surveillance-event-types.txt.
+ *
+ * @since_tizen 3.0
+ * @param [in] result           The event result
+ * @param [in] value_name       The name of the value to be gotten
+ * @param [in, out] value       The pointer to variable which will be filled
+ *                              by result value
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre Memory for value has to be allocated
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_event_occurred_cb
+ * @see mv_surveillance_subscribe_event_trigger_open()
+ * @see mv_surveillance_unsubscribe_event_trigger_open()
+ * @see mv_surveillance_query_events_open()
+ */
+int mv_surveillance_get_result_value_open(
+               mv_surveillance_result_h result,
+               const char *value_name,
+               void *value);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MEDIA_VISION_SURVEILLANCE_OPEN_H__ */
diff --git a/mv_surveillance/surveillance/src/EventManager.cpp b/mv_surveillance/surveillance/src/EventManager.cpp
new file mode 100644 (file)
index 0000000..0a3a05b
--- /dev/null
@@ -0,0 +1,410 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventManager.h"
+
+#include "SurveillanceHelper.h"
+
+#include "EventTriggerPersonAppearance.h"
+#include "EventTriggerPersonRecognition.h"
+#include "EventTriggerMovementDetection.h"
+
+#include <mv_private.h>
+
+namespace mediavision {
+namespace surveillance {
+
+static const int MAX_VALUE_NAME_LENGTH = 255;
+
+EventManager *EventManager::__pInstance = 0;
+EventManagerDestroyer EventManager::Destroyer;
+EventTypesMap EventManager::SupportedEventTypes;
+
+EventManagerDestroyer::~EventManagerDestroyer()
+{
+       delete __pInstance;
+}
+
+void EventManagerDestroyer::initialize(EventManager* pointer)
+{
+       __pInstance = pointer;
+}
+
+EventManager& EventManager::getInstance()
+{
+       if(!__pInstance) {
+               __pInstance = new EventManager();
+               Destroyer.initialize(__pInstance);
+               setSupportedEventTypes();
+       }
+
+       return *__pInstance;
+}
+
+void EventManager::setSupportedEventTypes()
+{
+       /* Add supported event types here */
+       SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED]
+               .push_back(MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS);
+       SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED]
+               .push_back(MV_SURVEILLANCE_MOVEMENT_REGIONS);
+
+       SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED]
+               .push_back(MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER);
+       SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED]
+               .push_back(MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER);
+       SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED]
+               .push_back(MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER);
+       SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED]
+               .push_back(MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS);
+       SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED]
+               .push_back(MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS);
+       SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED]
+               .push_back(MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS);
+
+       SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED]
+               .push_back(MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER);
+       SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED]
+               .push_back(MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS);
+       SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED]
+               .push_back(MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS);
+       SupportedEventTypes[MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED]
+               .push_back(MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES);
+}
+
+EventManager::EventManager()
+{
+       ; /* NULL */
+}
+
+EventManager::~EventManager()
+{
+       ; /* NULL */
+}
+
+int EventManager::registerEvent(
+                                       mv_surveillance_event_trigger_h eventTrigger,
+                                       long int triggerId,
+                                       const char *eventType,
+                                       int videoStreamId,
+                                       mv_engine_config_h engineCfg,
+                                       mv_surveillance_event_occurred_cb callback,
+                                       void *user_data,
+                                       int numberOfPoints,
+                                       mv_point_s *roi)
+{
+       if (NULL == callback || NULL == eventType) {
+               LOGE("Input event trigger or callback is NULL. Event registering failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       EventTriggersConstIter iter = __eventTriggers[videoStreamId].begin();
+
+       for (; iter != __eventTriggers[videoStreamId].end(); ++iter) {
+               if ((*iter)->isCallbackSubscribed(triggerId)) {
+                       LOGE("Callback with id %d is already subscribed. "
+                                       "Event registering failed.", triggerId);
+                       return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+               }
+       }
+
+       /* Add appropriate event trigger here */
+       if (strncmp(eventType, MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+                               MAX_VALUE_NAME_LENGTH) == 0) {
+               EventTriggerPersonAppearance* trigger =
+                       new EventTriggerPersonAppearance(
+                                       eventTrigger,
+                                       triggerId,
+                                       videoStreamId,
+                                       callback,
+                                       user_data,
+                                       numberOfPoints,
+                                       roi);
+               const int error = trigger->parseEngineConfig(engineCfg);
+
+               if (error != MEDIA_VISION_ERROR_NONE) {
+                       delete trigger;
+
+                       LOGE("Input engine configuration is wrong. Event registering failed.");
+                       return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+               }
+
+               EventTriggersIter iter2 = isTriggerExists(trigger, videoStreamId);
+
+               if (iter2 != __eventTriggers[videoStreamId].end()) {
+                       (*iter2)->subscribeCallback(
+                                               eventTrigger,
+                                               triggerId,
+                                               callback,
+                                               user_data,
+                                               numberOfPoints,
+                                               roi);
+
+                                               delete trigger;
+               } else {
+                       __eventTriggers[videoStreamId].push_back(trigger);
+               }
+       } else if (strncmp(eventType, MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED,
+                                               MAX_VALUE_NAME_LENGTH) == 0) {
+               EventTriggerPersonRecognition* trigger =
+                                               new EventTriggerPersonRecognition(
+                                                                               eventTrigger,
+                                                                               triggerId,
+                                                                               videoStreamId,
+                                                                               callback,
+                                                                               user_data,
+                                                                               numberOfPoints,
+                                                                               roi);
+
+               const int error = trigger->parseEngineConfig(engineCfg);
+               if (error != MEDIA_VISION_ERROR_NONE) {
+                       delete trigger;
+
+                       LOGE("Input engine configuration is wrong. Event registering failed.");
+                       return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+               }
+
+               EventTriggersIter iter2 = isTriggerExists(trigger, videoStreamId);
+
+               if (iter2 != __eventTriggers[videoStreamId].end()) {
+                       (*iter2)->subscribeCallback(
+                                               eventTrigger,
+                                               triggerId,
+                                               callback,
+                                               user_data,
+                                               numberOfPoints,
+                                               roi);
+
+                       delete trigger;
+               } else {
+                       __eventTriggers[videoStreamId].push_back(trigger);
+               }
+       } else if (strncmp(eventType, MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED,
+                               MAX_VALUE_NAME_LENGTH) == 0) {
+                       EventTriggerMovementDetection* trigger =
+                                               new EventTriggerMovementDetection(
+                                                                       eventTrigger,
+                                                                       triggerId,
+                                                                       videoStreamId,
+                                                                       callback,
+                                                                       user_data,
+                                                                       numberOfPoints,
+                                                                       roi);
+
+               const int error = trigger->parseEngineConfig(engineCfg);
+
+               if (error != MEDIA_VISION_ERROR_NONE) {
+                       delete trigger;
+
+                       LOGE("Input engine configuration is wrong. Event registering failed.");
+                       return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+               }
+
+               EventTriggersIter iter2 = isTriggerExists(trigger, videoStreamId);
+
+               if (iter2 != __eventTriggers[videoStreamId].end()) {
+                       (*iter2)->subscribeCallback(
+                                               eventTrigger,
+                                               triggerId,
+                                               callback,
+                                               user_data,
+                                               numberOfPoints,
+                                               roi);
+
+                       delete trigger;
+               } else {
+                       __eventTriggers[videoStreamId].push_back(trigger);
+               }
+       } else {
+               LOGE("Input event trigger has wrong type. Event registering failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventManager::unregisterEvent(long int triggerId, int videoStreamId)
+{
+       EventTriggersIter iter = __eventTriggers[videoStreamId].begin();
+
+       while (iter != __eventTriggers[videoStreamId].end()) {
+               if ((*iter)->unsubscribeCallback(triggerId)) {
+                       if ((*iter)->isCallbacksEmpty()) {
+                               delete *iter;
+                               __eventTriggers[videoStreamId].erase(iter);
+                       }
+
+                       return MEDIA_VISION_ERROR_NONE;
+               }
+
+               ++iter;
+       }
+
+       if (iter == __eventTriggers[videoStreamId].end()) {
+               LOGE("Event trigger doesn't exist. Event unregistering failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventManager::pushSource(mv_source_h source, int videoStreamId)
+{
+       if (NULL == source) {
+               LOGE("Input source is NULL. Push source failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       if (__eventTriggers[videoStreamId].empty()) {
+               LOGE("There are no events yet. Push source failed.");
+               return MEDIA_VISION_ERROR_INVALID_OPERATION;
+       }
+
+       unsigned int width = 0;
+       unsigned int height = 0;
+       mv_colorspace_e colorspace = MEDIA_VISION_COLORSPACE_INVALID;
+
+       MEDIA_VISION_ASSERT(mv_source_get_width(source, &width),
+                                               "Failed to get the width.");
+       MEDIA_VISION_ASSERT(mv_source_get_height(source, &height),
+                                               "Failed to get the height.");
+       MEDIA_VISION_ASSERT(mv_source_get_colorspace(source, &colorspace),
+                                               "Failed to get the colorspace.");
+
+       cv::Mat grayImage;
+
+       int error = MEDIA_VISION_ERROR_NONE;
+
+#ifdef ENABLE_NEON
+       if (colorspace == MEDIA_VISION_COLORSPACE_RGB888 && (width * height % 8) == 0)
+               error = SurveillanceHelper::convertSourceMVRGB2GrayCVNeon(source, grayImage);
+       else
+#endif /* ENABLE_NEON */
+               error = SurveillanceHelper::convertSourceMV2GrayCV(source, grayImage);
+
+       if (error != MEDIA_VISION_ERROR_NONE || grayImage.empty()) {
+               LOGE("Media source conversion failed.");
+               return error;
+       }
+
+       mv_source_h graySource;
+       error = mv_create_source(&graySource);
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               LOGE("Errors were occurred during source creating %i", error);
+               return error;
+       }
+
+       error = mv_source_fill_by_buffer(
+                               graySource,
+                               grayImage.data,
+                               grayImage.cols * grayImage.rows,
+                               grayImage.cols,
+                               grayImage.rows,
+                               MEDIA_VISION_COLORSPACE_Y800);
+
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               mv_destroy_source(graySource);
+               LOGE("Errors were occurred during source filling %i", error);
+               return error;
+       }
+
+       EventTriggersConstIter iter = __eventTriggers[videoStreamId].begin();
+
+       for (; iter != __eventTriggers[videoStreamId].end(); ++iter) {
+               error = (*iter)->pushSource(source, graySource, grayImage);
+
+               if (error != MEDIA_VISION_ERROR_NONE)
+                       LOGE("Push source failed for event ", (*iter)->getEventType().c_str());
+       }
+
+       error = mv_destroy_source(graySource);
+
+       if (MEDIA_VISION_ERROR_NONE != error)
+               LOGE("Errors were occurred during gray source destroying %i", error);
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventManager::getSupportedEventTypes(StringVector& eventTypes)
+{
+       eventTypes.clear();
+
+       if (!__pInstance)
+               setSupportedEventTypes();
+
+       EventTypesMapConstIter etIter = SupportedEventTypes.begin();
+       while (etIter != SupportedEventTypes.end()) {
+               eventTypes.push_back(etIter->first);
+               ++etIter;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventManager::getSupportedEventResultValueNames(
+       StringVector& eventResValNames)
+{
+       eventResValNames.clear();
+
+       if (!__pInstance)
+               setSupportedEventTypes();
+
+       EventTypesMapConstIter etIter = SupportedEventTypes.begin();
+       while (etIter != SupportedEventTypes.end()) {
+               eventResValNames.insert(
+                                       eventResValNames.end(),
+                                       etIter->second.begin(),
+                                       etIter->second.end());
+               ++etIter;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventManager::getSupportedEventResultValueNames(
+       const std::string& eventTypeName,
+       StringVector& eventResValNames)
+{
+       eventResValNames.clear();
+
+       if (!__pInstance)
+               setSupportedEventTypes();
+
+       EventTypesMapConstIter etIter = SupportedEventTypes.find(eventTypeName);
+       if (etIter == SupportedEventTypes.end())
+               return MEDIA_VISION_ERROR_KEY_NOT_AVAILABLE;
+
+       eventResValNames = etIter->second;
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+EventTriggersIter EventManager::isTriggerExists(
+               EventTrigger* trigger,
+               int videoStreamId)
+{
+       EventTriggersIter iter = __eventTriggers[videoStreamId].begin();
+
+       for (; iter != __eventTriggers[videoStreamId].end(); ++iter)
+               if (*(*iter) == *trigger)
+                       return iter;
+
+       return iter;
+}
+
+} /* surveillance */
+} /* mediavision */
+
diff --git a/mv_surveillance/surveillance/src/EventTrigger.cpp b/mv_surveillance/surveillance/src/EventTrigger.cpp
new file mode 100644 (file)
index 0000000..d6b4cec
--- /dev/null
@@ -0,0 +1,197 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventTrigger.h"
+
+#include <mv_private.h>
+#include <mv_mask_buffer.h>
+#include <mv_apply_mask.h>
+
+namespace mediavision {
+namespace surveillance {
+
+long int EventTrigger::InternalTriggersCounter = -1l;
+
+EventTrigger::EventTrigger(
+               mv_surveillance_event_trigger_h eventTrigger,
+               long int triggerId,
+               int videoStreamId,
+               mv_surveillance_event_occurred_cb callback,
+               void *userData,
+               int numberOfPoints,
+               mv_point_s *roi):
+       __videoStreamId(videoStreamId),
+       __roi(numberOfPoints)
+{
+       CallbackData callbackData;
+       callbackData.eventTrigger = eventTrigger;
+       callbackData.callback = callback;
+       callbackData.userData = userData;
+
+       __callbackDataMap.insert(CallbackDataPair(triggerId, callbackData));
+
+       for (int i = 0; i < numberOfPoints; ++i)
+               __roi[i] = roi[i];
+}
+
+EventTrigger::~EventTrigger()
+{
+       ; /* NULL */
+}
+
+int EventTrigger::getVideoStreamId() const
+{
+       return __videoStreamId;
+}
+
+bool EventTrigger::isCallbackSubscribed(long int triggerId) const
+{
+       return __callbackDataMap.find(triggerId) != __callbackDataMap.end();
+}
+
+bool EventTrigger::subscribeCallback(
+               mv_surveillance_event_trigger_h eventTrigger,
+               long int triggerId,
+               mv_surveillance_event_occurred_cb callback,
+               void *userData,
+               int numberOfPoints,
+               mv_point_s *roi)
+{
+       if (isCallbackSubscribed(triggerId)) {
+               LOGE("Callback with id %d is already subscribed. "
+                       "Callback subscribing failed.", triggerId);
+               return false;
+       }
+
+       CallbackData callbackData;
+       callbackData.eventTrigger = eventTrigger;
+       callbackData.callback = callback;
+       callbackData.userData = userData;
+
+       __callbackDataMap.insert(CallbackDataPair(triggerId, callbackData));
+
+       /* TODO: implement support of multiple ROI */
+       __roi.clear();
+       __roi.resize(numberOfPoints);
+
+       for (int i = 0; i < numberOfPoints; ++i)
+               __roi[i] = roi[i];
+
+       return true;
+}
+
+bool EventTrigger::unsubscribeCallback(long int triggerId)
+{
+       CallbackDataMapIter iter = __callbackDataMap.find(triggerId);
+
+       if (iter == __callbackDataMap.end()) {
+               LOGE("Callback with id %d was not subscribed. "
+                       "Callback unsubscribing failed.", triggerId);
+               return false;
+       }
+
+       iter->second.callback = NULL;
+       iter->second.userData = NULL;
+       __callbackDataMap.erase(iter);
+
+       return true;
+}
+
+bool EventTrigger::isCallbacksEmpty() const
+{
+       return __callbackDataMap.empty();
+}
+
+int EventTrigger::applyROIToImage(
+                                       unsigned char *image,
+                                       int imageWidth,
+                                       int imageHeight,
+                                       bool scalePoints,
+                                       int scaleX,
+                                       int scaleY)
+{
+       const size_t roiSize = __roi.size();
+
+       if (roiSize >= 3) {
+               MVPoints scaledPoints = __roi;
+
+               if (scalePoints)
+                       for (size_t i = 0u; i < roiSize; ++i) {
+                               scaledPoints[i].x /= scaleX;
+                               scaledPoints[i].y /= scaleY;
+                       }
+
+               unsigned char *maskBuffer = NULL;
+
+               int error = mv_get_mask_buffer(
+                                               imageWidth,
+                                               imageHeight,
+                                               scaledPoints.data(),
+                                               (int) roiSize,
+                                               &maskBuffer);
+
+               if (error != MEDIA_VISION_ERROR_NONE || maskBuffer == NULL) {
+                       if (maskBuffer != NULL)
+                               delete maskBuffer;
+
+                       LOGE("Getting mask buffer failed.");
+                       return error;
+               }
+
+               error = mv_apply_mask(
+                                       image,
+                                       maskBuffer,
+                                       imageWidth / 16 * 16,
+                                       imageHeight,
+                                       imageWidth,
+                                       image);
+
+               delete maskBuffer;
+
+               if (error != MEDIA_VISION_ERROR_NONE) {
+                       LOGE("Applying mask buffer failed.");
+                       return error;
+               }
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+bool EventTrigger::operator==(const EventTrigger& other) const
+{
+       const std::string currentEventType = this->getEventType();
+       const std::string otherEventType = other.getEventType();
+
+       if (__videoStreamId != other.__videoStreamId ||
+                       currentEventType.compare(otherEventType) != 0 ||
+                       __roi.size() != other.__roi.size())
+               return false;
+
+       size_t size = __roi.size();
+       for (size_t i = 0; i < size; ++i)
+               if (__roi[i].x != other.__roi[i].x || __roi[i].y != other.__roi[i].y)
+                       return false;
+
+       return true;
+}
+
+bool EventTrigger::operator!=(const EventTrigger& other) const
+{
+       return !(*this == other);
+}
+
+} /* surveillance */
+} /* mediavision */
diff --git a/mv_surveillance/surveillance/src/EventTriggerMovementDetection.cpp b/mv_surveillance/surveillance/src/EventTriggerMovementDetection.cpp
new file mode 100644 (file)
index 0000000..cc6ee91
--- /dev/null
@@ -0,0 +1,290 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventTriggerMovementDetection.h"
+
+#include "EventDefs.h"
+#include "mv_absdiff.h"
+#include "SurveillanceHelper.h"
+
+#include <mv_private.h>
+
+#include "opencv2/highgui/highgui.hpp"
+
+namespace mediavision {
+namespace surveillance {
+
+static const int DEFAULT_DIFF_THRESHOLD = 10;
+
+static const int MAX_VALUE_NAME_LENGTH = 255;
+
+const cv::Mat EventTriggerMovementDetection::__ERODE_KERNEL =
+       cv::getStructuringElement(cv::MORPH_RECT, cv::Size(4, 4));
+
+const cv::Mat EventTriggerMovementDetection::__DILATE_KERNEL =
+       cv::getStructuringElement(cv::MORPH_RECT, cv::Size(24, 24));
+
+static const cv::Rect DEFAULT_RECT = cv::Rect(0, 0, 0, 0);
+
+namespace {
+
+inline void convertRectCV2MV(const cv::Rect& src, mv_rectangle_s& dst)
+{
+       dst.point.x = src.x;
+       dst.point.y = src.y;
+       dst.width = src.width;
+       dst.height = src.height;
+}
+
+void mergeOverlappedRects(CVRectangles& rects)
+{
+       const size_t rectsSize = rects.size();
+
+       for (size_t i = 0; i < rectsSize; ++i) {
+               const int area1 = rects[i].area();
+
+               for (size_t j = i + 1; j < rectsSize; ++j) {
+                       const int area2 = rects[j].area();
+                       const int intersectionArea = (rects[i] & rects[j]).area();
+
+                       if (intersectionArea != 0 &&
+                               intersectionArea > std::min(area1, area2) / 2) {
+                               rects[i] |= rects[j];
+                               rects[j] = DEFAULT_RECT;
+                       }
+               }
+       }
+}
+
+} /* anonymous namespace */
+
+int EventResultMovementDetection::getResultValue(
+       const char *valueName,
+       void *value) const
+{
+       if (valueName == NULL) {
+               LOGE("Invalid pointer for value name. Getting result value failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       if (value == NULL) {
+               LOGE("Invalid pointer for value. Getting result value failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       if (strncmp(valueName, MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS,
+                               MAX_VALUE_NAME_LENGTH) == 0) {
+               size_t *const numberOfDetectedMovements = (size_t*) value;
+               *numberOfDetectedMovements = __movementRegions.size();
+       } else if (strncmp(valueName, MV_SURVEILLANCE_MOVEMENT_REGIONS,
+                               MAX_VALUE_NAME_LENGTH) == 0) {
+               mv_rectangle_s *const movementsRegions = (mv_rectangle_s*) value;
+
+               const size_t numberOfDetectedMovements = __movementRegions.size();
+
+               for (size_t i = 0u; i < numberOfDetectedMovements; ++i) {
+                       movementsRegions[i] = __movementRegions[i];
+               }
+       } else {
+               LOGE("This value name doesn't exist. Getting result value failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+EventTriggerMovementDetection::EventTriggerMovementDetection(
+               mv_surveillance_event_trigger_h eventTrigger,
+               long int triggerId,
+               int videoStreamId,
+               mv_surveillance_event_occurred_cb callback,
+               void *userData,
+               int numberOfPoints,
+               mv_point_s *roi) : EventTrigger(
+                                                               eventTrigger,
+                                                               triggerId,
+                                                               videoStreamId,
+                                                               callback,
+                                                               userData,
+                                                               numberOfPoints,
+                                                               roi),
+               __previousImage(),
+               __eventResult(new EventResultMovementDetection()),
+               __diffThreshold(DEFAULT_DIFF_THRESHOLD)
+{
+       ; /* NULL */
+}
+
+EventTriggerMovementDetection::~EventTriggerMovementDetection()
+{
+       delete __eventResult;
+}
+
+int EventTriggerMovementDetection::parseEngineConfig(mv_engine_config_h engineConfig)
+{
+       if (NULL == engineConfig) {
+               LOGI("Default value for movement detection threshold was set.");
+               return MEDIA_VISION_ERROR_NONE;
+       }
+
+       const int error = mv_engine_config_get_int_attribute(
+                       engineConfig,
+                       MV_SURVEILLANCE_MOVEMENT_DETECTION_THRESHOLD,
+                       &__diffThreshold);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               LOGE("Getting movement detection threshold from engine configuration failed.");
+               return error;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventTriggerMovementDetection::pushSource(
+               mv_source_h source,
+               mv_source_h graySource,
+               const cv::Mat& grayImage)
+{
+       if (source == NULL || graySource == NULL || grayImage.empty()) {
+               LOGE("Media source is NULL. Pushing source failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       __eventResult->__movementRegions.clear();
+
+       int error = MEDIA_VISION_ERROR_NONE;
+
+       if (__previousImage.empty()) {
+               __previousImage = grayImage.clone();
+
+               LOGI("Previous media source is empty. Push next source.");
+               return error;
+       }
+
+       cv::Mat image = grayImage.clone();
+
+       const int bufSize = image.cols * image.rows * sizeof(uint8_t);
+       uint8_t *diffBuffer = (uint8_t*) malloc(bufSize * sizeof(uint8_t));
+       memset(diffBuffer, 0, bufSize);
+
+       error = mv_absdiff(
+                       image.data,
+                       __previousImage.data,
+                       image.cols,
+                       image.rows,
+                       image.cols,
+                       diffBuffer);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               LOGE("Absolute difference calculation failed. Pushing source failed.");
+               return error;
+       }
+
+       error = applyROIToImage(diffBuffer, image.cols, image.rows);
+
+       if (error != MEDIA_VISION_ERROR_NONE || image.empty()) {
+               LOGE("Applying ROI failed with error %d.", error);
+               return error;
+       }
+
+       cv::Mat imgDiff = cv::Mat(cv::Size(image.cols, image.rows),
+                       CV_8UC1, diffBuffer);
+
+       cv::erode(imgDiff, imgDiff, __ERODE_KERNEL);
+       cv::dilate(imgDiff, imgDiff, __DILATE_KERNEL);
+
+       cv::threshold(imgDiff, imgDiff, __diffThreshold, 255, CV_THRESH_BINARY);
+
+       Contours contours;
+
+       cv::findContours(imgDiff, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);
+
+       free(diffBuffer);
+
+       const size_t contoursSize = contours.size();
+       CVRectangles rects(contoursSize);
+
+       for (size_t i = 0u; i < contoursSize; ++i)
+               rects[i] = cv::boundingRect(cv::Mat(contours[i]));
+
+       mergeOverlappedRects(rects);
+
+       const size_t roiSize = __roi.size();
+       CVPoints roi(roiSize);
+
+       cv::Rect roiRect(0, 0, imgDiff.cols, imgDiff.rows);
+
+       if (roiSize >= 3u) {
+               for (size_t i = 0u; i < roiSize; ++i)
+                       roi[i] = cv::Point(__roi[i].x, __roi[i].y);
+
+               roiRect = cv::boundingRect(roi);
+       }
+
+       const size_t rectsSize = rects.size();
+       for (size_t i = 0u; i < rectsSize; ++i)
+               if (rects[i] != DEFAULT_RECT &&
+                       roiRect.contains(rects[i].tl()) &&
+                       roiRect.contains(rects[i].br())) {
+                       mv_rectangle_s rectMV;
+                       convertRectCV2MV(rects[i], rectMV);
+
+                       __eventResult->__movementRegions.push_back(rectMV);
+               }
+
+       __previousImage = image;
+       __eventResult->__grayImage = __previousImage;
+
+       // Don't invoke the callback if movement wasn't detected at the frame
+       if (__eventResult->__movementRegions.size() > 0) {
+               CallbackDataMapConstIter iter = __callbackDataMap.begin();
+
+               for (; iter != __callbackDataMap.end(); ++iter) {
+                       mv_surveillance_event_occurred_cb callback = iter->second.callback;
+                       callback(
+                               iter->second.eventTrigger,
+                               source,
+                               __videoStreamId,
+                               __eventResult,
+                               iter->second.userData);
+               }
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+std::string EventTriggerMovementDetection::getEventType() const
+{
+       return MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED;
+}
+
+bool EventTriggerMovementDetection::operator==(const EventTriggerMovementDetection& other) const
+{
+       if (EventTrigger::operator !=(other))
+               return false;
+
+       /* TODO: compare private values if necessary */
+
+       return true;
+}
+
+bool EventTriggerMovementDetection::operator!=(const EventTriggerMovementDetection& other) const
+{
+       return !(*this == other);
+}
+
+} /* surveillance */
+} /* mediavision */
diff --git a/mv_surveillance/surveillance/src/EventTriggerPersonAppearance.cpp b/mv_surveillance/surveillance/src/EventTriggerPersonAppearance.cpp
new file mode 100644 (file)
index 0000000..ca14d45
--- /dev/null
@@ -0,0 +1,460 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventTriggerPersonAppearance.h"
+
+#include "EventManager.h"
+#include "FaceDetector.h"
+#include "SurveillanceHelper.h"
+#include "EventTriggerMovementDetection.h"
+
+#include "opencv2/opencv.hpp"
+#include "opencv2/highgui/highgui.hpp"
+
+#include <mv_private.h>
+
+#include <sys/time.h>
+#include <unistd.h>
+
+namespace mediavision {
+namespace surveillance {
+
+using namespace cv;
+
+static const int MAX_VALUE_NAME_LENGHT = 255;
+
+static const int DEFAULT_SKIP_FRAMES_COUNT = 6;
+
+static const int DEFAULT_FRAME_WIDTH = 640;
+
+static const int DEFAULT_FRAME_HEIGHT = 480;
+
+static const cv::Size DEFAULT_FRAME_SIZE(DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT);
+
+static const cv::Rect ALL_IMAGE_RECT(0, 0, DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT);
+
+static const cv::Size DEFAULT_DETECTION_STEPS = cv::Size(8, 8);
+
+static const std::vector<float> DEFAULT_SVM_PEOPLE_DETECTOR =
+               cv::HOGDescriptor::getDefaultPeopleDetector();
+
+namespace {
+
+inline void convertRectMV2CV(const mv_rectangle_s& src, cv::Rect& dst)
+{
+       dst.x = src.point.x;
+       dst.y = src.point.y;
+       dst.width = src.width;
+       dst.height = src.height;
+}
+
+inline void convertRectCV2MV(const cv::Rect& src, mv_rectangle_s& dst)
+{
+       dst.point.x = src.x;
+       dst.point.y = src.y;
+       dst.width = src.width;
+       dst.height = src.height;
+}
+
+} /* Anonymous namespace*/
+
+int EventResultPersonAppearance::getResultValue(const char *valueName,
+               void *value) const
+{
+       if (valueName == NULL) {
+               LOGE("Invalid pointer for value name. Getting result value failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       if (value == NULL) {
+               LOGE("Invalid pointer for value. Getting result value failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       if (strncmp(valueName, MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER,
+                       MAX_VALUE_NAME_LENGHT) == 0) {
+               size_t * const numberOfAppearedPersons = (size_t*) value;
+               *numberOfAppearedPersons = __appearedLocations.size();
+       }
+       else if (strncmp(valueName, MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS,
+                       MAX_VALUE_NAME_LENGHT) == 0) {
+               mv_rectangle_s * const appearedLocations = (mv_rectangle_s*) value;
+
+               const size_t numberOfAppearedPersons = __appearedLocations.size();
+
+               for (size_t i = 0u; i < numberOfAppearedPersons; ++i)
+                       appearedLocations[i] = __appearedLocations[i];
+       }
+       else if (strncmp(valueName, MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER,
+                       MAX_VALUE_NAME_LENGHT) == 0) {
+               size_t * const numberOfTrackedPersons = (size_t*) value;
+               *numberOfTrackedPersons = __trackedLocations.size();
+       }
+       else if (strncmp(valueName, MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS,
+                       MAX_VALUE_NAME_LENGHT) == 0) {
+               mv_rectangle_s * const trackedLocations = (mv_rectangle_s*) value;
+
+               const size_t numberOfTrackedPersons = __trackedLocations.size();
+
+               for (size_t i = 0u; i < numberOfTrackedPersons; ++i)
+                       trackedLocations[i] = __trackedLocations[i];
+       }
+       else if (strncmp(valueName, MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER,
+                       MAX_VALUE_NAME_LENGHT) == 0) {
+               size_t * const numberOfDisappearedPersons = (size_t*) value;
+               *numberOfDisappearedPersons = __disappearedLocations.size();
+       }
+       else if (strncmp(valueName, MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS,
+                       MAX_VALUE_NAME_LENGHT) == 0) {
+               mv_rectangle_s * const disappearedLocations = (mv_rectangle_s*) value;
+
+               const size_t numberOfDisappearedPersons = __disappearedLocations.size();
+
+               for (size_t i = 0u; i < numberOfDisappearedPersons; ++i)
+                       disappearedLocations[i] = __disappearedLocations[i];
+       }
+       else {
+               LOGE("This value name doesn't exist. Getting result value failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+EventTriggerPersonAppearance::EventTriggerPersonAppearance(
+               mv_surveillance_event_trigger_h eventTrigger, long int triggerId,
+               int videoStreamId, mv_surveillance_event_occurred_cb callback,
+               void *userData, int numberOfPoints, mv_point_s *roi) :
+                               EventTrigger(eventTrigger, triggerId, videoStreamId, callback, userData,
+                               numberOfPoints, roi), __skipFramesCount(DEFAULT_SKIP_FRAMES_COUNT),
+                               __frameCounter(0), __movementDetectedEventId(InternalTriggersCounter--),
+                               __factorX(1.f), __factorY(1.f), __rectToDetect(ALL_IMAGE_RECT),
+                               __rectToDetectPrevious(ALL_IMAGE_RECT), __trackedRects(),
+                               __appearedRects(), __disappearedRects(), __hogClassifier(),
+                               __eventResult(new EventResultPersonAppearance())
+{
+       __hogClassifier.setSVMDetector(DEFAULT_SVM_PEOPLE_DETECTOR);
+
+       EventManager::getInstance().registerEvent(
+       NULL, __movementDetectedEventId,
+       MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED, videoStreamId,
+       NULL, movementDetectedCB, this, numberOfPoints, roi);
+}
+
+EventTriggerPersonAppearance::~EventTriggerPersonAppearance()
+{
+       EventManager::getInstance().unregisterEvent(__movementDetectedEventId,
+                       __videoStreamId);
+
+       delete __eventResult;
+}
+
+int EventTriggerPersonAppearance::parseEngineConfig(
+               mv_engine_config_h engineConfig)
+{
+       if (NULL == engineConfig) {
+               LOGI("Default value for frame skip count was set.");
+               return MEDIA_VISION_ERROR_NONE;
+       }
+
+       const int error = mv_engine_config_get_int_attribute(engineConfig,
+       MV_SURVEILLANCE_SKIP_FRAMES_COUNT, &__skipFramesCount);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               LOGE("Getting frame skip count from engine configuration failed.");
+               return error;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventTriggerPersonAppearance::pushSource(mv_source_h source,
+               mv_source_h graySource, const cv::Mat& grayImage)
+{
+       if (source == NULL || graySource == NULL || grayImage.empty()) {
+               LOGE("Media source is NULL. Pushing source failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+std::string EventTriggerPersonAppearance::getEventType() const
+{
+       return MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED;
+}
+
+bool EventTriggerPersonAppearance::operator==(
+               const EventTriggerPersonAppearance& other) const
+{
+       if (EventTrigger::operator !=(other))
+               return false;
+
+       /* TODO: compare private values if necessary */
+
+       return true;
+}
+
+bool EventTriggerPersonAppearance::operator!=(
+               const EventTriggerPersonAppearance& other) const
+{
+       return !(*this == other);
+}
+
+void EventTriggerPersonAppearance::movementDetectedCB(
+               mv_surveillance_event_trigger_h /*event_trigger*/, mv_source_h source,
+               int /*video_stream_id*/, mv_surveillance_result_h event_result,
+               void *user_data)
+{
+       EventTriggerPersonAppearance *trigger =
+                       (EventTriggerPersonAppearance*) user_data;
+
+       /* 1. Get input image in grayscale and resize it */
+       EventResultMovementDetection *result =
+                       static_cast<EventResultMovementDetection*>(event_result);
+
+       cv::Mat resizedImage;
+       cv::resize(result->__grayImage, resizedImage, DEFAULT_FRAME_SIZE);
+
+       int error = trigger->applyROIToImage(resizedImage.data, resizedImage.cols,
+                       resizedImage.rows, true, DEFAULT_FRAME_WIDTH, DEFAULT_FRAME_HEIGHT);
+
+       if (error != MEDIA_VISION_ERROR_NONE || resizedImage.empty()) {
+               trigger->runCallbacks(source);
+               LOGE("Applying ROI failed with error %d.", error);
+               return;
+       }
+
+       trigger->__factorX = (float) DEFAULT_FRAME_WIDTH / result->__grayImage.cols;
+       trigger->__factorY = (float) DEFAULT_FRAME_HEIGHT / result->__grayImage.rows;
+
+       /* 2. Get detected movement regions */
+       const size_t numberOfMovementRegions = result->__movementRegions.size();
+       CVRectangles movementRegions(numberOfMovementRegions);
+
+       for (size_t i = 0u; i < numberOfMovementRegions; ++i) {
+               convertRectMV2CV(result->__movementRegions[i], movementRegions[i]);
+               movementRegions[i].x *= trigger->__factorX;
+               movementRegions[i].y *= trigger->__factorY;
+               movementRegions[i].width *= trigger->__factorX;
+               movementRegions[i].height *= trigger->__factorY;
+       }
+
+       /* 3. Calculate rectangle where person will be detect */
+       if (movementRegions.empty()) {
+               trigger->__rectToDetect = ALL_IMAGE_RECT;
+       } else {
+               trigger->__rectToDetect = movementRegions[0];
+
+               for (size_t j = 1u; j < numberOfMovementRegions; ++j)
+                       trigger->__rectToDetect |= movementRegions[j];
+
+               if (trigger->__rectToDetect.width
+                               < trigger->__hogClassifier.winSize.width
+                               || trigger->__rectToDetect.height
+                                               < trigger->__hogClassifier.winSize.height)
+                       trigger->__rectToDetect |= trigger->__rectToDetectPrevious;
+       }
+
+       trigger->__rectToDetect &= ALL_IMAGE_RECT;
+
+       /* 4. Perform Hog detector or try to track using movement regions */
+       if ((trigger->__skipFramesCount == 0 ||
+                       trigger->__frameCounter % trigger->__skipFramesCount == 0) &&
+                       (trigger->__rectToDetect != ALL_IMAGE_RECT)) {
+               /* 4.1 Perform Hog detector */
+               TrackedRectanglesConstIter iter = trigger->__trackedRects.begin();
+               for (; iter != trigger->__trackedRects.end(); ++iter)
+                       trigger->__rectToDetect |= iter->rect;
+
+               // Slightly extend detection area...
+               const int xShift = .25f * trigger->__rectToDetect.width;
+               const int yShift = .25f * trigger->__rectToDetect.height;
+               trigger->__rectToDetect.x -= xShift / 2;
+               trigger->__rectToDetect.y -= yShift / 2;
+               trigger->__rectToDetect.width += xShift;
+               trigger->__rectToDetect.height += yShift;
+               trigger->__rectToDetect &= ALL_IMAGE_RECT;
+               // and fit it to the HOG cell size
+               const int xRest = trigger->__rectToDetect.width % 8;
+               const int yRest = trigger->__rectToDetect.height % 8;
+               trigger->__rectToDetect.x += xRest / 2;
+               trigger->__rectToDetect.y += yRest / 2;
+               trigger->__rectToDetect.width -= xRest;
+               trigger->__rectToDetect.height -= yRest;
+
+               CVRectangles hogRects;
+
+               trigger->__hogClassifier.detectMultiScale(
+                               resizedImage(trigger->__rectToDetect), hogRects, 0,
+                               DEFAULT_DETECTION_STEPS, cv::Size(32, 32), 1.059, 2);
+
+               const size_t hogRectsSize = hogRects.size();
+
+               for (size_t i = 0u; i < hogRectsSize; ++i) {
+                       hogRects[i].x += trigger->__rectToDetect.x;
+                       hogRects[i].y += trigger->__rectToDetect.y;
+               }
+
+               std::vector<bool> trackChecks(hogRectsSize, false);
+               TrackedRectanglesIter trackRectIter = trigger->__trackedRects.begin();
+               for (; trackRectIter != trigger->__trackedRects.end();
+                               ++trackRectIter) {
+                       size_t bestArea = 0;
+                       size_t bestIdx = 0;
+                       for (size_t idx = 0u; idx < hogRectsSize; ++idx) {
+                               if (trackChecks[idx])
+                                       continue;
+                               const size_t curArea =
+                                               (hogRects[idx] & trackRectIter->rect).area();
+                               if (bestArea < curArea) {
+                                       bestArea = curArea;
+                                       bestIdx = idx;
+                               }
+                       }
+                       if (bestArea > 10) {
+                               trackChecks[bestIdx] = true;
+                               trackRectIter->rect = hogRects[bestIdx];
+                       }
+               }
+
+               trigger->__appearedRects.clear();
+               for (size_t idx = 0u; idx < hogRectsSize; ++idx)
+                       if (!trackChecks[idx])
+                               trigger->__appearedRects.push_back(hogRects[idx]);
+       }
+       else {
+               /* 4.2 Try to track */
+               CVRectanglesConstIter appearedIter = trigger->__appearedRects.begin();
+               for (; appearedIter != trigger->__appearedRects.end(); ++appearedIter)
+                       trigger->__trackedRects.push_back(
+                                       TrackedRectangle(*appearedIter, 7));
+
+               trigger->__appearedRects.clear();
+
+               TrackedRectanglesIter iter = trigger->__trackedRects.begin();
+               while (iter != trigger->__trackedRects.end()) {
+                       bool tracked = false;
+
+                       for (size_t j = 0u; j < numberOfMovementRegions; ++j) {
+                               cv::Rect rect = iter->rect;
+                               if ((rect & movementRegions[j]).area() != 0 &&
+                                               movementRegions[j].area() <= 3 * rect.area() / 2) {
+                                       cv::Rect r1 = rect | movementRegions[j];
+                                       const int dx = r1.width - rect.width;
+                                       const int dy = r1.height - rect.height;
+
+                                       if (r1.x < movementRegions[j].x)
+                                               r1.x += dx;
+                                       else if (r1.x > movementRegions[j].x)
+                                               r1.x -= dx;
+
+                                       if (r1.y < movementRegions[j].y)
+                                               r1.y += dy;
+                                       else if (r1.y > movementRegions[j].y)
+                                               r1.y -= dy;
+
+                                       r1.height = rect.height;
+                                       r1.width = rect.width;
+
+                                       iter->rect = r1;
+
+                                       tracked = true;
+                               }
+                       }
+
+                       if (tracked)
+                               ++iter;
+                       else {
+                               if (iter->framesCount == 0) {
+                                       trigger->__disappearedRects.push_back(iter->rect);
+                                       iter = trigger->__trackedRects.erase(iter);
+                               }
+                               else {
+                                       --(iter->framesCount);
+                                       ++iter;
+                               }
+                       }
+               }
+       }
+
+       trigger->__rectToDetectPrevious = trigger->__rectToDetect;
+       ++trigger->__frameCounter;
+
+       /* 5. Update event result and run callbacks */
+       trigger->runCallbacks(source);
+
+       trigger->__disappearedRects.clear();
+}
+
+void EventTriggerPersonAppearance::runCallbacks(mv_source_h source)
+{
+       __eventResult->__appearedLocations.clear();
+       __eventResult->__disappearedLocations.clear();
+       __eventResult->__trackedLocations.clear();
+
+       const size_t appearedLocationsSize = __appearedRects.size();
+       __eventResult->__appearedLocations.resize(appearedLocationsSize);
+
+       for (size_t i = 0u; i < appearedLocationsSize; ++i) {
+               convertRectCV2MV(__appearedRects[i],
+                               __eventResult->__appearedLocations[i]);
+               __eventResult->__appearedLocations[i].point.x /= __factorX;
+               __eventResult->__appearedLocations[i].point.y /= __factorY;
+               __eventResult->__appearedLocations[i].width /= __factorX;
+               __eventResult->__appearedLocations[i].height /= __factorY;
+       }
+
+       const size_t disappearedLocationsSize = __disappearedRects.size();
+       __eventResult->__disappearedLocations.resize(disappearedLocationsSize);
+
+       for (size_t i = 0u; i < disappearedLocationsSize; ++i) {
+               convertRectCV2MV(__disappearedRects[i],
+                               __eventResult->__disappearedLocations[i]);
+               __eventResult->__disappearedLocations[i].point.x /= __factorX;
+               __eventResult->__disappearedLocations[i].point.y /= __factorY;
+               __eventResult->__disappearedLocations[i].width /= __factorX;
+               __eventResult->__disappearedLocations[i].height /= __factorY;
+       }
+
+       const size_t trackedLocationsSize = __trackedRects.size();
+       __eventResult->__trackedLocations.resize(trackedLocationsSize);
+
+       TrackedRectanglesConstIter trackedIter = __trackedRects.begin();
+       for (size_t i = 0u; i < trackedLocationsSize; ++i, ++trackedIter) {
+               convertRectCV2MV(trackedIter->rect,
+                               __eventResult->__trackedLocations[i]);
+               __eventResult->__trackedLocations[i].point.x /= __factorX;
+               __eventResult->__trackedLocations[i].point.y /= __factorY;
+               __eventResult->__trackedLocations[i].width /= __factorX;
+               __eventResult->__trackedLocations[i].height /= __factorY;
+       }
+
+       // Don't invoke the callback if no appearance, disappearance or tracking
+       if (appearedLocationsSize > 0 || disappearedLocationsSize > 0
+                       || trackedLocationsSize > 0) {
+               CallbackDataMapConstIter iter = __callbackDataMap.begin();
+
+               for (; iter != __callbackDataMap.end(); ++iter) {
+                       mv_surveillance_event_occurred_cb callback = iter->second.callback;
+                       callback(iter->second.eventTrigger, source, __videoStreamId,
+                                       __eventResult, iter->second.userData);
+               }
+       }
+}
+
+} /* surveillance */
+} /* mediavision */
diff --git a/mv_surveillance/surveillance/src/EventTriggerPersonRecognition.cpp b/mv_surveillance/surveillance/src/EventTriggerPersonRecognition.cpp
new file mode 100644 (file)
index 0000000..7b28709
--- /dev/null
@@ -0,0 +1,397 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "EventTriggerPersonRecognition.h"
+#include "EventManager.h"
+
+#include <mv_private.h>
+#include <mv_face.h>
+#include <mv_surveillance.h>
+
+#include <sstream>
+
+namespace mediavision {
+namespace surveillance {
+
+static const int MAX_VALUE_NAME_LENGHT = 255;
+
+namespace {
+
+template <typename T>
+std::string numberToString(T Number)
+{
+       std::ostringstream ss;
+       ss << Number;
+       return ss.str();
+}
+
+} /* Anonymous namespace*/
+
+int EventResultPersonRecognition::getResultValue(
+       const char *valueName,
+       void *value) const
+{
+       if (valueName == NULL) {
+               LOGE("Invalid pointer for value name. Getting result value failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       if (value == NULL) {
+               LOGE("Invalid pointer for value. Getting result value failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       const size_t numberOfPersons = __locations.size();
+
+       if (strncmp(valueName,
+                               MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER,
+                               MAX_VALUE_NAME_LENGHT) == 0) {
+               size_t *outNumberOfPersons = (size_t*) value;
+               *outNumberOfPersons = numberOfPersons;
+       } else if (strncmp(valueName,
+                                               MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS,
+                                               MAX_VALUE_NAME_LENGHT) == 0) {
+               mv_rectangle_s *locations = (mv_rectangle_s*) value;
+
+               for (size_t i = 0; i < numberOfPersons; ++i)
+                       locations[i] = __locations[i];
+       } else if (strncmp(valueName,
+                                               MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS,
+                                               MAX_VALUE_NAME_LENGHT) == 0) {
+               int *labels = (int*) value;
+
+               for (size_t i = 0; i < numberOfPersons; ++i)
+                       labels[i] = __faceLabels[i];
+       } else if (strncmp(valueName,
+                                               MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES,
+                                               MAX_VALUE_NAME_LENGHT) == 0) {
+               double *confidences = (double*) value;
+
+               for (size_t i = 0; i < numberOfPersons; ++i)
+                       confidences[i] = __confidences[i];
+       } else {
+               LOGE("This value name doesn't exist. Getting result value failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+EventTriggerPersonRecognition::EventTriggerPersonRecognition(
+               mv_surveillance_event_trigger_h eventTrigger,
+               long int triggerId,
+               int videoStreamId,
+               mv_surveillance_event_occurred_cb callback,
+               void *userData,
+               int numberOfPoints,
+               mv_point_s *roi) : EventTrigger(eventTrigger,
+                                                                               triggerId,
+                                                                               videoStreamId,
+                                                                               callback,
+                                                                               userData,
+                                                                               numberOfPoints,
+                                                                               roi),
+       __faceRecognitionModel(NULL),
+       __lastFrame(NULL),
+       __eventResult(new EventResultPersonRecognition())
+{
+       ; /* NULL */
+}
+
+EventTriggerPersonRecognition::~EventTriggerPersonRecognition()
+{
+       if (NULL != __faceRecognitionModel) {
+               const int err = mv_face_recognition_model_destroy(__faceRecognitionModel);
+               if (MEDIA_VISION_ERROR_NONE != err)
+                       LOGE("Error while trying to delete face recognition model when "
+                                       "event trigger had been destroyed. Error code: %i.", err);
+       }
+
+       delete __eventResult;
+}
+
+int EventTriggerPersonRecognition::parseEngineConfig(mv_engine_config_h engineConfig)
+{
+       if (engineConfig == NULL) {
+               LOGE("Engine configuration is NULL. Parsing failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       char *modelPath = NULL;
+
+       int error = mv_engine_config_get_string_attribute(
+                       engineConfig,
+                       MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH,
+                       &modelPath);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               if (modelPath != NULL)
+                       delete[] modelPath;
+
+               LOGE("Getting recognition model from engine configuration failed.");
+
+               return error;
+       }
+
+       mv_face_recognition_model_h recognitionModel = NULL;
+
+       error = mv_face_recognition_model_load(modelPath, &recognitionModel);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               LOGE("Loading recognition model from file %s failed.",
+                               modelPath);
+
+               if (modelPath != NULL)
+                       delete[] modelPath;
+
+               return error;
+       }
+
+       if (NULL != __faceRecognitionModel) {
+               error = mv_face_recognition_model_destroy(__faceRecognitionModel);
+               if (MEDIA_VISION_ERROR_NONE != error) {
+                       LOGE("Error while trying to delete old face recognition model when "
+                                       "new model is trying to be loaded. Error code: %i.", error);
+               }
+       }
+
+       __faceRecognitionModel = recognitionModel;
+
+       if (NULL == __faceRecognitionModel) {
+               LOGE("Failed to load face recognition model. Check %s attribute of the "
+                               "engine config.", MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH);
+
+               if (modelPath != NULL)
+                       delete[] modelPath;
+
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       if (modelPath != NULL)
+               delete[] modelPath;
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int EventTriggerPersonRecognition::pushSource(
+               mv_source_h source,
+               mv_source_h graySource,
+               const cv::Mat& grayImage)
+{
+       if (source == NULL || graySource == NULL || grayImage.empty()) {
+               LOGE("Media source is NULL. Pushing source failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       __lastFrame = source;
+
+       __eventResult->__locations.clear();
+       __eventResult->__faceLabels.clear();
+       __eventResult->__confidences.clear();
+
+       unsigned char *data_buffer = NULL;
+       unsigned int buffer_size = 0;
+       mv_colorspace_e colorspace = MEDIA_VISION_COLORSPACE_INVALID;
+       unsigned int width = 0;
+       unsigned int height = 0;
+
+       int error = mv_source_get_buffer(graySource, &data_buffer, &buffer_size);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               LOGE("Operation with media source failed with error %d.", error);
+               return error;
+       }
+
+       error = mv_source_get_colorspace(graySource, &colorspace);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               LOGE("Operation with media source failed with error %d.", error);
+               return error;
+       }
+
+       error = mv_source_get_width(graySource, &width);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               LOGE("Operation with media source failed with error %d.", error);
+               return error;
+       }
+
+       error = mv_source_get_height(graySource, &height);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               LOGE("Operation with media source failed with error %d.", error);
+               return error;
+       }
+
+       if (buffer_size != width * height)
+       {
+               // Unexcepted behaviour
+               LOGE("Grayscale source interpretation failed.");
+               return MEDIA_VISION_ERROR_INTERNAL;
+       }
+
+       mv_source_h sourceCopy = NULL;
+
+       error = mv_create_source(&sourceCopy);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               LOGE("Operation with media source failed with error %d.", error);
+               return error;
+       }
+
+       error = mv_source_fill_by_buffer(sourceCopy, data_buffer, buffer_size,
+                       width, height, colorspace);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               mv_destroy_source(sourceCopy);
+               LOGE("Operation with media source failed with error %d.", error);
+               return error;
+       }
+
+       error = mv_source_get_buffer(sourceCopy, &data_buffer, &buffer_size);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               mv_destroy_source(sourceCopy);
+               LOGE("Operation with media source failed with error %d.", error);
+               return error;
+       }
+
+       error = applyROIToImage(data_buffer, width, height);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               mv_destroy_source(sourceCopy);
+               LOGE("Applying ROI failed with error %d.", error);
+               return error;
+       }
+
+       error = mv_face_detect(sourceCopy, NULL, faceDetectedCB, this);
+
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               mv_destroy_source(sourceCopy);
+               LOGE("Errors were occurred during face detecting %i", error);
+               return error;
+       }
+
+       error = mv_destroy_source(sourceCopy);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               LOGE("Operation with media source failed with error %d.", error);
+               return error;
+       }
+
+       return error;
+}
+
+std::string EventTriggerPersonRecognition::getEventType() const
+{
+       return MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED;
+}
+
+bool EventTriggerPersonRecognition::operator==(const EventTriggerPersonRecognition& other) const
+{
+       if (EventTrigger::operator !=(other))
+               return false;
+
+       /* TODO: compare private values if necessary */
+
+       return true;
+}
+
+bool EventTriggerPersonRecognition::operator!=(const EventTriggerPersonRecognition& other) const
+{
+       return !(*this == other);
+}
+
+void EventTriggerPersonRecognition::setEventResults(
+               mv_rectangle_s faceLocation,
+               int faceLabel,
+               double confidence)
+{
+       __eventResult->__locations.push_back(faceLocation);
+       __eventResult->__faceLabels.push_back(faceLabel);
+       __eventResult->__confidences.push_back(confidence);
+}
+
+void EventTriggerPersonRecognition::faceDetectedCB(
+               mv_source_h source,
+               mv_engine_config_h /*engine_cfg*/,
+               mv_rectangle_s *faces_locations,
+               int number_of_faces,
+               void *user_data)
+{
+       if (NULL == user_data) {
+               LOGE("Invalid user data passed");
+               return;
+       }
+
+       EventTriggerPersonRecognition *recognitionTrigger =
+               (EventTriggerPersonRecognition*)user_data;
+
+       int location_idx = 0;
+       for (; location_idx < number_of_faces; ++location_idx) {
+               LOGI("Start surveillance face recognition");
+
+               const int error = mv_face_recognize(
+                               source,
+                               recognitionTrigger->__faceRecognitionModel,
+                               NULL,
+                               &faces_locations[location_idx],
+                               faceRecognizedCB,
+                               recognitionTrigger);
+
+               if (error != MEDIA_VISION_ERROR_NONE) {
+                       LOGW("Face recognition for one model failed. Continue");
+                       continue;
+               }
+
+               LOGI("Face has been successfully recognized");
+       }
+}
+
+void EventTriggerPersonRecognition::faceRecognizedCB(
+               mv_source_h source,
+               mv_face_recognition_model_h /*recognition_model*/,
+               mv_engine_config_h /*engine_cfg*/,
+               mv_rectangle_s *face_location,
+               const int *face_label,
+               double confidence,
+               void *user_data)
+{
+       if (face_location == NULL || face_label == NULL) {
+               LOGI("Face wasn't recognized");
+               return;
+       }
+
+       EventTriggerPersonRecognition *trigger =
+               (EventTriggerPersonRecognition*) user_data;
+
+       trigger->setEventResults(*face_location, *face_label, confidence);
+
+       CallbackDataMapConstIter iter = trigger->__callbackDataMap.begin();
+
+       for (; iter != trigger->__callbackDataMap.end(); ++iter) {
+               mv_surveillance_event_occurred_cb callback = iter->second.callback;
+               callback(
+                       iter->second.eventTrigger,
+                       trigger->__lastFrame,
+                       trigger->__videoStreamId,
+                       trigger->__eventResult,
+                       iter->second.userData);
+       }
+}
+
+} /* surveillance */
+} /* mediavision */
diff --git a/mv_surveillance/surveillance/src/HoGDetector.cpp b/mv_surveillance/surveillance/src/HoGDetector.cpp
new file mode 100644 (file)
index 0000000..4d1ea0c
--- /dev/null
@@ -0,0 +1,1006 @@
+/*M///////////////////////////////////////////////////////////////////////////////////////
+//
+//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
+//
+//  By downloading, copying, installing or using the software you agree to this license.
+//  If you do not agree to this license, do not download, install,
+//  copy or use the software.
+//
+//
+//                           License Agreement
+//                For Open Source Computer Vision Library
+//
+// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
+// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
+// Third party copyrights are property of their respective owners.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+//   * Redistribution's of source code must retain the above copyright notice,
+//     this list of conditions and the following disclaimer.
+//
+//   * Redistribution's in binary form must reproduce the above copyright notice,
+//     this list of conditions and the following disclaimer in the documentation
+//     and/or other materials provided with the distribution.
+//
+//   * The name of the copyright holders may not be used to endorse or promote products
+//     derived from this software without specific prior written permission.
+//
+// This software is provided by the copyright holders and contributors "as is" and
+// any express or implied warranties, including, but not limited to, the implied
+// warranties of merchantability and fitness for a particular purpose are disclaimed.
+// In no event shall the Intel Corporation or contributors be liable for any direct,
+// indirect, incidental, special, exemplary, or consequential damages
+// (including, but not limited to, procurement of substitute goods or services;
+// loss of use, data, or profits; or business interruption) however caused
+// and on any theory of liability, whether in contract, strict liability,
+// or tort (including negligence or otherwise) arising in any way out of
+// the use of this software, even if advised of the possibility of such damage.
+//
+//M*/
+#include <stdio.h>
+#include "HoGDetector.h"
+#include "opencv2/imgproc/imgproc.hpp"
+#include <iterator>
+
+#ifdef ENABLE_NEON
+#include <arm_neon.h>
+#endif
+
+#ifdef ENABLE_OMP
+#include <sched.h>
+#define NCORES 4
+static int coreids[NCORES] = {1, 2, 3, 4};
+#endif
+
+/****************************************************************************************\
+      The code below is implementation of HOG (Histogram-of-Oriented Gradients)
+      descriptor and object detection, introduced by Navneet Dalal and Bill Triggs.
+
+      The computed feature vectors are compatible with the
+      INRIA Object Detection and Localization Toolkit
+      (http://pascal.inrialpes.fr/soft/olt/)
+\****************************************************************************************/
+
+namespace modifiedcv {
+
+class ParallelLoopBodyWrapper {
+public:
+       ParallelLoopBodyWrapper(const cv::ParallelLoopBody& _body, const cv::Range& _r) {
+               body = &_body;
+               wholeRange = _r;
+               nstripes = cvRound(wholeRange.end - wholeRange.start);
+       }
+       void operator()(const cv::Range& sr) const {
+               cv::Range r;
+               r.start = (int)(wholeRange.start +
+                                               ((uint64)sr.start*(wholeRange.end - wholeRange.start) + nstripes/2)/nstripes);
+               r.end = sr.end >= nstripes ? wholeRange.end : (int)(wholeRange.start +
+                               ((uint64)sr.end*(wholeRange.end - wholeRange.start) + nstripes/2)/nstripes);
+               (*body)(r);
+       }
+       cv::Range stripeRange() const {
+               return cv::Range(0, nstripes);
+       }
+
+protected:
+       const cv::ParallelLoopBody* body;
+       cv::Range wholeRange;
+       int nstripes;
+};
+
+void parallel_for_(const cv::Range& range, const cv::ParallelLoopBody& body)
+{
+#if defined ENABLE_OMP
+       ParallelLoopBodyWrapper pbody(body, range);
+       cv::Range stripeRange = pbody.stripeRange();
+       int i = 0;
+       #pragma omp parallel for private(i) num_threads(NCORES)
+       for (i = stripeRange.start; i < stripeRange.end; ++i) {
+               cpu_set_t mask;
+               CPU_ZERO(&mask);
+               CPU_SET(coreids[i % 4], &mask);
+
+               if (sched_setaffinity (0, sizeof(mask), &mask) == -1) {
+                       printf("Could not set CPU Affinity, continuing...");
+               }
+
+               pbody(Range(i, i + 1));
+       }
+#else
+       cv::parallel_for_(range, body);
+#endif
+}
+
+size_t HOGDescriptor::getDescriptorSize() const
+{
+       return (size_t)nbins*
+               (blockSize.width/cellSize.width)*
+               (blockSize.height/cellSize.height)*
+               ((winSize.width - blockSize.width)/blockStride.width + 1)*
+               ((winSize.height - blockSize.height)/blockStride.height + 1);
+}
+
+double HOGDescriptor::getWinSigma() const
+{
+       return winSigma >= 0 ? winSigma : (blockSize.width + blockSize.height)/8.;
+}
+
+bool HOGDescriptor::checkDetectorSize() const
+{
+       size_t detectorSize = svmDetector.size(), descriptorSize = getDescriptorSize();
+       return detectorSize == 0 ||
+               detectorSize == descriptorSize ||
+               detectorSize == descriptorSize + 1;
+}
+
+void HOGDescriptor::setSVMDetector(InputArray _svmDetector)
+{
+       _svmDetector.getMat().convertTo(svmDetector, CV_32F);
+       CV_Assert(checkDetectorSize());
+}
+
+void HOGDescriptor::computeGradient(const Mat& img, Mat& grad, Mat& qangle,
+                                                                       Size paddingTL, Size paddingBR) const
+{
+       CV_Assert(img.type() == CV_8U);
+
+       Size gradsize(img.cols + paddingTL.width + paddingBR.width,
+                       img.rows + paddingTL.height + paddingBR.height);
+       grad.create(gradsize, CV_32FC2);  /* <magnitude*(1-alpha), magnitude*alpha> */
+       qangle.create(gradsize, CV_8UC2); /* [0..nbins-1] - quantized gradient orientation */
+       Size wholeSize;
+       Point roiofs;
+       img.locateROI(wholeSize, roiofs);
+
+       int i, x, y;
+       /*    int cn = img.channels(); */
+
+       Mat_<float> _lut(1, 256);
+       const float* lut = &_lut(0, 0);
+
+       if ( gammaCorrection )
+               for ( i = 0; i < 256; i++ )
+                       _lut(0, i) = std::sqrt((float)i);
+       else
+               for ( i = 0; i < 256; i++ )
+                       _lut(0, i) = (float)i;
+
+       AutoBuffer<int> mapbuf(gradsize.width + gradsize.height + 4);
+       int* xmap = (int*)mapbuf + 1;
+       int* ymap = xmap + gradsize.width + 2;
+
+       const int borderType = (int)cv::BORDER_REFLECT_101;
+
+       for ( x = -1; x < gradsize.width + 1; x++ )
+               xmap[x] = cv::borderInterpolate(x - paddingTL.width + roiofs.x,
+                               wholeSize.width, borderType) - roiofs.x;
+       for ( y = -1; y < gradsize.height + 1; y++ )
+               ymap[y] = cv::borderInterpolate(y - paddingTL.height + roiofs.y,
+                               wholeSize.height, borderType) - roiofs.y;
+
+       /* x- & y- derivatives for the whole row */
+       int width = gradsize.width;
+       AutoBuffer<float> _dbuf(width*4);
+       float* dbuf = _dbuf;
+       Mat Dx(1, width, CV_32F, dbuf);
+       Mat Dy(1, width, CV_32F, dbuf + width);
+       Mat Mag(1, width, CV_32F, dbuf + width*2);
+       Mat Angle(1, width, CV_32F, dbuf + width*3);
+
+       int _nbins = nbins;
+       float angleScale = (float)(_nbins/CV_PI);
+
+       for ( y = 0; y < gradsize.height; y++ ) {
+               const uchar* imgPtr  = img.data + img.step*ymap[y];
+               const uchar* prevPtr = img.data + img.step*ymap[y-1];
+               const uchar* nextPtr = img.data + img.step*ymap[y+1];
+               float* gradPtr = (float*)grad.ptr(y);
+               uchar* qanglePtr = (uchar*)qangle.ptr(y);
+
+               for (x = 0; x < width; x++) {
+                       int x1 = xmap[x];
+                       dbuf[x] = (float)(lut[imgPtr[xmap[x+1]]] - lut[imgPtr[xmap[x-1]]]);
+                       dbuf[width + x] = (float)(lut[nextPtr[x1]] - lut[prevPtr[x1]]);
+               }
+
+               cartToPolar(Dx, Dy, Mag, Angle, false);
+
+               for (x = 0; x < width; x++) {
+                       float mag = dbuf[x+width*2], angle = dbuf[x+width*3]*angleScale - 0.5f;
+                       int hidx = cvFloor(angle);
+                       angle -= hidx;
+                       gradPtr[x*2] = mag*(1.f - angle);
+                       gradPtr[x*2+1] = mag*angle;
+
+                       if ( hidx < 0 )
+                               hidx += _nbins;
+                       else if ( hidx >= _nbins )
+                               hidx -= _nbins;
+                       assert((unsigned)hidx < (unsigned)_nbins);
+
+                       qanglePtr[x*2] = (uchar)hidx;
+                       hidx++;
+                       hidx &= hidx < _nbins ? -1 : 0;
+                       qanglePtr[x*2+1] = (uchar)hidx;
+               }
+       }
+}
+
+
+struct HOGCache {
+       struct BlockData {
+               BlockData() : histOfs(0), imgOffset() {}
+               int histOfs;
+               Point imgOffset;
+       };
+
+       struct PixData {
+               size_t gradOfs, qangleOfs;
+               int histOfs[4];
+               float histWeights[4];
+               float gradWeight;
+       };
+
+       HOGCache();
+       HOGCache(const HOGDescriptor* descriptor,
+                       const Mat& img, Size paddingTL, Size paddingBR,
+                       bool useCache, Size cacheStride);
+       virtual ~HOGCache() {};
+       virtual void init(const HOGDescriptor* descriptor,
+                       const Mat& img, Size paddingTL, Size paddingBR,
+                       bool useCache, Size cacheStride);
+
+       Size windowsInImage(Size imageSize, Size winStride) const;
+       Rect getWindow(Size imageSize, Size winStride, int idx) const;
+
+       const float* getBlock(Point pt, float* buf);
+       virtual void normalizeBlockHistogram(float* histogram) const;
+
+       vector<PixData> pixData;
+       vector<BlockData> blockData;
+
+       bool useCache;
+       vector<int> ymaxCached;
+       Size winSize, cacheStride;
+       Size nblocks, ncells;
+       int blockHistogramSize;
+       int count1, count2, count4;
+       Point imgoffset;
+       Mat_<float> blockCache;
+       Mat_<uchar> blockCacheFlags;
+
+       Mat grad, qangle;
+       const HOGDescriptor* descriptor;
+};
+
+
+HOGCache::HOGCache()
+{
+       useCache = false;
+       blockHistogramSize = count1 = count2 = count4 = 0;
+       descriptor = 0;
+}
+
+HOGCache::HOGCache(const HOGDescriptor* _descriptor,
+               const Mat& _img, Size _paddingTL, Size _paddingBR,
+               bool _useCache, Size _cacheStride)
+{
+       init(_descriptor, _img, _paddingTL, _paddingBR, _useCache, _cacheStride);
+}
+
+void HOGCache::init(const HOGDescriptor* _descriptor,
+               const Mat& _img, Size _paddingTL, Size _paddingBR,
+               bool _useCache, Size _cacheStride)
+{
+       descriptor = _descriptor;
+       cacheStride = _cacheStride;
+       useCache = _useCache;
+
+       descriptor->computeGradient(_img, grad, qangle, _paddingTL, _paddingBR);
+       imgoffset = _paddingTL;
+
+       winSize = descriptor->winSize;
+       Size blockSize = descriptor->blockSize;
+       Size blockStride = descriptor->blockStride;
+       Size cellSize = descriptor->cellSize;
+       int i, j, nbins = descriptor->nbins;
+       int rawBlockSize = blockSize.width*blockSize.height;
+
+       nblocks = Size((winSize.width - blockSize.width)/blockStride.width + 1,
+                       (winSize.height - blockSize.height)/blockStride.height + 1);
+       ncells = Size(blockSize.width/cellSize.width, blockSize.height/cellSize.height);
+       blockHistogramSize = ncells.width*ncells.height*nbins;
+
+       if ( useCache ) {
+               Size cacheSize((grad.cols - blockSize.width)/cacheStride.width+1,
+                               (winSize.height/cacheStride.height)+1);
+               blockCache.create(cacheSize.height, cacheSize.width*blockHistogramSize);
+               blockCacheFlags.create(cacheSize);
+               size_t cacheRows = blockCache.rows;
+               ymaxCached.resize(cacheRows);
+               for (size_t ii = 0; ii < cacheRows; ii++ )
+                       ymaxCached[ii] = -1;
+       }
+
+       Mat_<float> weights(blockSize);
+       float sigma = (float)descriptor->getWinSigma();
+       float scale = 1.f/(sigma*sigma*2);
+
+       float blockHalfHeight = blockSize.height*0.5f;
+       float blockHalfWidth = blockSize.width*0.5f;
+       for (i = 0; i < blockSize.height; i++)
+               for (j = 0; j < blockSize.width; j++) {
+                       float di = i - blockHalfHeight;
+                       float dj = j - blockHalfWidth;
+                       weights(i, j) = std::exp(-(di*di + dj*dj)*scale);
+               }
+
+       blockData.resize(nblocks.width*nblocks.height);
+       pixData.resize(rawBlockSize*3);
+
+       /*
+        * Initialize 2 lookup tables, pixData & blockData.
+        * Here is why:
+        *
+        * The detection algorithm runs in 4 nested loops (at each pyramid layer):
+        *  loop over the windows within the input image
+        *    loop over the blocks within each window
+        *      loop over the cells within each block
+        *        loop over the pixels in each cell
+        *
+        * As each of the loops runs over a 2-dimensional array,
+        * we could get 8(!) nested loops in total, which is very-very slow.
+        *
+        * To speed the things up, we do the following:
+        *   1. loop over windows is unrolled in the HOGDescriptor::{compute|detect} methods;
+        *         inside we compute the current search window using getWindow() method.
+        *         Yes, it involves some overhead (function call + couple of divisions),
+        *         but it's tiny in fact.
+        *   2. loop over the blocks is also unrolled. Inside we use pre-computed blockData[j]
+        *         to set up gradient and histogram pointers.
+        *   3. loops over cells and pixels in each cell are merged
+        *       (since there is no overlap between cells, each pixel in the block is processed once)
+        *      and also unrolled. Inside we use PixData[k] to access the gradient values and
+        *      update the histogram
+        */
+
+       count1 = count2 = count4 = 0;
+       for ( j = 0; j < blockSize.width; j++ )
+               for ( i = 0; i < blockSize.height; i++ ) {
+                       PixData* data = 0;
+                       float cellX = (j+0.5f)/cellSize.width - 0.5f;
+                       float cellY = (i+0.5f)/cellSize.height - 0.5f;
+                       int icellX0 = cvFloor(cellX);
+                       int icellY0 = cvFloor(cellY);
+                       int icellX1 = icellX0 + 1, icellY1 = icellY0 + 1;
+                       cellX -= icellX0;
+                       cellY -= icellY0;
+
+                       if ( (unsigned)icellX0 < (unsigned)ncells.width &&
+                                       (unsigned)icellX1 < (unsigned)ncells.width ) {
+                               if ( (unsigned)icellY0 < (unsigned)ncells.height &&
+                                               (unsigned)icellY1 < (unsigned)ncells.height ) {
+                                       data = &pixData[rawBlockSize*2 + (count4++)];
+                                       data->histOfs[0] = (icellX0*ncells.height + icellY0)*nbins;
+                                       data->histWeights[0] = (1.f - cellX)*(1.f - cellY);
+                                       data->histOfs[1] = (icellX1*ncells.height + icellY0)*nbins;
+                                       data->histWeights[1] = cellX*(1.f - cellY);
+                                       data->histOfs[2] = (icellX0*ncells.height + icellY1)*nbins;
+                                       data->histWeights[2] = (1.f - cellX)*cellY;
+                                       data->histOfs[3] = (icellX1*ncells.height + icellY1)*nbins;
+                                       data->histWeights[3] = cellX*cellY;
+                               } else {
+                                       data = &pixData[rawBlockSize + (count2++)];
+                                       if ( (unsigned)icellY0 < (unsigned)ncells.height ) {
+                                               icellY1 = icellY0;
+                                               cellY = 1.f - cellY;
+                                       }
+                                       data->histOfs[0] = (icellX0*ncells.height + icellY1)*nbins;
+                                       data->histWeights[0] = (1.f - cellX)*cellY;
+                                       data->histOfs[1] = (icellX1*ncells.height + icellY1)*nbins;
+                                       data->histWeights[1] = cellX*cellY;
+                                       data->histOfs[2] = data->histOfs[3] = 0;
+                                       data->histWeights[2] = data->histWeights[3] = 0;
+                               }
+                       } else {
+                               if ( (unsigned)icellX0 < (unsigned)ncells.width ) {
+                                       icellX1 = icellX0;
+                                       cellX = 1.f - cellX;
+                               }
+
+                               if ( (unsigned)icellY0 < (unsigned)ncells.height &&
+                                               (unsigned)icellY1 < (unsigned)ncells.height ) {
+                                       data = &pixData[rawBlockSize + (count2++)];
+                                       data->histOfs[0] = (icellX1*ncells.height + icellY0)*nbins;
+                                       data->histWeights[0] = cellX*(1.f - cellY);
+                                       data->histOfs[1] = (icellX1*ncells.height + icellY1)*nbins;
+                                       data->histWeights[1] = cellX*cellY;
+                                       data->histOfs[2] = data->histOfs[3] = 0;
+                                       data->histWeights[2] = data->histWeights[3] = 0;
+                               } else {
+                                       data = &pixData[count1++];
+                                       if ( (unsigned)icellY0 < (unsigned)ncells.height ) {
+                                               icellY1 = icellY0;
+                                               cellY = 1.f - cellY;
+                                       }
+                                       data->histOfs[0] = (icellX1*ncells.height + icellY1)*nbins;
+                                       data->histWeights[0] = cellX*cellY;
+                                       data->histOfs[1] = data->histOfs[2] = data->histOfs[3] = 0;
+                                       data->histWeights[1] = data->histWeights[2] = data->histWeights[3] = 0;
+                               }
+                       }
+                       data->gradOfs = (grad.cols*i + j)*2;
+                       data->qangleOfs = (qangle.cols*i + j)*2;
+                       data->gradWeight = weights(i, j);
+               }
+
+       assert(count1 + count2 + count4 == rawBlockSize);
+       /* defragment pixData */
+       for ( j = 0; j < count2; j++ )
+               pixData[j + count1] = pixData[j + rawBlockSize];
+       for ( j = 0; j < count4; j++ )
+               pixData[j + count1 + count2] = pixData[j + rawBlockSize*2];
+       count2 += count1;
+       count4 += count2;
+
+       /* initialize blockData */
+       for ( j = 0; j < nblocks.width; j++ )
+               for ( i = 0; i < nblocks.height; i++ ) {
+                       BlockData& data = blockData[j*nblocks.height + i];
+                       data.histOfs = (j*nblocks.height + i)*blockHistogramSize;
+                       data.imgOffset = Point(j*blockStride.width, i*blockStride.height);
+               }
+}
+
+
+const float* HOGCache::getBlock(Point pt, float* buf)
+{
+       float* blockHist = buf;
+       assert(descriptor != 0);
+
+       Size blockSize = descriptor->blockSize;
+       pt += imgoffset;
+
+       CV_Assert( (unsigned)pt.x <= (unsigned)(grad.cols - blockSize.width) &&
+                       (unsigned)pt.y <= (unsigned)(grad.rows - blockSize.height) );
+
+       if ( useCache ) {
+               CV_Assert(pt.x % cacheStride.width == 0 &&
+                               pt.y % cacheStride.height == 0);
+               Point cacheIdx(pt.x/cacheStride.width,
+                               (pt.y/cacheStride.height) % blockCache.rows);
+               if ( pt.y != ymaxCached[cacheIdx.y] ) {
+                       Mat_<uchar> cacheRow = blockCacheFlags.row(cacheIdx.y);
+                       cacheRow = (uchar)0;
+                       ymaxCached[cacheIdx.y] = pt.y;
+               }
+
+               blockHist = &blockCache[cacheIdx.y][cacheIdx.x*blockHistogramSize];
+               uchar& computedFlag = blockCacheFlags(cacheIdx.y, cacheIdx.x);
+               if ( computedFlag != 0 )
+                       return blockHist;
+               computedFlag = (uchar)1; /* set it at once, before actual computing */
+       }
+
+       int k, C1 = count1, C2 = count2, C4 = count4;
+       const float* gradPtr = (const float*)(grad.data + grad.step*pt.y) + pt.x*2;
+       const uchar* qanglePtr = qangle.data + qangle.step*pt.y + pt.x*2;
+
+       CV_Assert(blockHist != 0);
+       for ( k = 0; k < blockHistogramSize; k++ )
+               blockHist[k] = 0.f;
+
+       const PixData* _pixData = &pixData[0];
+
+       for ( k = 0; k < C1; k++ ) {
+               const PixData& pk = _pixData[k];
+               const float* a = gradPtr + pk.gradOfs;
+               float w = pk.gradWeight*pk.histWeights[0];
+               const uchar* h = qanglePtr + pk.qangleOfs;
+               int h0 = h[0], h1 = h[1];
+               float* hist = blockHist + pk.histOfs[0];
+               float t0 = hist[h0] + a[0]*w;
+               float t1 = hist[h1] + a[1]*w;
+               hist[h0] = t0;
+               hist[h1] = t1;
+       }
+
+       for ( ; k < C2; k++ ) {
+               const PixData& pk = _pixData[k];
+               const float* a = gradPtr + pk.gradOfs;
+               float w, t0, t1, a0 = a[0], a1 = a[1];
+               const uchar* h = qanglePtr + pk.qangleOfs;
+               int h0 = h[0], h1 = h[1];
+
+               float* hist = blockHist + pk.histOfs[0];
+               w = pk.gradWeight*pk.histWeights[0];
+               t0 = hist[h0] + a0*w;
+               t1 = hist[h1] + a1*w;
+               hist[h0] = t0;
+               hist[h1] = t1;
+
+               hist = blockHist + pk.histOfs[1];
+               w = pk.gradWeight*pk.histWeights[1];
+               t0 = hist[h0] + a0*w;
+               t1 = hist[h1] + a1*w;
+               hist[h0] = t0;
+               hist[h1] = t1;
+       }
+
+       for ( ; k < C4; k++ ) {
+               const PixData& pk = _pixData[k];
+               const float* a = gradPtr + pk.gradOfs;
+               float w, t0, t1, a0 = a[0], a1 = a[1];
+               const uchar* h = qanglePtr + pk.qangleOfs;
+               int h0 = h[0], h1 = h[1];
+
+               float* hist = blockHist + pk.histOfs[0];
+               w = pk.gradWeight*pk.histWeights[0];
+               t0 = hist[h0] + a0*w;
+               t1 = hist[h1] + a1*w;
+               hist[h0] = t0;
+               hist[h1] = t1;
+
+               hist = blockHist + pk.histOfs[1];
+               w = pk.gradWeight*pk.histWeights[1];
+               t0 = hist[h0] + a0*w;
+               t1 = hist[h1] + a1*w;
+               hist[h0] = t0;
+               hist[h1] = t1;
+
+               hist = blockHist + pk.histOfs[2];
+               w = pk.gradWeight*pk.histWeights[2];
+               t0 = hist[h0] + a0*w;
+               t1 = hist[h1] + a1*w;
+               hist[h0] = t0;
+               hist[h1] = t1;
+
+               hist = blockHist + pk.histOfs[3];
+               w = pk.gradWeight*pk.histWeights[3];
+               t0 = hist[h0] + a0*w;
+               t1 = hist[h1] + a1*w;
+               hist[h0] = t0;
+               hist[h1] = t1;
+       }
+
+       normalizeBlockHistogram(blockHist);
+
+       return blockHist;
+}
+
+void HOGCache::normalizeBlockHistogram(float* _hist) const
+{
+#ifdef ENABLE_NEON
+       /* NEON vector for loading the histogram to the memory */
+       float32x4_t hist_v;
+       /* Initialize the accumulator for summation storing */
+       float32x4_t acc = vdupq_n_f32(0.f);
+#endif
+
+       /* Histogram pointer in the memory */
+       float *hist_ptr = &_hist[0];
+       /* Variable to store values of summations */
+       float sum = 0.f;
+       size_t sz = blockHistogramSize;
+
+#ifdef ENABLE_NEON
+       for (; sz != 0u; sz -= 4u) {
+               hist_v = vld1q_f32(hist_ptr);
+               acc = vmlaq_f32(acc, hist_v, hist_v);
+               hist_ptr += 4;
+       }
+
+       sum += vgetq_lane_f32(acc, 0) + vgetq_lane_f32(acc, 1) +
+               vgetq_lane_f32(acc, 2) + vgetq_lane_f32(acc, 3);
+
+       /* Reset accumulator */
+       acc = vdupq_n_f32(0.f);
+
+       sz = blockHistogramSize;
+       hist_ptr = &_hist[0];
+#else
+       for (size_t i = 0; i < sz; ++i)
+               sum += hist_ptr[i] * hist_ptr[i];
+#endif
+
+       float scale = 1.f / (std::sqrt(sum) + sz * 0.1f);
+       sum = 0.f;
+
+#ifdef ENABLE_NEON
+       float32x4_t thres_v = vdupq_n_f32((float)descriptor->L2HysThreshold);
+
+       for (; sz != 0; sz -= 4) {
+               /* Find minimal value among threshold and histogram value, accumulate
+                * this value squared */
+               hist_v = vminq_f32(vmulq_n_f32(vld1q_f32(hist_ptr), scale), thres_v);
+               acc = vmlaq_f32(acc, hist_v, hist_v);
+               /* Update histograms in memory according with found min values */
+               vst1q_f32(hist_ptr, hist_v);
+               hist_ptr += 4;
+       }
+
+       sum += vgetq_lane_f32(acc, 0) + vgetq_lane_f32(acc, 1) +
+               vgetq_lane_f32(acc, 2) + vgetq_lane_f32(acc, 3);
+
+#else
+       float thresh = (float)descriptor->L2HysThreshold;
+       for (size_t i = 0; i < sz; ++i) {
+               hist_ptr[i] = std::min(hist_ptr[i] * scale, thresh);
+               sum += hist_ptr[i] * hist_ptr[i];
+       }
+#endif
+
+       scale = 1.f / (std::sqrt(sum) + 1e-3f);
+
+#ifdef ENABLE_NEON
+       sz = blockHistogramSize;
+       hist_ptr = &_hist[0];
+
+       /* Scale histogram (normalize): */
+       for (; sz != 0; sz -= 4) {
+               vst1q_f32(hist_ptr, vmulq_n_f32(vld1q_f32(hist_ptr), scale));
+               hist_ptr += 4;
+       }
+#else
+       for (size_t i = 0; i < sz; i++ )
+               hist_ptr[i] *= scale;
+#endif
+}
+
+
+Size HOGCache::windowsInImage(Size imageSize, Size winStride) const
+{
+       return Size((imageSize.width - winSize.width)/winStride.width + 1,
+                               (imageSize.height - winSize.height)/winStride.height + 1);
+}
+
+Rect HOGCache::getWindow(Size imageSize, Size winStride, int idx) const
+{
+       int nwindowsX = (imageSize.width - winSize.width)/winStride.width + 1;
+       int y = idx / nwindowsX;
+       int x = idx - nwindowsX*y;
+       return Rect( x*winStride.width, y*winStride.height, winSize.width, winSize.height );
+}
+
+
+void HOGDescriptor::compute(const Mat& img, vector<float>& descriptors,
+                                                       Size winStride, Size padding,
+                                                       const vector<Point>& locations) const
+{
+       if ( winStride == Size() )
+               winStride = cellSize;
+       Size cacheStride(gcd(winStride.width, blockStride.width),
+                       gcd(winStride.height, blockStride.height));
+       size_t nwindows = locations.size();
+       padding.width = (int)alignSize(std::max(padding.width, 0), cacheStride.width);
+       padding.height = (int)alignSize(std::max(padding.height, 0), cacheStride.height);
+       Size paddedImgSize(img.cols + padding.width*2, img.rows + padding.height*2);
+
+       HOGCache cache(this, img, padding, padding, nwindows == 0, cacheStride);
+
+       if ( !nwindows )
+               nwindows = cache.windowsInImage(paddedImgSize, winStride).area();
+
+       const HOGCache::BlockData* blockData = &cache.blockData[0];
+
+       int nblocks = cache.nblocks.area();
+       int blockHistogramSize = cache.blockHistogramSize;
+       size_t dsize = getDescriptorSize();
+       descriptors.resize(dsize*nwindows);
+
+       for ( size_t i = 0; i < nwindows; i++ ) {
+               float* descriptor = &descriptors[i*dsize];
+
+               Point pt0;
+               if ( !locations.empty() ) {
+                       pt0 = locations[i];
+                       if ( pt0.x < -padding.width || pt0.x > img.cols + padding.width - winSize.width ||
+                                       pt0.y < -padding.height || pt0.y > img.rows + padding.height - winSize.height )
+                               continue;
+               } else {
+                       pt0 = cache.getWindow(paddedImgSize, winStride, (int)i).tl() - Point(padding);
+                       CV_Assert(pt0.x % cacheStride.width == 0 && pt0.y % cacheStride.height == 0);
+               }
+
+               for ( int j = 0; j < nblocks; j++ ) {
+                       const HOGCache::BlockData& bj = blockData[j];
+                       Point pt = pt0 + bj.imgOffset;
+
+                       float* dst = descriptor + bj.histOfs;
+                       const float* src = cache.getBlock(pt, dst);
+                       if ( src != dst )
+                               for ( int k = 0; k < blockHistogramSize; k++ )
+                                       dst[k] = src[k];
+               }
+       }
+}
+
+
+void HOGDescriptor::detect(const Mat& img,
+               vector<Point>& hits, vector<double>& weights, double hitThreshold,
+               Size winStride, Size padding, const vector<Point>& locations) const
+{
+       hits.clear();
+       if ( svmDetector.empty() )
+               return;
+
+       if ( winStride == Size() )
+               winStride = cellSize;
+       Size cacheStride(gcd(winStride.width, blockStride.width),
+                       gcd(winStride.height, blockStride.height));
+       size_t nwindows = locations.size();
+       padding.width = (int)alignSize(std::max(padding.width, 0), cacheStride.width);
+       padding.height = (int)alignSize(std::max(padding.height, 0), cacheStride.height);
+       Size paddedImgSize(img.cols + padding.width*2, img.rows + padding.height*2);
+
+       HOGCache cache(this, img, padding, padding, nwindows == 0, cacheStride);
+
+       if ( !nwindows )
+               nwindows = cache.windowsInImage(paddedImgSize, winStride).area();
+
+       const HOGCache::BlockData* blockData = &cache.blockData[0];
+
+       int nblocks = cache.nblocks.area();
+       int blockHistogramSize = cache.blockHistogramSize;
+       size_t dsize = getDescriptorSize();
+
+       double rho = svmDetector.size() > dsize ? svmDetector[dsize] : 0;
+       vector<float> blockHist(blockHistogramSize);
+
+       for ( size_t i = 0; i < nwindows; i++ ) {
+               Point pt0;
+               if ( !locations.empty() ) {
+                       pt0 = locations[i];
+                       if ( pt0.x < -padding.width || pt0.x > img.cols + padding.width - winSize.width ||
+                                       pt0.y < -padding.height || pt0.y > img.rows + padding.height - winSize.height )
+                               continue;
+               } else {
+                       pt0 = cache.getWindow(paddedImgSize, winStride, (int)i).tl() - Point(padding);
+                       CV_Assert(pt0.x % cacheStride.width == 0 && pt0.y % cacheStride.height == 0);
+               }
+               double s = rho;
+               const float* svmVec = &svmDetector[0];
+               int j, k;
+
+               for ( j = 0; j < nblocks; j++, svmVec += blockHistogramSize ) {
+                       const HOGCache::BlockData& bj = blockData[j];
+                       Point pt = pt0 + bj.imgOffset;
+
+                       const float* vec = cache.getBlock(pt, &blockHist[0]);
+#ifdef ENABLE_NEON
+                       float32x4_t vec_v; /* NEON feature vector */
+                       float32x4_t svm_v; /* NEON SVM feature weights */
+                       float32x4_t acc = vdupq_n_f32(0.f); /* NEON partial sum */
+                       for ( k = 0; k <= blockHistogramSize - 4; k += 4 ) {
+                               vec_v = vld1q_f32(vec + k);
+                               svm_v = vld1q_f32(svmVec + k);
+                               acc = vmlaq_f32(acc, vec_v, svm_v);
+                       }
+
+                       s += vgetq_lane_f32(acc, 0) + vgetq_lane_f32(acc, 1) +
+                               vgetq_lane_f32(acc, 2) + vgetq_lane_f32(acc, 3);
+
+#else
+                       for ( k = 0; k <= blockHistogramSize - 4; k += 4 )
+                               s += vec[k]*svmVec[k] + vec[k+1]*svmVec[k+1] +
+                                       vec[k+2]*svmVec[k+2] + vec[k+3]*svmVec[k+3];
+#endif
+                       for ( ; k < blockHistogramSize; k++ )
+                               s += vec[k]*svmVec[k];
+               }
+
+               if ( s >= hitThreshold ) {
+                       hits.push_back(pt0);
+                       weights.push_back(s);
+               }
+       }
+}
+
+void HOGDescriptor::detect(const Mat& img, vector<Point>& hits, double hitThreshold,
+               Size winStride, Size padding, const vector<Point>& locations) const
+{
+       vector<double> weightsV;
+       detect(img, hits, weightsV, hitThreshold, winStride, padding, locations);
+}
+
+class HOGInvoker : public ParallelLoopBody {
+       public:
+               HOGInvoker(const HOGDescriptor* _hog, const Mat& _img,
+                               double _hitThreshold, Size _winStride, Size _padding,
+                               const double* _levelScale, std::vector<Rect> * _vec, Mutex* _mtx,
+                               std::vector<double>* _weights = 0, std::vector<double>* _scales = 0) {
+                       hog = _hog;
+                       img = _img;
+                       hitThreshold = _hitThreshold;
+                       winStride = _winStride;
+                       padding = _padding;
+                       levelScale = _levelScale;
+                       vec = _vec;
+                       weights = _weights;
+                       scales = _scales;
+                       mtx = _mtx;
+               }
+
+               void operator()(const Range& range) const {
+                       int i, i1 = range.start, i2 = range.end;
+                       double minScale = i1 > 0 ? levelScale[i1] : i2 > 1 ? levelScale[i1+1] : std::max(img.cols, img.rows);
+                       Size maxSz(cvCeil(img.cols/minScale), cvCeil(img.rows/minScale));
+                       Mat smallerImgBuf(maxSz, img.type());
+                       vector<Point> locations;
+                       vector<double> hitsWeights;
+
+                       Size wholeSize;
+                       Point offset;
+                       img.locateROI(wholeSize, offset);
+
+                       for ( i = i1; i < i2; i++ ) {
+                               double scale = levelScale[i];
+                               Size sz(cvRound(img.cols/scale), cvRound(img.rows/scale));
+                               Mat smallerImg(sz, img.type(), smallerImgBuf.data);
+                               if (sz == img.size())
+                                       smallerImg = Mat(sz, img.type(), img.data, img.step);
+                               else
+                                       resize(img, smallerImg, sz);
+                               hog->detect(smallerImg, locations, hitsWeights, hitThreshold, winStride, padding);
+
+                               Size scaledWinSize = Size(cvRound(hog->winSize.width*scale), cvRound(hog->winSize.height*scale));
+
+                               mtx->lock();
+                               for ( size_t j = 0; j < locations.size(); j++ ) {
+                                       vec->push_back(Rect(cvRound(locations[j].x*scale),
+                                                               cvRound(locations[j].y*scale),
+                                                               scaledWinSize.width, scaledWinSize.height));
+                                       if (scales) {
+                                               scales->push_back(scale);
+                                       }
+                               }
+                               mtx->unlock();
+
+                               if (weights && (!hitsWeights.empty())) {
+                                       mtx->lock();
+                                       for (size_t j = 0; j < locations.size(); j++) {
+                                               weights->push_back(hitsWeights[j]);
+                                       }
+                                       mtx->unlock();
+                               }
+                       }
+               }
+
+               const HOGDescriptor* hog;
+               Mat img;
+               double hitThreshold;
+               Size winStride;
+               Size padding;
+               const double* levelScale;
+               std::vector<Rect>* vec;
+               std::vector<double>* weights;
+               std::vector<double>* scales;
+               Mutex* mtx;
+};
+
+
+void HOGDescriptor::detectMultiScale(
+               const Mat& img, vector<Rect>& foundLocations, vector<double>& foundWeights,
+               double hitThreshold, Size winStride, Size padding,
+               double scale0, double finalThreshold, bool useMeanshiftGrouping) const
+{
+       double scale = 1.;
+       int levels = 0;
+
+       vector<double> levelScale;
+       for ( levels = 0; levels < nlevels; levels++ ) {
+               levelScale.push_back(scale);
+               if ( cvRound(img.cols/scale) < winSize.width ||
+                               cvRound(img.rows/scale) < winSize.height ||
+                               scale0 <= 1 )
+                       break;
+               scale *= scale0;
+       }
+       levels = std::max(levels, 1);
+       levelScale.resize(levels);
+
+       std::vector<Rect> allCandidates;
+       std::vector<double> tempScales;
+       std::vector<double> tempWeights;
+       std::vector<double> foundScales;
+       Mutex mtx;
+
+       modifiedcv::parallel_for_(Range(0, (int)levelScale.size()),
+                       HOGInvoker(this, img, hitThreshold, winStride, padding, &levelScale[0], &allCandidates, &mtx, &tempWeights, &tempScales));
+
+       std::copy(tempScales.begin(), tempScales.end(), back_inserter(foundScales));
+       foundLocations.clear();
+       std::copy(allCandidates.begin(), allCandidates.end(), back_inserter(foundLocations));
+       foundWeights.clear();
+       std::copy(tempWeights.begin(), tempWeights.end(), back_inserter(foundWeights));
+
+       if ( useMeanshiftGrouping ) {
+               groupRectangles_meanshift(foundLocations, foundWeights, foundScales, finalThreshold, winSize);
+       } else {
+               groupRectangles(foundLocations, foundWeights, (int)finalThreshold, 0.2);
+       }
+}
+
+void HOGDescriptor::detectMultiScale(const Mat& img, vector<Rect>& foundLocations,
+               double hitThreshold, Size winStride, Size padding,
+               double scale0, double finalThreshold, bool useMeanshiftGrouping) const
+{
+       vector<double> foundWeights;
+       detectMultiScale(img, foundLocations, foundWeights, hitThreshold, winStride,
+                       padding, scale0, finalThreshold, useMeanshiftGrouping);
+}
+
+void HOGDescriptor::groupRectangles(vector<cv::Rect>& rectList, vector<double>& weights, int groupThreshold, double eps) const
+{
+       if ( groupThreshold <= 0 || rectList.empty() ) {
+               return;
+       }
+
+       CV_Assert(rectList.size() == weights.size());
+
+       vector<int> labels;
+       int nclasses = partition(rectList, labels, SimilarRects(eps));
+
+       vector<cv::Rect_<double> > rrects(nclasses);
+       vector<int> numInClass(nclasses, 0);
+       vector<double> foundWeights(nclasses, DBL_MIN);
+       int i, j, nlabels = (int)labels.size();
+
+       for ( i = 0; i < nlabels; i++ ) {
+               int cls = labels[i];
+               rrects[cls].x += rectList[i].x;
+               rrects[cls].y += rectList[i].y;
+               rrects[cls].width += rectList[i].width;
+               rrects[cls].height += rectList[i].height;
+               foundWeights[cls] = max(foundWeights[cls], weights[i]);
+               numInClass[cls]++;
+       }
+
+       for ( i = 0; i < nclasses; i++ ) {
+               /* find the average of all ROI in the cluster */
+               cv::Rect_<double> r = rrects[i];
+               double s = 1.0/numInClass[i];
+               rrects[i] = cv::Rect_<double>(cv::saturate_cast<double>(r.x*s),
+                               cv::saturate_cast<double>(r.y*s),
+                               cv::saturate_cast<double>(r.width*s),
+                               cv::saturate_cast<double>(r.height*s));
+       }
+
+       rectList.clear();
+       weights.clear();
+
+       for ( i = 0; i < nclasses; i++ ) {
+               cv::Rect r1 = rrects[i];
+               int n1 = numInClass[i];
+               double w1 = foundWeights[i];
+               if ( n1 <= groupThreshold )
+                       continue;
+               /* filter out small rectangles inside large rectangles */
+               for ( j = 0; j < nclasses; j++ ) {
+                       int n2 = numInClass[j];
+
+                       if ( j == i || n2 <= groupThreshold )
+                               continue;
+
+                       cv::Rect r2 = rrects[j];
+
+                       int dx = cv::saturate_cast<int>(r2.width * eps);
+                       int dy = cv::saturate_cast<int>(r2.height * eps);
+
+                       if ( r1.x >= r2.x - dx &&
+                                       r1.y >= r2.y - dy &&
+                                       r1.x + r1.width <= r2.x + r2.width + dx &&
+                                       r1.y + r1.height <= r2.y + r2.height + dy &&
+                                       (n2 > std::max(3, n1) || n1 < 3) )
+                               break;
+               }
+
+               if ( j == nclasses ) {
+                       rectList.push_back(r1);
+                       weights.push_back(w1);
+               }
+       }
+}
+}
diff --git a/mv_surveillance/surveillance/src/SurveillanceHelper.cpp b/mv_surveillance/surveillance/src/SurveillanceHelper.cpp
new file mode 100644 (file)
index 0000000..bbd92e9
--- /dev/null
@@ -0,0 +1,200 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SurveillanceHelper.h"
+
+#include <mv_private.h>
+
+#include "opencv2/highgui/highgui.hpp"
+
+namespace mediavision {
+namespace surveillance {
+
+int SurveillanceHelper::convertSourceMV2GrayCV(mv_source_h mvSource, cv::Mat& cvSource)
+{
+       MEDIA_VISION_INSTANCE_CHECK(mvSource);
+
+       int depth = CV_8U; /* Default depth. 1 byte per channel. */
+       unsigned int channelsNumber = 0;
+       unsigned int width = 0, height = 0;
+       unsigned int bufferSize = 0;
+       unsigned char *buffer = NULL;
+
+       mv_colorspace_e colorspace = MEDIA_VISION_COLORSPACE_INVALID;
+
+       MEDIA_VISION_ASSERT(mv_source_get_width(mvSource, &width),
+                                               "Failed to get the width.");
+       MEDIA_VISION_ASSERT(mv_source_get_height(mvSource, &height),
+                                               "Failed to get the height.");
+       MEDIA_VISION_ASSERT(mv_source_get_colorspace(mvSource, &colorspace),
+                                               "Failed to get the colorspace.");
+       MEDIA_VISION_ASSERT(mv_source_get_buffer(mvSource, &buffer, &bufferSize),
+                                               "Failed to get the buffer size.");
+
+       int conversionType = -1; /* Type of conversion from given colorspace to gray */
+       switch(colorspace) {
+       case MEDIA_VISION_COLORSPACE_INVALID:
+               LOGE("Error: mv_source has invalid colorspace.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       case MEDIA_VISION_COLORSPACE_Y800:
+               channelsNumber = 1;
+               /* Without convertion */
+               break;
+       case MEDIA_VISION_COLORSPACE_I420:
+               channelsNumber = 1;
+               height *= 1.5;
+               conversionType = CV_YUV2GRAY_I420;
+               break;
+       case MEDIA_VISION_COLORSPACE_NV12:
+               channelsNumber = 1;
+               height *= 1.5;
+               conversionType = CV_YUV2GRAY_NV12;
+               break;
+       case MEDIA_VISION_COLORSPACE_YV12:
+               channelsNumber = 1;
+               height *= 1.5;
+               conversionType = CV_YUV2GRAY_YV12;
+               break;
+       case MEDIA_VISION_COLORSPACE_NV21:
+               channelsNumber = 1;
+               height *= 1.5;
+               conversionType = CV_YUV2GRAY_NV21;
+               break;
+       case MEDIA_VISION_COLORSPACE_YUYV:
+               channelsNumber = 2;
+               conversionType = CV_YUV2GRAY_YUYV;
+               break;
+       case MEDIA_VISION_COLORSPACE_UYVY:
+               channelsNumber = 2;
+               conversionType = CV_YUV2GRAY_UYVY;
+               break;
+       case MEDIA_VISION_COLORSPACE_422P:
+               channelsNumber = 2;
+               conversionType = CV_YUV2GRAY_Y422;
+               break;
+       case MEDIA_VISION_COLORSPACE_RGB565:
+               channelsNumber = 2;
+               conversionType = CV_BGR5652GRAY;
+               break;
+       case MEDIA_VISION_COLORSPACE_RGB888:
+               channelsNumber = 3;
+               conversionType = CV_RGB2GRAY;
+               break;
+       case MEDIA_VISION_COLORSPACE_RGBA:
+               channelsNumber = 4;
+               conversionType = CV_RGBA2GRAY;
+               break;
+       default:
+               LOGE("Error: mv_source has unsupported colorspace.");
+               return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT;
+       }
+
+       if (conversionType == -1) { /* Without conversion */
+               cvSource = cv::Mat(cv::Size(width, height),
+                               CV_MAKETYPE(depth, channelsNumber), buffer).clone();
+       } else { /* Conversion */
+               /* Class for representation the given image as cv::Mat before conversion */
+               cv::Mat origin(cv::Size(width, height),
+                               CV_MAKETYPE(depth, channelsNumber), buffer);
+               cv::cvtColor(origin, cvSource, conversionType);
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+#ifdef ENABLE_NEON
+int SurveillanceHelper::convertSourceMVRGB2GrayCVNeon(
+               mv_source_h mvSource,
+               cv::Mat& cvSource)
+{
+       MEDIA_VISION_INSTANCE_CHECK(mvSource);
+
+       const int depth = CV_8U; /* Default depth. 1 byte per channel. */
+       unsigned int width = 0, height = 0;
+       unsigned int bufferSize = 0;
+       unsigned char *src = NULL;
+
+       mv_colorspace_e colorspace = MEDIA_VISION_COLORSPACE_INVALID;
+
+       MEDIA_VISION_ASSERT(mv_source_get_width(mvSource, &width),
+                                               "Failed to get the width.");
+       MEDIA_VISION_ASSERT(mv_source_get_height(mvSource, &height),
+                                               "Failed to get the height.");
+       MEDIA_VISION_ASSERT(mv_source_get_colorspace(mvSource, &colorspace),
+                                               "Failed to get the colorspace.");
+       MEDIA_VISION_ASSERT(mv_source_get_buffer(mvSource, &src, &bufferSize),
+                                               "Failed to get the buffer size.");
+
+       if (colorspace != MEDIA_VISION_COLORSPACE_RGB888) {
+               LOGE("Error: mv_source has unsupported colorspace.");
+               return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT;
+       }
+
+       cvSource = cv::Mat(cv::Size(width, height), CV_MAKETYPE(depth, 1));
+       const unsigned int cvSourceSize = width * height;
+
+#if defined(__aarch64__)
+       asm volatile ("lsr  %2, %2, #3     \n"
+               "# channel multimpliers:       \n"
+               "mov         w4, #28           \n"
+               "mov         w5, #151          \n"
+               "mov         w6, #77           \n"
+               "dup         v3.8b, w4         \n"
+               "dup         v4.8b, w5         \n"
+               "dup         v5.8b, w6         \n"
+               ".loop:                        \n"
+               "# load 8 pixels:              \n"
+               "ld3         {v0.8b,v1.8b,v2.8b}, [%0],#24 \n"
+               "# conversion:                             \n"
+               "umull       v7.8h, v0.8b, v3.8b           \n"
+               "umlal       v7.8h, v1.8b, v4.8b           \n"
+               "umlal       v7.8h, v2.8b, v5.8b           \n"
+               "# shift and store:                        \n"
+               "shrn        v6.8b, v7.8h, #8              \n"
+               "st1         {v6.8b}, [%1],#8              \n"
+               "subs        %2, %2, #1                    \n"
+               "bne         .loop             \n"::"r" (src), "r" (cvSource.data), "r" (cvSourceSize)
+               :"memory", "w4", "w5", "w6");
+#else
+       asm volatile ("lsr  %2, %2, #3     \n"
+               "# channel multimpliers:       \n"
+               "mov         r4, #77           \n"
+               "mov         r5, #151          \n"
+               "mov         r6, #28           \n"
+               "vdup.8      d3, r4            \n"
+               "vdup.8      d4, r5            \n"
+               "vdup.8      d5, r6            \n"
+               ".loop:                        \n"
+               "# load 8 pixels:              \n"
+               "vld3.8      {d0-d2}, [%0]!    \n"
+               "# conversion:                 \n"
+               "vmull.u8    q7, d0, d3        \n"
+               "vmlal.u8    q7, d1, d4        \n"
+               "vmlal.u8    q7, d2, d5        \n"
+               "# shift and store:            \n"
+               "vshrn.u16   d6, q7, #8        \n"
+               "vst1.8      {d6}, [%1]!       \n"
+               "subs        %2, %2, #1        \n"
+               "bne         .loop             \n"::"r" (src), "r" (cvSource.data), "r" (cvSourceSize)
+               :"memory", "r4", "r5", "r6");
+#endif
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+#endif
+
+} /* surveillance */
+} /* mediavision */
diff --git a/mv_surveillance/surveillance/src/mv_absdiff.c b/mv_surveillance/surveillance/src/mv_absdiff.c
new file mode 100644 (file)
index 0000000..9e122e6
--- /dev/null
@@ -0,0 +1,81 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_absdiff.h"
+
+#include "mv_common.h"
+#include "mv_private.h"
+
+#ifdef ENABLE_NEON
+#include <arm_neon.h>
+#endif
+
+int mv_absdiff(
+               uint8_t *__restrict__ src1,
+               uint8_t *__restrict__ src2,
+               int width,
+               int height,
+               int stride,
+               uint8_t *__restrict__ dst)
+{
+       if (src1 == NULL || src2 == NULL || width <= 0 || height <= 0 ||
+                       stride <= 0 || dst == NULL) {
+               LOGE("Wrong input parameter. Aplpying mask failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       int column = 0;
+       int row = 0;
+       const int padding = stride - width;
+
+#ifdef ENABLE_NEON
+       const int batch_size = 16;
+       const int batch_columns_count = width / batch_size;
+#endif
+
+       for (; row < height; ++row) {
+#ifdef ENABLE_NEON
+               for (column = 0; column < batch_columns_count; ++column) {
+                       uint8x16_t gray1 = vld1q_u8 (src1);
+                       uint8x16_t gray2 = vld1q_u8 (src2);
+
+                       uint8x16_t dst_temp = vabdq_u8(gray1, gray2);
+
+                       vst1q_u8 (dst, dst_temp);
+
+                       src1 += batch_size;
+                       src2 += batch_size;
+                       dst += batch_size;
+               }
+#else
+               for (column = 0; column < width; ++column) {
+                       uint8_t gray1 = *src1;
+                       uint8_t gray2 = *src2;
+
+                       (*dst) = abs((*src1) - (*src2));
+
+                       ++src1;
+                       ++src2;
+                       ++dst;
+               }
+#endif
+               src1 += padding;
+               src2 += padding;
+               dst += padding;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
diff --git a/mv_surveillance/surveillance/src/mv_apply_mask.c b/mv_surveillance/surveillance/src/mv_apply_mask.c
new file mode 100644 (file)
index 0000000..f156d07
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_apply_mask.h"
+
+#include "mv_common.h"
+#include "mv_private.h"
+
+#ifdef ENABLE_NEON
+#include <arm_neon.h>
+#endif
+
+int mv_apply_mask(
+       uint8_t *src_buffer,
+       uint8_t *__restrict mask,
+       int width,
+       int height,
+       int stride,
+       uint8_t *dst_buffer)
+{
+       if (src_buffer == NULL || mask == NULL || width <= 0 || height <= 0 ||
+                       stride <= 0 || dst_buffer == NULL) {
+               LOGE("Wrong input parameter. Aplpying mask failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       const int padding = stride - width;
+
+#ifdef ENABLE_NEON
+       const int batch_size = 16;
+       const int batch_columns_count = width / batch_size;
+#endif
+
+       int row = 0;
+       int column = 0;
+       for (; row < height; ++row) {
+#ifdef ENABLE_NEON
+               for (column = 0; column < batch_columns_count; ++column) {
+                       uint8x16_t src_v = vld1q_u8(src_buffer);
+                       uint8x16_t mask_v = vld1q_u8(mask);
+
+                       uint8x16_t dst_v = vandq_u8(src_v, mask_v);
+
+                       vst1q_u8(dst_buffer, dst_v);
+
+                       dst_buffer += batch_size;
+                       src_buffer += batch_size;
+                       mask += batch_size;
+               }
+#else
+               for (column = 0; column < width; ++column) {
+                       (*dst_buffer) = ((*src_buffer) & (*mask));
+                       ++dst_buffer;
+                       ++src_buffer;
+                       ++mask;
+               }
+#endif
+               dst_buffer += padding;
+               src_buffer += padding;
+               mask += padding;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
diff --git a/mv_surveillance/surveillance/src/mv_mask_buffer.c b/mv_surveillance/surveillance/src/mv_mask_buffer.c
new file mode 100644 (file)
index 0000000..f1d50ef
--- /dev/null
@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_mask_buffer.h"
+
+#include "mv_common.h"
+#include "mv_private.h"
+
+#include <stdio.h>
+
+int mv_get_mask_buffer(
+       unsigned int buffer_width,
+       unsigned int buffer_height,
+       mv_point_s *polygon,
+       unsigned int points_number,
+       unsigned char **mask_buffer)
+{
+       if (buffer_width == 0u || buffer_height == 0u ||
+                       polygon == NULL|| points_number == 0u || mask_buffer == NULL) {
+               LOGE("Wrong input parameter. Getting mask buffer failed.");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       const unsigned int buffer_size = buffer_width * buffer_height;
+
+       *mask_buffer = (unsigned char*) malloc(sizeof(unsigned char) * buffer_size);
+
+       unsigned int i = 0u;
+       unsigned int j = 0u;
+       unsigned int k = 0u;
+
+       int max_x = polygon[0].x;
+       int max_y = polygon[0].y;
+       int min_x = polygon[0].x;
+       int min_y = polygon[0].y;
+
+       for (k = 1u; k < points_number; ++k) {
+               if (polygon[k].x > max_x) {
+                       max_x = polygon[k].x;
+               } else if (polygon[k].x < min_x) {
+                       min_x = polygon[k].x;
+               }
+
+               if (polygon[k].y > max_y) {
+                       max_y = polygon[k].y;
+               } else if (polygon[k].y < min_y) {
+                       min_y = polygon[k].y;
+               }
+       }
+
+
+       for (k = 0u; k < buffer_size; ++k) {
+               bool inside_polygon = false;
+
+               const int test_x = (int) k % buffer_width;
+               const int test_y = (int) k / buffer_width;
+
+               if (test_x > max_x || test_x < min_x || test_y > max_y || test_y < min_y) {
+                       (*mask_buffer)[k] = 0;
+                       continue;
+               }
+
+               for (i = 0u, j = points_number - 1; i < points_number; j = i++) {
+                       if (((polygon[i].y > test_y) != (polygon[j].y > test_y)) &&
+                                       ((float) test_x < (float) (polygon[j].x - polygon[i].x) *
+                                       (test_y - polygon[i].y) /
+                                       (polygon[j].y - polygon[i].y) +
+                                       polygon[i].x)) {
+                               inside_polygon = !inside_polygon;
+                       }
+               }
+               inside_polygon ? ((*mask_buffer)[k] = 255) : ((*mask_buffer)[k] = 0);
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
diff --git a/mv_surveillance/surveillance/src/mv_surveillance_open.cpp b/mv_surveillance/surveillance/src/mv_surveillance_open.cpp
new file mode 100644 (file)
index 0000000..4d4c328
--- /dev/null
@@ -0,0 +1,140 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_surveillance_open.h"
+
+#include "EventManager.h"
+#include "EventResult.h"
+
+#include <mv_private.h>
+
+using namespace mediavision::surveillance;
+
+int mv_surveillance_subscribe_event_trigger_open(
+       mv_surveillance_event_trigger_h event_trigger,
+       int video_stream_id,
+       mv_engine_config_h engine_cfg,
+       mv_surveillance_event_occurred_cb callback,
+       void *user_data)
+{
+       mv_surveillance_event_trigger_s *handle =
+               (mv_surveillance_event_trigger_s *)event_trigger;
+
+       return EventManager::getInstance().registerEvent(
+                       event_trigger,
+                       static_cast<long int>(handle->trigger_id),
+                       handle->event_type,
+                       video_stream_id,
+                       engine_cfg,
+                       callback,
+                       user_data,
+                       handle->number_of_roi_points,
+                       handle->roi);
+}
+
+int mv_surveillance_unsubscribe_event_trigger_open(
+       mv_surveillance_event_trigger_h event_trigger,
+       int video_stream_id)
+{
+       mv_surveillance_event_trigger_s *handle =
+               (mv_surveillance_event_trigger_s *)event_trigger;
+
+       return EventManager::getInstance().unregisterEvent(
+                       static_cast<long int>(handle->trigger_id),
+                       video_stream_id);
+}
+
+int mv_surveillance_push_source_open(
+               mv_source_h source,
+               int video_stream_id)
+{
+       MEDIA_VISION_INSTANCE_CHECK(source);
+
+       return EventManager::getInstance().pushSource(source, video_stream_id);
+}
+
+int mv_surveillance_foreach_event_type_open(
+               mv_surveillance_event_type_cb callback,
+               void *user_data)
+{
+       StringVector eventTypes;
+       const int error = EventManager::getInstance().getSupportedEventTypes(eventTypes);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               LOGE("Query events failed due to internal issues. Error code: %i",
+                               error);
+               return error;
+       }
+
+       StringConstIter eventIter = eventTypes.begin();
+       while (eventIter != eventTypes.end()) {
+               if (!callback((*eventIter).c_str(), user_data)) {
+                       break;
+               }
+               ++eventIter;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_foreach_event_result_value_name_open(
+       const char *event_type,
+       mv_surveillance_event_result_name_cb callback,
+       void *user_data)
+{
+       StringVector eventResultValueNames;
+
+       int error = MEDIA_VISION_ERROR_NONE;
+
+       if (NULL == event_type) {
+               error = EventManager::getInstance().getSupportedEventResultValueNames(
+                                       eventResultValueNames);
+       } else {
+               error = EventManager::getInstance().getSupportedEventResultValueNames(
+                                       event_type,
+                                       eventResultValueNames);
+       }
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               LOGE("Query result value names failed due to internal issues. "
+                               "Error code: %i", error);
+               return error;
+       }
+
+       StringConstIter ervnIter = eventResultValueNames.begin();
+       while (ervnIter != eventResultValueNames.end()) {
+               if (!callback((*ervnIter).c_str(), user_data)) {
+                       break;
+               }
+               ++ervnIter;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_get_result_value_open(
+       mv_surveillance_result_h result,
+       const char *value_name,
+       void *value)
+{
+       MEDIA_VISION_INSTANCE_CHECK(result);
+       MEDIA_VISION_NULL_ARG_CHECK(value_name);
+       MEDIA_VISION_NULL_ARG_CHECK(value);
+
+       EventResult *eventResult = (EventResult*) result;
+
+       return eventResult->getResultValue(value_name, value);
+}
diff --git a/mv_surveillance/surveillance_lic/CMakeLists.txt b/mv_surveillance/surveillance_lic/CMakeLists.txt
new file mode 100644 (file)
index 0000000..266b94a
--- /dev/null
@@ -0,0 +1,25 @@
+project(${MV_SURVEILLANCE_LIB_NAME})
+cmake_minimum_required(VERSION 2.6)
+
+set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG _DEBUG)
+
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+include_directories("${INC_DIR}")
+include_directories("${PROJECT_SOURCE_DIR}/include")
+include_directories("${PROJECT_SOURCE_DIR}/src")
+
+file(GLOB MV_SURVEILLANCE_INC_LIST "${PROJECT_SOURCE_DIR}/include/*.h")
+file(GLOB MV_SURVEILLANCE_SRC_LIST "${PROJECT_SOURCE_DIR}/src/*.c")
+
+if(FORCED_STATIC_BUILD)
+    add_library(${PROJECT_NAME} STATIC ${MV_SURVEILLANCE_INC_LIST} ${MV_SURVEILLANCE_SRC_LIST})
+else()
+    add_library(${PROJECT_NAME} SHARED ${MV_SURVEILLANCE_INC_LIST} ${MV_SURVEILLANCE_SRC_LIST})
+endif()
+
+target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME})
+
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION lib)
diff --git a/mv_surveillance/surveillance_lic/include/mv_surveillance_lic.h b/mv_surveillance/surveillance_lic/include/mv_surveillance_lic.h
new file mode 100644 (file)
index 0000000..16bd4fc
--- /dev/null
@@ -0,0 +1,187 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __TIZEN_MEDIAVISION_SURVEILLANCE_LIC_H__
+#define __TIZEN_MEDIAVISION_SURVEILLANCE_LIC_H__
+
+#include <mv_surveillance.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @file  mv_surveillance_lic.h
+ * @brief This file contains the Media Vision surveillance API
+ */
+
+/**
+ * @brief Allows to subscribe to the event and start calling @a callback
+ *        each time when the @a source is pushed using
+ *        @ref mv_surveillance_push_source_lic() and event is detected.
+ *
+ * @since_tizen 3.0
+ * @remarks To stop handling triggering use
+ *          @ref mv_surveillance_unsubscribe_event_trigger_lic().
+ * @param [in] event_trigger    The event trigger activating calls of the
+ *                              @a callback function
+ * @param [in] engine_cfg       The engine configuration of the event
+ * @param [in] callback         Callback to be called each time when event
+ *                              occurrence is detected
+ * @param [in] user_data        The user data to be passed to the callback function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @post @ref mv_surveillance_event_occurred_cb
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_unsubscribe_event_trigger_lic()
+ */
+int mv_surveillance_subscribe_event_trigger_lic(
+        mv_surveillance_event_trigger_h event_trigger,
+        mv_engine_config_h engine_cfg,
+        mv_surveillance_event_occurred_cb callback,
+        void *user_data);
+
+/**
+ * @brief Allows to unsubscribe from the event and stop calling @a callback.
+ *
+ * @since_tizen 3.0
+ * @remarks To start handling trigger activation use
+            @ref mv_surveillance_subscribe_event_trigger_lic().
+ * @param [in] event_trigger    The event trigger for which subscription will be
+ *                              stopped
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @post @ref mv_surveillance_event_occurred_cb
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_subscribe_event_trigger_lic()
+ */
+int mv_surveillance_unsubscribe_event_trigger_lic(
+        mv_surveillance_event_trigger_h event_trigger);
+
+/**
+ * @brief Allows to push source to the event trigger and start calling @a callback.
+ *
+ * @since_tizen 3.0
+ * @param [in] source             The handle to the media source
+ * @param [in] video_stream_id    The video stream, wthich will be updated
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_event_occurred_cb
+ * @see mv_surveillance_subscribe_event_trigger_lic()
+ * @see mv_surveillance_unsubscribe_event_trigger_lic()
+ */
+int mv_surveillance_push_source_lic(
+        mv_source_h source,
+        int video_stream_id);
+
+/**
+ * @brief Starts traversing through list of supported event types.
+ *
+ * @since_tizen 3.0
+ * @remarks Supported event types and their descriptions can be found in
+ *          @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ *          section
+ * @param [in] callback     The callback function to be called for each
+ *                          supported event type
+ * @param [in] user_data    The user data to be passed to the @a callback
+ *                          function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_type_cb
+ * @see mv_surveillance_foreach_event_result_value_name_lic()
+ */
+int mv_surveillance_foreach_event_type_lic(
+        mv_surveillance_event_type_cb callback,
+        void *user_data);
+
+/**
+ * @brief Starts traversing through list of supported event result value names.
+ *
+ * @since_tizen 3.0
+ * @remarks Supported event types, event result value names and their
+ *          descriptions can be found in
+ *          @ref CAPI_MEDIA_VISION_SURVEILLANCE_EVENT_TYPES documentation
+ *          section
+ * @param [in] event_type    The name of the event type for which result value
+ *                           names will be passed to the @a callback. Can be
+ *                           set @c NULL. If set @c NULL then all supported
+ *                           event result value names will be traversed
+ * @param [in] callback      The callback function to be called for each
+ *                           supported event result value name
+ * @param [in] user_data     The user data to be passed to the @a callback
+ *                           function
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @see mv_surveillance_event_result_value_name_cb
+ * @see mv_surveillance_foreach_event_type_lic()
+ * @see mv_surveillance_get_result_value_lic()
+ */
+int mv_surveillance_foreach_event_result_value_name_lic(
+        const char *event_type,
+        mv_surveillance_event_result_value_name_cb callback,
+        void *user_data);
+
+/**
+ * @brief Gets result value.
+ * @details See the output values names in the event types descriptions located
+ *          in /usr/share/config/capi-media-vision/surveillance-event-types.txt.
+ *
+ * @since_tizen 3.0
+ * @param [in] result           The handle to the event result
+ * @param [in] value_name       The name of the value to be gotten
+ * @param [in, out] value       The pointer to variable which will be filled
+ *                              by result value
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ *
+ * @pre Memory for value has to be allocated
+ *
+ * @see mv_surveillance_event_trigger_s
+ * @see mv_surveillance_event_occurred_cb
+ * @see mv_surveillance_subscribe_event_trigger_lic()
+ * @see mv_surveillance_unsubscribe_event_trigger_lic()
+ * @see mv_surveillance_query_events_lic()
+ */
+int mv_surveillance_get_result_value_lic(
+        mv_surveillance_result_h result,
+        const char *value_name,
+        void *value);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_MEDIAVISION_SURVEILLANCE_LIC_H__ */
diff --git a/mv_surveillance/surveillance_lic/src/mv_surveillance_lic.c b/mv_surveillance/surveillance_lic/src/mv_surveillance_lic.c
new file mode 100644 (file)
index 0000000..95acb63
--- /dev/null
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_surveillance_lic.h"
+
+int mv_surveillance_subscribe_event_trigger_lic(
+        mv_surveillance_event_trigger_h event_trigger,
+        mv_engine_config_h engine_cfg,
+        mv_surveillance_event_occurred_cb callback,
+        void *user_data)
+{
+    return MEDIA_VISION_ERROR_NOT_SUPPORTED;
+}
+
+
+int mv_surveillance_unsubscribe_event_trigger_lic(
+        mv_surveillance_event_trigger_h event_trigger)
+{
+    return MEDIA_VISION_ERROR_NOT_SUPPORTED;
+}
+
+int mv_surveillance_push_source_lic(
+        mv_source_h source,
+        int video_stream_id)
+{
+    return MEDIA_VISION_ERROR_NOT_SUPPORTED;
+}
+
+int mv_surveillance_foreach_event_type_lic(
+        mv_surveillance_event_type_cb callback,
+        void *user_data)
+{
+    return MEDIA_VISION_ERROR_NOT_SUPPORTED;
+}
+
+int mv_surveillance_foreach_event_result_value_name_lic(
+        const char *event_type,
+        mv_surveillance_event_result_value_name_cb callback,
+        void *user_data)
+{
+    return MEDIA_VISION_ERROR_NOT_SUPPORTED;
+}
+
+int mv_surveillance_get_result_value_lic(
+        mv_surveillance_result_h result,
+        const char *value_name,
+        void *value)
+{
+    return MEDIA_VISION_ERROR_NOT_SUPPORTED;
+}
index db59b53..d7eac4a 100644 (file)
@@ -1,6 +1,6 @@
 Name:        capi-media-vision
 Summary:     Media Vision library for Tizen Native API
-Version:     0.2.5
+Version:     0.3.0
 Release:     0
 Group:       Multimedia/Framework
 License:     Apache-2.0 and BSD-2.0
@@ -49,6 +49,17 @@ export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
 export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
 export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
 %endif
+
+%ifarch %{arm}
+export CFLAGS="$CFLAGS -DENABLE_NEON"
+export CXXFLAGS="$CXXFLAGS -DENABLE_NEON"
+%endif
+
+%ifarch %{aarch64}
+export CFLAGS="$CFLAGS -DENABLE_NEON"
+export CXXFLAGS="$CXXFLAGS -DENABLE_NEON"
+%endif
+
 MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
 %cmake . -DFULLVER=%{version} -DMAJORVER=${MAJORVER}
 
diff --git a/src/mv_surveillance.c b/src/mv_surveillance.c
new file mode 100644 (file)
index 0000000..48aa269
--- /dev/null
@@ -0,0 +1,363 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_surveillance.h"
+
+#include "mv_surveillance_private.h"
+#include "mv_private.h"
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+/* Include headers of licensed surveillance module here. */
+#include "mv_surveillance_lic.h"
+
+#else
+
+/* Include headers of open surveillance module here. */
+#include "mv_surveillance_open.h"
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+/**
+ * @file  mv_surveillance.c
+ * @brief This file contains the porting layer for Media Vision surveillance module.
+ */
+
+static size_t __mv_surveillance_id_counter = 0;
+
+int mv_surveillance_event_trigger_create(
+               const char *event_type,
+               mv_surveillance_event_trigger_h * trigger)
+{
+       MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+       MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+       MEDIA_VISION_NULL_ARG_CHECK(event_type);
+       MEDIA_VISION_NULL_ARG_CHECK(trigger);
+       MEDIA_VISION_FUNCTION_ENTER();
+
+       mv_surveillance_event_trigger_s *handle =
+                       (mv_surveillance_event_trigger_s *) malloc(
+                                       sizeof(mv_surveillance_event_trigger_s));
+       if (NULL == handle) {
+               LOGE("[%s] malloc fail", __func__);
+               return MEDIA_VISION_ERROR_OUT_OF_MEMORY;
+       }
+
+       memset(handle, 0, sizeof(mv_surveillance_event_trigger_s));
+
+       // default values:
+       handle->trigger_id = ++__mv_surveillance_id_counter;
+       handle->event_type = strndup(event_type, 255);
+       handle->number_of_roi_points = 0;
+       handle->roi = NULL;
+
+       *trigger = (mv_surveillance_event_trigger_h) handle;
+
+       MEDIA_VISION_FUNCTION_LEAVE();
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_event_trigger_destroy(
+               mv_surveillance_event_trigger_h trigger)
+{
+       MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+       MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+       MEDIA_VISION_NULL_ARG_CHECK(trigger);
+       MEDIA_VISION_FUNCTION_ENTER();
+
+       mv_surveillance_event_trigger_s *handle =
+                       (mv_surveillance_event_trigger_s *) trigger;
+       free(handle->event_type);
+       free(handle->roi);
+       free((mv_surveillance_event_trigger_s *) trigger);
+
+       MEDIA_VISION_FUNCTION_LEAVE();
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_get_event_trigger_type(
+               mv_surveillance_event_trigger_h trigger,
+               char **event_type)
+{
+       MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+       MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+       MEDIA_VISION_INSTANCE_CHECK(trigger);
+       MEDIA_VISION_NULL_ARG_CHECK(event_type);
+       MEDIA_VISION_FUNCTION_ENTER();
+
+       mv_surveillance_event_trigger_s *handle =
+                       (mv_surveillance_event_trigger_s *)trigger;
+       *event_type = strndup(handle->event_type, 255);
+
+    MEDIA_VISION_FUNCTION_LEAVE();
+    return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_set_event_trigger_roi(
+               mv_surveillance_event_trigger_h trigger,
+               int number_of_points,
+               mv_point_s *roi)
+{
+       MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+       MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+       MEDIA_VISION_INSTANCE_CHECK(trigger);
+       MEDIA_VISION_NULL_ARG_CHECK(roi);
+       MEDIA_VISION_FUNCTION_ENTER();
+
+       mv_surveillance_event_trigger_s *handle =
+                       (mv_surveillance_event_trigger_s *)trigger;
+
+       handle->number_of_roi_points = number_of_points;
+       handle->roi = (mv_point_s*) malloc(sizeof(mv_point_s) * number_of_points);
+
+       if (NULL == handle->roi) {
+               LOGE("[%s] malloc fail", __func__);
+               return MEDIA_VISION_ERROR_OUT_OF_MEMORY;
+       }
+
+       int i = 0;
+       for (; i < number_of_points; ++i) {
+               handle->roi[i].x = roi[i].x;
+               handle->roi[i].y = roi[i].y;
+       }
+
+       MEDIA_VISION_FUNCTION_LEAVE();
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_get_event_trigger_roi(
+               mv_surveillance_event_trigger_h trigger,
+               int *number_of_points,
+               mv_point_s ** roi)
+{
+       MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+       MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+       MEDIA_VISION_INSTANCE_CHECK(trigger);
+       MEDIA_VISION_NULL_ARG_CHECK(number_of_points);
+       MEDIA_VISION_NULL_ARG_CHECK(roi);
+       MEDIA_VISION_FUNCTION_ENTER();
+
+       mv_surveillance_event_trigger_s *handle =
+                       (mv_surveillance_event_trigger_s *) trigger;
+
+       *number_of_points = handle->number_of_roi_points;
+       if (0 == *number_of_points)
+       {
+               MEDIA_VISION_FUNCTION_LEAVE();
+               return MEDIA_VISION_ERROR_NONE;
+       }
+       *roi = (mv_point_s *) malloc(
+                                       sizeof(mv_point_s) * handle->number_of_roi_points);
+
+       int i = 0;
+       for (; i < handle->number_of_roi_points; ++i) {
+               (*roi)[i].x = handle->roi[i].x;
+               (*roi)[i].y = handle->roi[i].y;
+       }
+
+       MEDIA_VISION_FUNCTION_LEAVE();
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_surveillance_subscribe_event_trigger(
+               mv_surveillance_event_trigger_h event_trigger,
+               int video_stream_id,
+               mv_engine_config_h engine_cfg,
+               mv_surveillance_event_occurred_cb callback,
+               void *user_data)
+{
+       MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+       MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+       MEDIA_VISION_INSTANCE_CHECK(event_trigger);
+       MEDIA_VISION_NULL_ARG_CHECK(callback);
+       MEDIA_VISION_FUNCTION_ENTER();
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+       /* Use licensed surveillance functionality here. */
+       const int ret = mv_surveillance_subscribe_event_trigger_lic(
+                                       event_trigger,
+                                       video_stream_id,
+                                       engine_cfg,
+                                       callback,
+                                       user_data);
+
+#else
+
+       /* Use open surveillance functionality here. */
+       const int ret = mv_surveillance_subscribe_event_trigger_open(
+                                       event_trigger,
+                                       video_stream_id,
+                                       engine_cfg,
+                                       callback,
+                                       user_data);
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+       MEDIA_VISION_FUNCTION_LEAVE();
+       return ret;
+}
+
+int mv_surveillance_unsubscribe_event_trigger(
+               mv_surveillance_event_trigger_h event_trigger,
+               int video_stream_id)
+{
+       MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+       MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+       MEDIA_VISION_INSTANCE_CHECK(event_trigger);
+       MEDIA_VISION_FUNCTION_ENTER();
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+       /* Use licensed surveillance functionality here. */
+       const int ret = mv_surveillance_unsubscribe_event_trigger_lic(
+                                       event_trigger,
+                                       video_stream_id);
+
+#else
+
+       /* Use open surveillance functionality here. */
+       const int ret = mv_surveillance_unsubscribe_event_trigger_open(
+                                       event_trigger,
+                                       video_stream_id);
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+       MEDIA_VISION_FUNCTION_LEAVE();
+       return ret;
+}
+
+int mv_surveillance_push_source(
+               mv_source_h source,
+               int video_stream_id)
+{
+       MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+       MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+       MEDIA_VISION_INSTANCE_CHECK(source);
+       MEDIA_VISION_FUNCTION_ENTER();
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+       /* Use licensed surveillance functionality here. */
+       const int ret = mv_surveillance_push_source_lic(source, video_stream_id);
+
+#else
+
+       /* Use open surveillance functionality here. */
+       const int ret = mv_surveillance_push_source_open(source, video_stream_id);
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+       MEDIA_VISION_FUNCTION_LEAVE();
+       return ret;
+}
+
+int mv_surveillance_foreach_supported_event_type(
+               mv_surveillance_event_type_cb callback,
+               void *user_data)
+{
+       MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+       MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+       MEDIA_VISION_NULL_ARG_CHECK(callback);
+       MEDIA_VISION_FUNCTION_ENTER();
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+       /* Use licensed surveillance functionality here. */
+       const int ret = mv_surveillance_foreach_event_type_lic(
+                                       callback,
+                                       user_data);
+
+#else
+
+       /* Use open surveillance functionality here. */
+       const int ret = mv_surveillance_foreach_event_type_open(
+                                       callback,
+                                       user_data);
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+       MEDIA_VISION_FUNCTION_LEAVE();
+       return ret;
+}
+
+int mv_surveillance_foreach_event_result_name(
+               const char *event_type,
+               mv_surveillance_event_result_name_cb callback,
+               void *user_data)
+{
+       MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+       MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+       MEDIA_VISION_NULL_ARG_CHECK(event_type);
+       MEDIA_VISION_NULL_ARG_CHECK(callback);
+       MEDIA_VISION_FUNCTION_ENTER();
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+       /* Use licensed surveillance functionality here. */
+       const int ret = mv_surveillance_foreach_event_result_value_name_lic(
+                                       event_type,
+                                       callback,
+                                       user_data);
+
+#else
+
+       /* Use open surveillance functionality here. */
+       const int ret = mv_surveillance_foreach_event_result_value_name_open(
+                                       event_type,
+                                       callback,
+                                       user_data);
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+       MEDIA_VISION_FUNCTION_LEAVE();
+
+       return ret;
+}
+
+int mv_surveillance_get_result_value(
+               mv_surveillance_result_h result,
+               const char *value_name,
+               void *value)
+{
+       MEDIA_VISION_SUPPORT_CHECK(__mv_face_check_system_info_feature_supported());
+       MEDIA_VISION_SUPPORT_CHECK(__mv_image_check_system_info_feature_supported());
+       MEDIA_VISION_INSTANCE_CHECK(result);
+       MEDIA_VISION_NULL_ARG_CHECK(value_name);
+       MEDIA_VISION_NULL_ARG_CHECK(value);
+       MEDIA_VISION_FUNCTION_ENTER();
+
+#ifdef MEDIA_VISION_SURVEILLANCE_LICENSE_PORT
+
+       /* Use licensed surveillance functionality here. */
+       const int ret = mv_surveillance_get_result_value_lic(
+                                       result,
+                                       value_name,
+                                       value);
+
+#else
+
+       /* Use open surveillance functionality here. */
+       const int ret = mv_surveillance_get_result_value_open(
+                                       result,
+                                       value_name,
+                                       value);
+
+#endif /* MEDIA_VISION_SURVEILLANCE_LICENSE_PORT */
+
+       MEDIA_VISION_FUNCTION_LEAVE();
+       return ret;
+}
index 16a2eb6..fdb2d20 100644 (file)
@@ -11,3 +11,4 @@ add_subdirectory(${PROJECT_SOURCE_DIR}/common)
 add_subdirectory(${PROJECT_SOURCE_DIR}/barcode)
 add_subdirectory(${PROJECT_SOURCE_DIR}/face)
 add_subdirectory(${PROJECT_SOURCE_DIR}/image)
+add_subdirectory(${PROJECT_SOURCE_DIR}/surveillance)
\ No newline at end of file
diff --git a/test/testsuites/surveillance/CMakeLists.txt b/test/testsuites/surveillance/CMakeLists.txt
new file mode 100644 (file)
index 0000000..80ac1ac
--- /dev/null
@@ -0,0 +1,31 @@
+project(mv_surveillance_test_suite)
+cmake_minimum_required(VERSION 2.6)
+
+set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG    _DEBUG)
+
+if(NOT SKIP_WARNINGS)
+    set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Werror")
+endif()
+
+set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${LIB_INSTALL_DIR})
+set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${LIB_INSTALL_DIR})
+set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+
+include_directories(${PROJECT_SOURCE_DIR})
+include_directories(${MV_CAPI_MEDIA_VISION_INC_DIR})
+include_directories(${INC_TS_COMMON})
+include_directories(${INC_VIDEO_HELPER})
+include_directories(${INC_IMAGE_HELPER})
+
+file(GLOB MV_SURVEILLANCE_TS_INC_LIST "${PROJECT_SOURCE_DIR}/*.h")
+file(GLOB MV_SURVEILLANCE_TS_SRC_LIST "${PROJECT_SOURCE_DIR}/*.c")
+
+add_executable(${PROJECT_NAME} ${MV_SURVEILLANCE_TS_SRC_LIST}
+                               ${MV_SURVEILLANCE_TS_INC_LIST}
+                               ${MV_CAPI_MEDIA_VISION_INC_LIST})
+
+target_link_libraries(${PROJECT_NAME} capi-media-vision
+                                      mv_testsuite_common
+                                      mv_image_helper)
+
+install(TARGETS ${PROJECT_NAME} DESTINATION ${testsuites_dir})
diff --git a/test/testsuites/surveillance/surveillance_test_suite.c b/test/testsuites/surveillance/surveillance_test_suite.c
new file mode 100644 (file)
index 0000000..6057121
--- /dev/null
@@ -0,0 +1,1137 @@
+/**
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mv_testsuite_common.h"
+#include "image_helper.h"
+
+#include "mv_log_cfg.h"
+
+#include "mv_private.h"
+#include "mv_surveillance.h"
+
+#include <limits.h>
+
+#define MAX_EVENTS_NUMBER 101
+
+#define MAX_EVENT_TYPE_LEN 255
+
+#define MIN_NUMBER_OF_ROI_POINTS 3
+#define MAX_NUMBER_OF_ROI_POINTS 100
+
+#define MIN_ROI_X_COORD 0
+#define MAX_ROI_X_COORD 10000
+#define MIN_ROI_Y_COORD 0
+#define MAX_ROI_Y_COORD 10000
+
+/*----------------------------------------------------*/
+
+#define PRINT_R(MSG) printf(TEXT_RED MSG "\n" TEXT_RESET)
+#define PRINT_Y(MSG) printf(TEXT_YELLOW MSG "\n" TEXT_RESET)
+#define PRINT_G(MSG) printf(TEXT_GREEN MSG "\n" TEXT_RESET);
+
+#define PRINT_E(MSG, ERR) printf(TEXT_RED MSG "\n" TEXT_RESET, ERR)
+#define PRINT_W(MSG, WARN) printf(TEXT_YELLOW MSG "\n" TEXT_RESET, WARN)
+#define PRINT_S(MSG, RES) printf(TEXT_GREEN MSG "\n" TEXT_RESET, RES)
+
+/*----------------------------------------------------*/
+/* static */
+static mv_surveillance_event_trigger_h is_subscribed[MAX_EVENTS_NUMBER];
+static int video_streams_ids[MAX_EVENTS_NUMBER];
+static unsigned int trigger_id_cnt = 0;
+static const int green_color[] = {0, 255, 0};
+static const int red_color[] = {0, 0, 255};
+static const int blue_color[] = {255, 0, 0};
+static bool save_results_to_image = false;
+/*----------------------------------------------------*/
+/*functions*/
+
+/* initializes is_subscribed by false */
+void init_is_subscribed();
+
+/* prints identificators of subscribed events */
+void print_is_subscribed();
+
+/* prints names of all available event types */
+void print_supported_events();
+
+/* select event name from all available event types and creates trigger handle */
+int create_trigger_handle_by_event_name(mv_surveillance_event_trigger_h *handle);
+
+/* subscribes event */
+void subscribe_to_event();
+
+/* adds ROI to event */
+void add_roi_to_event(mv_surveillance_event_trigger_h event_trigger);
+
+/* unsubscribes from event */
+void unsubscribe_from_event();
+
+/* unsubscribes from all event */
+void unsubscribe_from_all_events();
+
+/* pushes media source to event manager */
+void push_source();
+
+/* fills engine configuration for person recognized event */
+bool fill_engine_cfg_person_recognized(mv_engine_config_h engine_cfg);
+
+/* Turn on (off) saving event results to image file */
+void turn_on_off_saving_to_image();
+
+/*----------------------------------------------------*/
+/* callbacks */
+
+void detect_person_appeared_cb(
+       mv_surveillance_event_trigger_h handle,
+       mv_source_h source,
+       int video_stream_id,
+       mv_surveillance_result_h event_result,
+       void *user_data);
+
+void person_recognized_cb(
+       mv_surveillance_event_trigger_h handle,
+       mv_source_h source,
+       int video_stream_id,
+       mv_surveillance_result_h event_result,
+       void *user_data);
+
+void movement_detected_cb(
+       mv_surveillance_event_trigger_h handle,
+       mv_source_h source,
+       int video_stream_id,
+       mv_surveillance_result_h event_result,
+       void *user_data);
+
+/*----------------------------------------------------*/
+
+int main(void)
+{
+       LOGI("Surveillance Media Vision Testsuite is launched.");
+
+       PRINT_W("Maximal number of events is %d", MAX_EVENTS_NUMBER - 1);
+
+       init_is_subscribed();
+
+       const int options[8] = { 1, 2, 3, 4, 5, 6, 7, 8 };
+       const char *names[8] = {
+               "Get list of supported events",
+               "Get identificators of subscribed events",
+               "Subscribe to event",
+               "Unsubscribe from event",
+               "Unsubscribe from all events",
+               "Push source",
+               "Turn on (off) saving event result to image",
+               "Exit"
+       };
+
+       while(1) {
+               char exit = 'n';
+               int sel_opt = show_menu("Select action:", options, names, 8);
+               switch (sel_opt) {
+               case 1: /* Get list of supported events */
+                       print_supported_events();
+                       break;
+               case 2: /* Get identificators of subscribed events */
+                       print_is_subscribed();
+                       break;
+               case 3: /* Subscribe to event */
+                       subscribe_to_event();
+                       break;
+               case 4: /* Unsubscribe from event */
+                       unsubscribe_from_event();
+                       break;
+               case 5: /* Unsubscribe from all events */
+                       unsubscribe_from_all_events();
+                       break;
+               case 6: /* Push source */
+                       push_source();
+                       break;
+               case 7: /* Save event results to image */
+                       turn_on_off_saving_to_image();
+                       break;
+               case 8: /* Exit */
+                       exit = 'y';
+                       break;
+               default:
+                       PRINT_R("Invalid option.");
+                       sel_opt = 0;
+                       continue;
+               }
+
+               if ('y' == exit) {
+                       sel_opt = 0;
+                       const int options_last[2] = { 1, 2 };
+                       const char *names_last[2] = { "No", "Yes" };
+
+                       while (sel_opt == 0) {
+                               sel_opt = show_menu("Are you sure?",
+                                                                       options_last, names_last, 2);
+                               switch (sel_opt) {
+                               case 1:
+                                       exit = 'n';
+                                       break;
+                               case 2:
+                                       exit = 'y';
+                                       break;
+                               default:
+                                       PRINT_R("Invalid option. Back to the main menu.");
+                                       sel_opt = 0;
+                                       break;
+                               }
+                       }
+
+                       if ('y' == exit) {
+                               unsubscribe_from_all_events();
+                               break;
+                       }
+               }
+       }
+
+       LOGI("Surveillance Media Vision Testsuite is closed");
+
+       return 0;
+}
+
+void init_is_subscribed()
+{
+       int i = 0;
+       for (; i < MAX_EVENTS_NUMBER; ++i) {
+               is_subscribed[i] = NULL;
+               video_streams_ids[i] = -1;
+       }
+}
+
+void print_is_subscribed()
+{
+       PRINT_Y("List of subscribed events identificators:");
+
+       bool is_empty = true;
+
+       int i = 0;
+       for (; i < MAX_EVENTS_NUMBER; ++i) {
+               if (NULL != is_subscribed[i]) {
+                       printf("%d ", i);
+                       is_empty = false;
+               }
+       }
+
+       if (is_empty)
+               PRINT_Y("List of subscribed events is empty");
+}
+
+static const char *EVENT_TYPES_NAMES[MAX_EVENT_TYPE_LEN] = {
+       MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED,
+       MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+       MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED
+};
+
+static const unsigned int NUMBER_OF_TYPES = 3u;
+
+bool foreach_event_result_value_name_cb(const char *value_name, void *user_data)
+{
+       if (NULL == value_name) {
+               PRINT_R("\tError occurred. Value name is NULL");
+               return true;
+       }
+       PRINT_W("%s", value_name);
+       return true;
+}
+
+bool foreach_event_type_cb(const char *event_type, void *user_data)
+{
+       if (NULL == event_type) {
+               PRINT_R("Error occurred. Event type name is NULL");
+               return true;
+       }
+
+       PRINT_W("%s", event_type);
+       PRINT_G("\tList of supported event result value names is:");
+
+       const int error = mv_surveillance_foreach_event_result_name(
+                       event_type, foreach_event_result_value_name_cb, user_data);
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               PRINT_E("Error occurred when trying to get value names for "
+                               "event named '%s'", event_type);
+               return true;
+       }
+       return true;
+}
+
+void print_supported_events()
+{
+       PRINT_G("List of supported events is:");
+
+       const int error = mv_surveillance_foreach_supported_event_type(
+                       foreach_event_type_cb, NULL);
+
+       if (MEDIA_VISION_ERROR_NONE != error)
+               PRINT_R("Error occurred when trying to get list of event type names \n");
+}
+
+int create_trigger_handle_by_event_name(
+       mv_surveillance_event_trigger_h *handle)
+{
+       PRINT_G("\nSelect event type:");
+
+       unsigned int i = 0u;
+       for (; i < NUMBER_OF_TYPES; ++i)
+               printf("#%d. %s\n", i, EVENT_TYPES_NAMES[i]);
+
+       unsigned int event_id = 0u;
+       while (input_size("Input event type (unsigned integer value):",
+                               NUMBER_OF_TYPES - 1, &event_id) == -1) {
+               PRINT_R("Incorrect input! Try again.\n List of supported events is:");
+
+               unsigned int i = 0u;
+               for (; i < NUMBER_OF_TYPES; ++i)
+                       printf("%d\t%s\n", i, EVENT_TYPES_NAMES[i]);
+       }
+
+       const int error = mv_surveillance_event_trigger_create(
+                                               EVENT_TYPES_NAMES[event_id], handle);
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               PRINT_E("mv_surveillance_event_trigger_create() error!\n"
+                               "Error code: %i\n", error);
+               return error;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+bool try_destroy_event_trigger(mv_surveillance_event_trigger_h trigger)
+{
+       const int error = mv_surveillance_event_trigger_destroy(trigger);
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               PRINT_E("Error with code %d was occured when try to destroy "
+                               "event trigger.", error);
+               return false;
+       }
+       return true;
+}
+
+void subscribe_to_event()
+{
+       if (++trigger_id_cnt >= MAX_EVENTS_NUMBER) {
+               PRINT_R("Maximal value of event trigger id is reached. "
+                               "Subscription impossible");
+               return;
+       }
+
+       mv_surveillance_event_trigger_h event_trigger = NULL;
+       int error = create_trigger_handle_by_event_name(&event_trigger);
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               PRINT_E("Error occurred when creating of event trigger. "
+                               "Error code: %i", error);
+               try_destroy_event_trigger(event_trigger);
+               return;
+       }
+
+       int video_stream_id = 0;
+
+       while (input_int("Input video stream identificator (integer value):",
+                               INT_MIN,
+                               INT_MAX,
+                               &video_stream_id) == -1)
+               PRINT_R("Incorrect input! Try again.");
+
+       char *event_type = NULL;
+       error = mv_surveillance_get_event_trigger_type(event_trigger, &event_type);
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               PRINT_E("Error occurred when getting of event trigger type. "
+                               "Error code: %i", error);
+               try_destroy_event_trigger(event_trigger);
+               return;
+       }
+
+       if (show_confirm_dialog("Would you like to set ROI (Region Of Interest)?"))
+               add_roi_to_event(event_trigger);
+
+       if (strncmp(event_type,
+                       MV_SURVEILLANCE_EVENT_TYPE_PERSON_APPEARED_DISAPPEARED,
+                       MAX_EVENT_TYPE_LEN) == 0) {
+               error = mv_surveillance_subscribe_event_trigger(
+                       event_trigger,
+                       video_stream_id,
+                       NULL,
+                       detect_person_appeared_cb,
+                       NULL);
+       } else if (strncmp(event_type,
+                                       MV_SURVEILLANCE_EVENT_TYPE_PERSON_RECOGNIZED,
+                                       MAX_EVENT_TYPE_LEN) == 0) {
+                       PRINT_Y("Please create and save face recognition models\n"
+                                       "before subscribing to event. Use mv_face_test_suite.");
+
+               mv_engine_config_h engine_cfg = NULL;
+               error = mv_create_engine_config(&engine_cfg);
+
+               if (error != MEDIA_VISION_ERROR_NONE) {
+                       PRINT_R("Failed to create engine configuration for event trigger.");
+                       try_destroy_event_trigger(event_trigger);
+                       free(event_type);
+                       return;
+               }
+
+               const bool is_filled = fill_engine_cfg_person_recognized(engine_cfg);
+
+               if (!is_filled) {
+                       PRINT_R("Failed to fill engine configuration for event trigger.");
+                       try_destroy_event_trigger(event_trigger);
+                       if (mv_destroy_engine_config(engine_cfg) != MEDIA_VISION_ERROR_NONE)
+                               PRINT_E("Failed to destroy engine configuration for event trigger.",
+                                               error);
+                       free(event_type);
+                       return;
+               }
+
+               error = mv_surveillance_subscribe_event_trigger(
+                                       event_trigger,
+                                       video_stream_id,
+                                       engine_cfg,
+                                       person_recognized_cb,
+                                       NULL);
+
+               if (error != MEDIA_VISION_ERROR_NONE) {
+                       PRINT_E("Subscription failed. Error code: %i.", error);
+                       try_destroy_event_trigger(event_trigger);
+                       if (mv_destroy_engine_config(engine_cfg) != MEDIA_VISION_ERROR_NONE)
+                               PRINT_E("Failed to destroy engine configuration for event trigger.",
+                                               error);
+                       free(event_type);
+                       return;
+               }
+
+               if (mv_destroy_engine_config(engine_cfg) != MEDIA_VISION_ERROR_NONE)
+                       PRINT_E("Failed to destroy engine configuration for event trigger.",
+                                       error);
+       } else if (strncmp(event_type,
+                               MV_SURVEILLANCE_EVENT_TYPE_MOVEMENT_DETECTED,
+                               MAX_EVENT_TYPE_LEN) == 0) {
+               error = mv_surveillance_subscribe_event_trigger(
+                                       event_trigger,
+                                       video_stream_id,
+                                       NULL,
+                                       movement_detected_cb,
+                                       NULL);
+       }
+
+       free(event_type);
+
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               PRINT_E("Error with code %d was occurred in subscribe event.", error);
+               try_destroy_event_trigger(event_trigger);
+               return;
+       }
+
+       is_subscribed[trigger_id_cnt] = event_trigger;
+       video_streams_ids[trigger_id_cnt] = video_stream_id;
+       PRINT_S("Event trigger %i has been successfully subscribed", trigger_id_cnt);
+}
+
+void add_roi_to_event(mv_surveillance_event_trigger_h event_trigger)
+{
+       int number_of_roi_points = 0;
+       while (input_int("Input number of ROI points (integer value >2):",
+                                       MIN_NUMBER_OF_ROI_POINTS,
+                                       MAX_NUMBER_OF_ROI_POINTS,
+                                       &number_of_roi_points) == -1)
+               PRINT_R("Incorrect input! Try again.");
+
+       mv_point_s* roi = (mv_point_s*) malloc(sizeof(mv_point_s) * number_of_roi_points);
+
+       int x = 0;
+       int y = 0;
+
+       int i = 0;
+       for (; i < number_of_roi_points; ++i) {
+               printf("Point %d \n", i + 1);
+
+               while (input_int("Input x (integer value):",
+                                               MIN_ROI_X_COORD,
+                                               MAX_ROI_X_COORD,
+                                               &x) == -1)
+                       PRINT_R("Incorrect input! Try again.");
+
+               while (input_int("Input y (integer value):",
+                                               MIN_ROI_Y_COORD,
+                                               MAX_ROI_Y_COORD,
+                                               &y) == -1)
+                       PRINT_R("Incorrect input! Try again.");
+
+               roi[i].x = x;
+               roi[i].y = y;
+       }
+
+       const int error = mv_surveillance_set_event_trigger_roi(
+                                               event_trigger,
+                                               number_of_roi_points,
+                                               roi);
+
+       if (error == MEDIA_VISION_ERROR_NONE)
+               PRINT_G("ROI was successfully set")
+       else
+               PRINT_R("Setting ROI failed. Please try again") ;
+
+       if (roi != NULL)
+               free(roi);
+}
+
+void unsubscribe_from_event()
+{
+       int trigger_id = 0;
+       while (input_int("Input event identificator (1-100):",
+                                       1,
+                                       MAX_EVENTS_NUMBER - 1,
+                                       &trigger_id) == -1)
+               PRINT_R("Incorrect input! Try again.");
+
+       mv_surveillance_event_trigger_h event_trigger = is_subscribed[trigger_id];
+       if (NULL == event_trigger) {
+               PRINT_E("Sorry, event trigger with %i identifier wasn't subscribed.",
+                               trigger_id);
+               return;
+       }
+
+       const int error = mv_surveillance_unsubscribe_event_trigger(
+                       event_trigger,
+                       video_streams_ids[trigger_id]);
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in unsubscribe event.", error);
+               return;
+       }
+
+       try_destroy_event_trigger(event_trigger);
+       is_subscribed[trigger_id] = NULL;
+       video_streams_ids[trigger_id] = -1;
+       PRINT_S("Event with id %d was successfully unsubscribed", trigger_id);
+}
+
+void unsubscribe_from_all_events()
+{
+       int error = MEDIA_VISION_ERROR_NONE;
+       unsigned int trigger_id = 0;
+       int unsubscribed_number = 0;
+       for (; trigger_id < MAX_EVENTS_NUMBER; ++trigger_id) {
+               mv_surveillance_event_trigger_h event_trigger =
+                       is_subscribed[trigger_id];
+               if (NULL != event_trigger) {
+                       error = mv_surveillance_unsubscribe_event_trigger(
+                                       event_trigger,
+                                       video_streams_ids[trigger_id]);
+                       if (error != MEDIA_VISION_ERROR_NONE) {
+                               PRINT_E("Error with code %d was occurred in unsubscribe event.",
+                                               error);
+                               continue;
+                       }
+                       ++unsubscribed_number;
+
+                       PRINT_S("Event with id %d was successfully unsubscribed", trigger_id);
+
+                       try_destroy_event_trigger(event_trigger);
+                       is_subscribed[trigger_id] = NULL;
+                       video_streams_ids[trigger_id] = -1;
+               }
+       }
+
+       unsubscribed_number > 0 ?
+       PRINT_S("%d event(s) was successfully unsubscribed", unsubscribed_number):
+       PRINT_Y("\nThere are no triggers can be unsubscribed.");
+}
+
+void push_source()
+{
+       mv_source_h source;
+       int error = mv_create_source(&source);
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               PRINT_E("ERROR: Errors were occurred during source creating!!! Code %i" ,
+                               error);
+               return;
+       }
+
+       char *path_to_image = NULL;
+
+       while (input_string("Input file name with image to be analyzed:",
+                                               1024, &path_to_image) == -1)
+               PRINT_R("Incorrect input! Try again.");
+
+       error = load_mv_source_from_file(path_to_image, source);
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               PRINT_E("Errors were occurred during source loading, code %i", error);
+               return;
+       }
+
+       if (path_to_image != NULL)
+               free(path_to_image);
+
+       int video_stream_id = 0;
+
+       while (input_int("Input video stream identificator (integer value):",
+                               INT_MIN,
+                               INT_MAX,
+                               &video_stream_id) == -1)
+               PRINT_R("Incorrect input! Try again.");
+
+       error = mv_surveillance_push_source(source, video_stream_id);
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               PRINT_E("Errors were occurred during source pushing, code %i", error);
+               return;
+       }
+
+       error = mv_destroy_source(source);
+       if (MEDIA_VISION_ERROR_NONE != error) {
+               PRINT_E("Errors were occurred during source destroying, code %i", error);
+               return;
+       }
+
+       PRINT_G("Media source was successfully pushed");
+}
+
+bool fill_engine_cfg_person_recognized(mv_engine_config_h engine_cfg)
+{
+       char *path_to_model = NULL;
+
+       while (input_string("Input file name with face recognition model:",
+                                               1024, &path_to_model) == -1)
+               PRINT_R("Incorrect input! Try again.");
+
+       const int error = mv_engine_config_set_string_attribute(
+                                               engine_cfg,
+                                               MV_SURVEILLANCE_FACE_RECOGNITION_MODEL_FILE_PATH,
+                                               path_to_model);
+
+       if (error != MEDIA_VISION_ERROR_NONE)
+               PRINT_E("Setting path to face recognition model failed, code %i",
+                               error);
+       else
+               printf("\nModel path is %s \n", path_to_model);
+
+       if (path_to_model != NULL)
+               free(path_to_model);
+
+       return true;
+}
+
+void turn_on_off_saving_to_image()
+{
+       save_results_to_image = !save_results_to_image;
+
+       save_results_to_image ?
+               PRINT_Y("Save event results to image files ON."):
+               PRINT_Y("Save event results to image files OFF.");
+}
+
+void detect_person_appeared_cb(
+       mv_surveillance_event_trigger_h handle,
+       mv_source_h source,
+       int video_stream_id,
+       mv_surveillance_result_h event_result,
+       void *user_data)
+{
+       PRINT_G("Person appeared / disappeared event was occured");
+       if (save_results_to_image)
+               PRINT_G("Output image will be saved to /tmp/person_app.jpg.\n"
+                               "Appeared locations - green;\n"
+                               "Tracked locations - blue;\n"
+                               "Disappeared locations - red.");
+
+       unsigned char *out_buffer = NULL;
+       unsigned int buf_size = 0;
+       image_data_s image_data = { 0, 0, MEDIA_VISION_COLORSPACE_INVALID };
+
+       if (save_results_to_image &&
+               (mv_source_get_buffer(source, &out_buffer, &buf_size) ||
+                mv_source_get_width(source, &(image_data.image_width)) ||
+                mv_source_get_height(source, &(image_data.image_height)) ||
+                mv_source_get_colorspace(source, &(image_data.image_colorspace)) ||
+                out_buffer == NULL ||
+                buf_size == 0))
+       {
+               PRINT_R("ERROR: Creating out image is impossible.");
+
+               return;
+       }
+
+       unsigned char *out_buffer_copy = NULL;
+       if (save_results_to_image) {
+               out_buffer_copy = (unsigned char *) malloc(buf_size);
+               memcpy(out_buffer_copy, out_buffer, buf_size);
+       }
+
+       int number_of_appeared_persons = 0;
+       int error = mv_surveillance_get_result_value(
+                                       event_result,
+                                       MV_SURVEILLANCE_PERSONS_APPEARED_NUMBER,
+                                       &number_of_appeared_persons);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in getting number of "
+                               "appeared persons.", error);
+               if (out_buffer_copy != NULL)
+                       free(out_buffer_copy);
+
+               return;
+       }
+
+       printf("\nNumber of appeared persons is %d \n", number_of_appeared_persons);
+
+       mv_rectangle_s *appeared_locations =
+               malloc(sizeof(mv_rectangle_s) * number_of_appeared_persons);
+
+       error = mv_surveillance_get_result_value(
+                               event_result,
+                               MV_SURVEILLANCE_PERSONS_APPEARED_LOCATIONS,
+                               appeared_locations);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in getting locations of "
+                               "appeared persons.", error);
+
+               if (appeared_locations != NULL)
+                       free(appeared_locations);
+
+               if (out_buffer_copy != NULL)
+                       free(out_buffer_copy);
+
+               return;
+       }
+
+       int i = 0;
+       for (; i < number_of_appeared_persons; ++i) {
+               printf("Person #%d location is: x - %d, y - %d, w - %d, h - %d.\n",
+                               i,
+                               appeared_locations[i].point.x,
+                               appeared_locations[i].point.y,
+                               appeared_locations[i].width,
+                               appeared_locations[i].height);
+
+               if (save_results_to_image)
+                       draw_rectangle_on_buffer(
+                                               appeared_locations[i].point.x,
+                                               appeared_locations[i].point.y,
+                                               appeared_locations[i].point.x + appeared_locations[i].width,
+                                               appeared_locations[i].point.y + appeared_locations[i].height,
+                                               3,
+                                               green_color,
+                                               &image_data,
+                                               out_buffer_copy);
+       }
+
+       int number_of_tracked_persons = 0;
+       error = mv_surveillance_get_result_value(
+                               event_result,
+                               MV_SURVEILLANCE_PERSONS_TRACKED_NUMBER,
+                               &number_of_tracked_persons);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in getting number of "
+                               "tracked persons.", error);
+
+               if (appeared_locations != NULL)
+                       free(appeared_locations);
+
+               if (out_buffer_copy != NULL)
+                       free(out_buffer_copy);
+
+               return;
+       }
+
+       printf("\nNumber of tracked persons is %d \n", number_of_tracked_persons);
+
+       mv_rectangle_s *tracked_locations =
+               malloc(sizeof(mv_rectangle_s) * number_of_tracked_persons);
+
+       error = mv_surveillance_get_result_value(
+                               event_result,
+                               MV_SURVEILLANCE_PERSONS_TRACKED_LOCATIONS,
+                               tracked_locations);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in getting locations of "
+                               "tracked persons.", error);
+
+               if (appeared_locations != NULL)
+                       free(appeared_locations);
+
+               if (tracked_locations != NULL)
+                       free(tracked_locations);
+
+               if (out_buffer_copy != NULL)
+                       free(out_buffer_copy);
+
+               return;
+       }
+
+       for (i = 0; i < number_of_tracked_persons; ++i) {
+               printf("Person #%d location is: x - %d, y - %d, w - %d, h - %d.\n",
+                               i,
+                               tracked_locations[i].point.x,
+                               tracked_locations[i].point.y,
+                               tracked_locations[i].width,
+                               tracked_locations[i].height);
+
+               if (save_results_to_image)
+                       draw_rectangle_on_buffer(
+                                               tracked_locations[i].point.x,
+                                               tracked_locations[i].point.y,
+                                               tracked_locations[i].point.x + tracked_locations[i].width,
+                                               tracked_locations[i].point.y + tracked_locations[i].height,
+                                               3,
+                                               blue_color,
+                                               &image_data,
+                                               out_buffer_copy);
+       }
+
+       int number_of_disappeared_persons = 0;
+       error = mv_surveillance_get_result_value(
+                               event_result,
+                               MV_SURVEILLANCE_PERSONS_DISAPPEARED_NUMBER,
+                               &number_of_disappeared_persons);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in getting number of "
+                               "disappeared persons.", error);
+
+               if (appeared_locations != NULL)
+                       free(appeared_locations);
+
+               if (tracked_locations != NULL)
+                       free(tracked_locations);
+
+               if (out_buffer_copy != NULL)
+                       free(out_buffer_copy);
+
+               return;
+       }
+
+       printf("\nNumber of disappeared persons is %d \n", number_of_disappeared_persons);
+
+       mv_rectangle_s *disappeared_locations =
+               malloc(sizeof(mv_rectangle_s) * number_of_disappeared_persons);
+
+       error = mv_surveillance_get_result_value(
+                               event_result,
+                               MV_SURVEILLANCE_PERSONS_DISAPPEARED_LOCATIONS,
+                               disappeared_locations);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in getting locations of "
+                               "disappeared persons.", error);
+
+               if (appeared_locations != NULL)
+                       free(appeared_locations);
+
+               if (tracked_locations != NULL)
+                       free(tracked_locations);
+
+               if (disappeared_locations != NULL)
+                       free(disappeared_locations);
+
+               if (out_buffer_copy != NULL)
+                       free(out_buffer_copy);
+
+               return;
+       }
+
+       for (i = 0; i < number_of_disappeared_persons; ++i) {
+               printf("Person #%d location is: x - %d, y - %d, w - %d, h - %d.\n",
+                               i,
+                               disappeared_locations[i].point.x,
+                               disappeared_locations[i].point.y,
+                               disappeared_locations[i].width,
+                               disappeared_locations[i].height);
+
+               if (save_results_to_image)
+                       draw_rectangle_on_buffer(
+                                               disappeared_locations[i].point.x,
+                                               disappeared_locations[i].point.y,
+                                               disappeared_locations[i].point.x + disappeared_locations[i].width,
+                                               disappeared_locations[i].point.y + disappeared_locations[i].height,
+                                               3,
+                                               red_color,
+                                               &image_data,
+                                               out_buffer_copy);
+       }
+
+       if (save_results_to_image)
+               save_image_from_buffer("/tmp/person_app.jpg", out_buffer_copy, &image_data, 100);
+
+       printf("\n");
+
+       if (appeared_locations != NULL)
+               free(appeared_locations);
+
+       if (tracked_locations != NULL)
+               free(tracked_locations);
+
+       if (disappeared_locations != NULL)
+               free(disappeared_locations);
+
+       if (out_buffer_copy != NULL)
+               free(out_buffer_copy);
+}
+
+void person_recognized_cb(
+       mv_surveillance_event_trigger_h handle,
+       mv_source_h source,
+       int video_stream_id,
+       mv_surveillance_result_h event_result,
+       void *user_data)
+{
+       PRINT_G("Person recognized event was occurred");
+       if (save_results_to_image)
+               PRINT_G("Output image will be saved to /tmp/person_rec.jpg.\n"
+                               "Person recognized locations - red.");
+
+       int number_of_persons = 0;
+       int error = mv_surveillance_get_result_value(
+                                       event_result,
+                                       MV_SURVEILLANCE_PERSONS_RECOGNIZED_NUMBER,
+                                       &number_of_persons);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in getting number of persons.",
+                               error);
+               return;
+       }
+
+       printf("\nNumber of persons is %d \n\n", number_of_persons);
+
+       mv_rectangle_s *locations = malloc(sizeof(mv_rectangle_s) * number_of_persons);
+
+       error = mv_surveillance_get_result_value(
+                               event_result,
+                               MV_SURVEILLANCE_PERSONS_RECOGNIZED_LOCATIONS,
+                               locations);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in getting locations of persons.",
+                               error);
+
+               if (locations != NULL)
+                       free(locations);
+
+               return;
+       }
+
+       int *labels = malloc(sizeof(int) * number_of_persons);
+
+       error = mv_surveillance_get_result_value(
+                               event_result,
+                               MV_SURVEILLANCE_PERSONS_RECOGNIZED_LABELS,
+                               labels);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in getting labels of persons.",
+                               error);
+
+               if (locations != NULL)
+                       free(locations);
+
+               if (labels != NULL)
+                       free(labels);
+
+               return;
+       }
+
+       double *confidences = malloc(sizeof(double) * number_of_persons);
+
+       error = mv_surveillance_get_result_value(
+                               event_result,
+                               MV_SURVEILLANCE_PERSONS_RECOGNIZED_CONFIDENCES,
+                               confidences);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in getting confidences of persons.",
+                               error);
+
+               if (locations != NULL)
+                       free(locations);
+
+               if (labels != NULL)
+                       free(labels);
+
+               if (confidences != NULL)
+                       free(confidences);
+
+               return;
+       }
+
+       unsigned char *out_buffer = NULL;
+       unsigned int buf_size = 0;
+       image_data_s image_data = { 0, 0, MEDIA_VISION_COLORSPACE_INVALID };
+
+       if (save_results_to_image &&
+               (mv_source_get_buffer(source, &out_buffer, &buf_size) ||
+                mv_source_get_width(source, &(image_data.image_width)) ||
+                mv_source_get_height(source, &(image_data.image_height)) ||
+                mv_source_get_colorspace(source, &(image_data.image_colorspace)) ||
+                out_buffer == NULL ||
+                buf_size == 0))
+       {
+               PRINT_R("ERROR: Creating out image is impossible.");
+
+               return;
+       }
+
+       unsigned char *out_buffer_copy = NULL;
+       if (save_results_to_image) {
+               out_buffer_copy = (unsigned char *) malloc(buf_size);
+               memcpy(out_buffer_copy, out_buffer, buf_size);
+       }
+
+       int i = 0;
+       for (; i < number_of_persons; ++i) {
+               printf("Person %d:\n", labels[i]);
+               printf("Location is: x - %d, y - %d, w - %d, h - %d.\n",
+                               locations[i].point.x,
+                               locations[i].point.y,
+                               locations[i].width,
+                               locations[i].height);
+               printf("Model confidence - %3.2f", confidences[i]);
+               printf("\n");
+
+               if (save_results_to_image)
+                       draw_rectangle_on_buffer(
+                                               locations[i].point.x,
+                                               locations[i].point.y,
+                                               locations[i].point.x + locations[i].width,
+                                               locations[i].point.y + locations[i].height,
+                                               3,
+                                               red_color,
+                                               &image_data,
+                                               out_buffer_copy);
+       }
+
+       printf("\n");
+
+       if (save_results_to_image)
+               save_image_from_buffer("/tmp/person_rec.jpg", out_buffer_copy, &image_data, 100);
+
+       if (locations != NULL)
+               free(locations);
+
+       if (labels != NULL)
+               free(labels);
+
+       if (confidences != NULL)
+               free(confidences);
+
+       if (out_buffer_copy != NULL)
+               free(out_buffer_copy);
+}
+
+void movement_detected_cb(
+       mv_surveillance_event_trigger_h event_trigger,
+       mv_source_h source,
+       int video_stream_id,
+       mv_surveillance_result_h event_result,
+       void *user_data)
+{
+       PRINT_G("Movement detected event was occured");
+       if (save_results_to_image)
+               PRINT_G("Output image will be saved to /tmp/move_detect.jpg.\n"
+                               "Movement detected locations - blue.");
+
+       int number_of_movement_regions = 0;
+       int error = mv_surveillance_get_result_value(
+                                       event_result,
+                                       MV_SURVEILLANCE_MOVEMENT_NUMBER_OF_REGIONS,
+                                       &number_of_movement_regions);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in getting number of "
+                               "movement regions.", error);
+
+               return;
+       }
+
+       printf("\nNumber of movement regions is %d \n", number_of_movement_regions);
+
+       mv_rectangle_s *movement_regions =
+               malloc(sizeof(mv_rectangle_s) * number_of_movement_regions);
+
+       error = mv_surveillance_get_result_value(
+                               event_result,
+                               MV_SURVEILLANCE_MOVEMENT_REGIONS,
+                               movement_regions);
+
+       if (error != MEDIA_VISION_ERROR_NONE) {
+               PRINT_E("Error with code %d was occured in getting movement regions.",
+                               error);
+
+               if (movement_regions != NULL)
+                       free(movement_regions);
+
+               return;
+       }
+
+       unsigned char *out_buffer = NULL;
+       unsigned int buf_size = 0;
+       image_data_s image_data = { 0, 0, MEDIA_VISION_COLORSPACE_INVALID };
+
+       if (save_results_to_image &&
+               (mv_source_get_buffer(source, &out_buffer, &buf_size) ||
+                mv_source_get_width(source, &(image_data.image_width)) ||
+                mv_source_get_height(source, &(image_data.image_height)) ||
+                mv_source_get_colorspace(source, &(image_data.image_colorspace)) ||
+                out_buffer == NULL ||
+                buf_size == 0))
+       {
+               PRINT_R("ERROR: Creating out image is impossible.");
+
+               if (movement_regions != NULL)
+                       free(movement_regions);
+
+               return;
+       }
+
+       unsigned char *out_buffer_copy = NULL;
+       if (save_results_to_image) {
+               out_buffer_copy = (unsigned char *) malloc(buf_size);
+               memcpy(out_buffer_copy, out_buffer, buf_size);
+       }
+
+       int i = 0;
+       for (; i < number_of_movement_regions; ++i) {
+               printf("Movement #%d region is: x - %d, y - %d, w - %d, h - %d.\n",
+                               i,
+                               movement_regions[i].point.x,
+                               movement_regions[i].point.y,
+                               movement_regions[i].width,
+                               movement_regions[i].height);
+
+               if (save_results_to_image)
+                       draw_rectangle_on_buffer(
+                                               movement_regions[i].point.x,
+                                               movement_regions[i].point.y,
+                                               movement_regions[i].point.x + movement_regions[i].width,
+                                               movement_regions[i].point.y + movement_regions[i].height,
+                                               3,
+                                               blue_color,
+                                               &image_data,
+                                               out_buffer_copy);
+       }
+
+       printf("\n");
+
+       if (save_results_to_image)
+               save_image_from_buffer("/tmp/move_detect.jpg", out_buffer_copy, &image_data, 100);
+
+       if (movement_regions != NULL)
+               free(movement_regions);
+
+       if (out_buffer_copy != NULL)
+               free(out_buffer_copy);
+}