From 3214648f800f5a8f6e9c3045612e95d0c41c124e Mon Sep 17 00:00:00 2001 From: Minje Ahn Date: Wed, 9 Sep 2015 16:55:36 +0900 Subject: [PATCH] [ACR-408] Add API for face Change-Id: I341c48d9a62608218c426d47653122f6b683001d Signed-off-by: Minje Ahn --- include/media_content.h | 1 + include/media_content_type.h | 34 +++++ include/media_face.h | 317 +++++++++++++++++++++++++++++++++++++++++++ include/media_info.h | 39 ++++++ include/media_info_private.h | 29 ++++ src/media_content.c | 4 + src/media_db.c | 77 +++++++++++ src/media_face.c | 316 ++++++++++++++++++++++++++++++++++++++++++ src/media_info.c | 34 +++++ test/media-content_test.c | 148 ++++++++++++++++++++ 10 files changed, 999 insertions(+) create mode 100755 include/media_face.h create mode 100755 src/media_face.c diff --git a/include/media_content.h b/include/media_content.h index 800e4f6..473b030 100755 --- a/include/media_content.h +++ b/include/media_content.h @@ -29,6 +29,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { diff --git a/include/media_content_type.h b/include/media_content_type.h index 0059189..da11e7b 100755 --- a/include/media_content_type.h +++ b/include/media_content_type.h @@ -270,6 +270,13 @@ typedef struct filter_s *filter_h; typedef void *media_storage_h; /** + * @ingroup CAPI_CONTENT_MEDIA_FACE_MODULE + * @brief The structure type for the Media face handle. + * @since_tizen 3.0 + */ +typedef void *media_face_h; + +/** * @ingroup CAPI_MEDIA_CONTENT_MODULE * @brief Called when the media scanning is finished. * @since_tizen @if MOBILE 2.3 @elseif WEARABLE 2.3.1 @endif @@ -566,6 +573,27 @@ typedef bool (*media_group_cb)(const char *group_name, void *user_data); typedef bool (*media_storage_cb)(media_storage_h storage, void *user_data); /** + * @ingroup CAPI_CONTENT_MEDIA_FACE_MODULE + * @brief Called for every face in the obtained list of face. + * @since_tizen 3.0 + * + * @details Iterates over a media face list. + * + * @remarks You should not destroy @a face returned by this function. + * + * @param[in] face The handle of the media face + * @param[in] user_data The user data passed from the foreach function + * + * @return @c true to continue with the next iteration of the loop, + * otherwise @c false to break out of the loop + * + * @pre media_info_foreach_face_from_db() will invoke this function. + * + * @see media_info_foreach_face_from_db() + */ +typedef bool (*media_face_cb)(media_face_h face, void *user_data); + +/** * @} */ @@ -1189,6 +1217,12 @@ typedef bool (*media_storage_cb)(media_storage_h storage, void *user_data); #define MEDIA_STORAGE_PATH "STORAGE_PATH" /**< Storage path */ /** + * @brief You can use above define to set the condition of face filter and order keyword. + * @since_tizen 3.0 + */ +#define MEDIA_FACE_TAG "MEDIA_FACE_TAG" /**< face tag */ + +/** * @} */ diff --git a/include/media_face.h b/include/media_face.h new file mode 100755 index 0000000..211f279 --- /dev/null +++ b/include/media_face.h @@ -0,0 +1,317 @@ +/* +* Copyright (c) 2014 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_MEDIA_IMAGE_FACE_H__ +#define __TIZEN_MEDIA_IMAGE_FACE_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @file media_face.h + * @brief This file contains the media face API and related to all operations with the face information of the image in Meida DB. \n + * Functions include cloning and destroying the face handler, getting face information such as face id, face coordinates in file, \n + * face tag. Face information detected and managed by DB automatically when image contents scanning. \n + * And you can insert,update,delete face information manually. + */ + +/** + * @addtogroup CAPI_CONTENT_MEDIA_FACE_MODULE + * @{ + */ + +/** + * @brief Clones the face handle. + * @details This function copies the face handle from a source to + * destination. There is no media_face_create() function. The media_face_h is created internally and available through + * media face foreach function such as media_face_foreach_face_from_db(). To use this handle outside of these foreach functions, + * use this function. + * + * @since_tizen 3.0 + * @remark The destination handle must be released with media_event_destroy() by you. + * + * @param [in] src The source face handle + * @param [out] dst A destination face handle + * + * @return 0 on success, otherwise a negative error value. + * + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_CONTENT_ERROR_OUT_OF_MEMORY Out of memory + * + * @see media_face_destroy() + * @see media_face_foreach_face_from_db() + */ +int media_face_clone(media_face_h *dst, media_face_h src); + +/** + * @brief Destroys the face handle. + * @details Function frees all resources related to face handle. This + * handle no longer can be used to perform any operation. New handle has to + * be created before next usage. + * + * @since_tizen 3.0 + * + * @param [in] face The face handle + * + * @return 0 on success, otherwise a negative error value. + * + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + * + * @see media_face_clone() + * + * @pre Get copy of face handle by calling media_face_clone() or Get face handle by calling media_info_foreach_face_from_db() + * + */ +int media_face_destroy(media_face_h face); + +/** + * @brief Gets the face id from the face handle. + * + * @since_tizen 3.0 + * + * @param [in] face The face handle + * @param [out] face_id The uuid of the face handle + * + * @return 0 on success, otherwise a negative error value. + * + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + */ +int media_face_get_face_id(media_face_h face, char **face_id); + +/** + * @brief Gets the media uuid from the face handle. + * + * @since_tizen 3.0 + * + * @param [in] face The face handle + * @param [out] media_id The media uuid of the face handle + * + * @return 0 on success, otherwise a negative error value. + * + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + */ +int media_face_get_media_id(media_face_h face, char **media_id); + + /** + * @brief Gets the face's rectangle from the face handle. + * @details This API can get the face's rectangle information. returned rectangle information includes the orientation value. + * + * @since_tizen 3.0 + * + * @param [in] face The face handle + * @param [out] rect_x The x position of face of the face handle + * @param [out] rect_y The y position of face of the face handle + * @param [out] rect_w The width of face of the face handle + * @param [out] rect_h The height of face of the face handle + * + * @return 0 on success, otherwise a negative error value. + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + */ +int media_face_get_face_rect(media_face_h face, unsigned int *rect_x, unsigned int *rect_y, unsigned int *rect_w, unsigned int *rect_h); + +/** + * @brief Gets the orientation from the face handle. + * @details This API can get the orientation value from the original image. + * + * @since_tizen 3.0 + * + * @param [in] face The face handle + * @param [out] orientation The orientation of the face handle + * + * @return 0 on success, otherwise a negative error value. + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + */ +int media_face_get_orientation(media_face_h face, media_content_orientation_e *orientation); + +/** + * @brief Gets the tag from the face handle. + * + * @since_tizen 3.0 + * + * @param [in] face The face handle + * @param [out] tag The tag of the face handle + * + * @return 0 on success, otherwise a negative error value. + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + */ +int media_face_get_tag(media_face_h face, char **tag); + +/** + * @brief Creates the face handle. + * + * @since_tizen 3.0 + * + * @param [out] face The face handle + * + * @return 0 on success, otherwise a negative error value. + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + * @see media_face_destroy() + */ +int media_face_create_handle(const char *media_id, media_face_h *face); + +/** + * @brief Sets the face rectangle of the face handle + * + * @since_tizen 3.0 + * + * @param[in] face The face handle + * @param[in] rect_x The integer to set as a position x of face rectangle + * @param[in] rect_y The integer to set as a position y of face rectangle + * @param[in] rect_w The integer to set as a width of face rectangle + * @param[in] rect_h The integer to set as a height of face rectangle + * + * @return 0 on success, otherwise a negative error value. + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_CONTENT_ERROR_OUT_OF_MEMORY Out of memory + * + * @post media_face_insert_to_db() + * @post media_face_update_to_db() + * + */ +int media_face_set_face_rect(media_face_h face, unsigned int rect_x, unsigned int rect_y, unsigned int rect_w, unsigned int rect_h); + +/** + * @brief Sets the orientation of the face handle + * @details This API may set the value of the original image orientation. + * + * @since_tizen 3.0 + * + * @param[in] face The face handle + * @param[in] orientation The integer to set as an orientation + * + * @return 0 on success, otherwise a negative error value. + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_CONTENT_ERROR_OUT_OF_MEMORY Out of memory + * + * @post media_face_insert_to_db() + * @post media_face_update_to_db() + * + */ +int media_face_set_orientation(media_face_h face, media_content_orientation_e orientation); + +/** + * @brief Sets the tag of the face handle. + * + * @since_tizen 3.0 + * + * @param [in] face The face handle + * @param [in] tag The tag of the face handle + * + * @return 0 on success, otherwise a negative error value. + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_CONTENT_ERROR_OUT_OF_MEMORY Out of memory + * + * @post media_face_insert_to_db() + * @post media_face_update_to_db() + */ +int media_face_set_tag(media_face_h face, const char *tag); + +/** + * @brief Inserts a new face in the media database. + * @since_tizen 3.0 + * + * @privlevel public + * @privilege %http://tizen.org/privilege/content.write + * + * @remarks The created tag handle must be released using media_tag_destroy(). + * + * @param [in] face The face handle + * + * @return 0 on success, otherwise a negative error value. + * + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_CONTENT_ERROR_OUT_OF_MEMORY Out of memory + * @retval #MEDIA_CONTENT_ERROR_PERMISSION_DENIED Permission denied + * + * @see media_content_connect() + * @see media_face_destroy() + * @see media_face_set_xxx() + */ +int media_face_insert_to_db(media_face_h face); + +/** + * @brief Updates the face details to the media database. + * + * @details The function updates the given media face in the media database. The function should be called after any change in face, to be updated to the media + * database. For example, after using media_face_set_orientation() for setting the orientation of the face, media_face_update_to_db() function should be called so as to update + * the given face attibutes in the media database. + * @since_tizen 3.0 + * + * @privlevel public + * @privilege %http://tizen.org/privilege/content.write + * + * @param[in] face The face handle to update + * + * @return 0 on success, otherwise a negative error value. + * + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_CONTENT_ERROR_PERMISSION_DENIED Permission denied + * + * @pre This function requires opened connection to content service by media_content_connect(). + * + * @see media_content_connect() + * @see media_face_destroy() + * @see media_face_set_xxx() + * + */ +int media_face_update_to_db(media_face_h face); + +/** + * @brief Deletes the face with given face uuid from the media database. + * + * @since_tizen 3.0 + * + * @privlevel public + * @privilege %http://tizen.org/privilege/content.write + * + * @param [in] face_id The id of media face + * + * @return 0 on success, otherwise a negative error value. + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_CONTENT_ERROR_PERMISSION_DENIED Permission denied + * + * @pre This function requires opened connection to content service by media_content_connect(). + * @see media_content_connect() + * + */ +int media_face_delete_from_db(const char *face_id); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIA_IMAGE_FACE_H__ */ diff --git a/include/media_info.h b/include/media_info.h index 4a3b2f6..04c377c 100755 --- a/include/media_info.h +++ b/include/media_info.h @@ -445,6 +445,45 @@ int media_info_get_bookmark_count_from_db(const char *media_id, filter_h filter, int media_info_foreach_bookmark_from_db (const char *media_id, filter_h filter, media_bookmark_cb callback, void *user_data); /** + * @brief Gets the number of face for the passed @a media_id from the media database. + * @since_tizen 3.0 + * @param[in] media_id media id + * @param[in] filter The handle to the media filter + * @param[out] face_count The count of media face + * @return 0 on success, otherwise a negative error value. + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_CONTENT_ERROR_DB_FAILED DB operation failed + * @retval #MEDIA_CONTENT_ERROR_PERMISSION_DENIED Permission denied + * @pre This function requires opened connection to content service by media_content_connect(). + * @see media_content_connect() + * + */ +int media_info_get_face_count_from_db(const char *media_id, filter_h filter, int *face_count); + +/** + * @brief Iterates through the media files with optional @a media_id in the given @a face @a face from the media database. + * @details This function gets all media face info associated with the given media id and + * meeting desired filter option and calls registered callback function for + * every retrieved media face info. If NULL is passed to the @a filter, no filtering is applied. + * @since_tizen 3.0 + * @param [in] media_id media id + * @param[in] filter The handle to the media filter + * @param [in] callback The callback function to invoke + * @param [in] user_data The user data to be passed to the callback function + * @return 0 on success, otherwise a negative error value. + * @retval #MEDIA_CONTENT_ERROR_NONE Successful + * @retval #MEDIA_CONTENT_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_CONTENT_ERROR_OUT_OF_MEMORY Out of memory + * @retval #MEDIA_CONTENT_ERROR_PERMISSION_DENIED Permission denied + * @pre This function requires opened connection to content service by media_content_connect(). + * @see media_content_connect() + * @see media_filter_create() + * + */ +int media_info_foreach_face_from_db (const char *media_id, filter_h filter, media_face_cb callback, void *user_data); + +/** * @brief Gets the image metadata for a given media info. * @details This function returns an image metadata handle retrieved from the media info. * diff --git a/include/media_info_private.h b/include/media_info_private.h index 1058357..ba1669f 100755 --- a/include/media_info_private.h +++ b/include/media_info_private.h @@ -161,6 +161,7 @@ typedef enum { MEDIA_GROUP_TAG_BY_MEDIA_ID, MEDIA_GROUP_BOOKMARK_BY_MEDIA_ID, MEDIA_GROUP_STORAGE, + MEDIA_GROUP_FACE_BY_MEDIA_ID, } group_list_e; typedef enum { @@ -349,6 +350,18 @@ typedef struct int storage_type; }media_storage_s; +typedef struct +{ + char *face_id; /* face uuid */ + char *media_id; /* media uuid */ + unsigned int face_rect_x; /* x position of face */ + unsigned int face_rect_y; /* y position of face */ + unsigned int face_rect_w; /* width of face */ + unsigned int face_rect_h; /* height of face */ + int orientation; /* orientation */ + char *face_tag; /* face tag */ +}media_face_s; + typedef struct _attribute_map_s { GHashTable *attr_map; @@ -394,6 +407,8 @@ typedef struct _media_content_cb_data { #define DB_TABLE_BOOKMARK "bookmark" #define DB_TABLE_STORAGE "storage" #define DB_TABLE_MEDIA_VIEW "media_view" +#define DB_TABLE_FACE "face" +#define DB_TABLE_FACE_SCAN_LIST "face_scan_list" /* DB View */ #define DB_VIEW_PLAYLIST "playlist_view" @@ -513,6 +528,9 @@ typedef struct _media_content_cb_data { #define DB_FIELD_STORAGE_ID "storage_uuid" #define DB_FIELD_STORAGE_PATH "storage_path" +/* DB field for Face */ +#define DB_FIELD_FACE_TAG "face_tag" + /* DB Query Keyword */ #define QUERY_KEYWORD_AND "AND" #define QUERY_KEYWORD_OR "OR" @@ -530,6 +548,8 @@ typedef struct _media_content_cb_data { ON (b.media_uuid = m.media_uuid)) WHERE m.validity=1" #define ALBUM_MEDIA_JOIN "("DB_TABLE_ALBUM" AS a INNER JOIN '%s' AS m \ ON (a.album_id = m.album_id)) WHERE m.validity=1" +#define FACE_MEDIA_JOIN "("DB_TABLE_FACE" AS fa INNER JOIN '%s' AS m \ + ON (fa.media_uuid = m.media_uuid)) WHERE m.validity=1" /* Get Group List */ #define SELECT_ALBUM_LIST "SELECT DISTINCT a.album_id, a.name, a.artist, a.album_art FROM "ALBUM_MEDIA_JOIN @@ -628,6 +648,14 @@ typedef struct _media_content_cb_data { #define SELECT_STORAGE_LIST "SELECT * FROM "DB_TABLE_STORAGE" WHERE validity=1" #define SELECT_STORAGE_INFO_FROM_STORAGE "SELECT * FROM "DB_TABLE_STORAGE" WHERE validity=1 AND storage_uuid='%s'" +/* Face */ +#define DELETE_FACE_FROM_FACE "DELETE FROM "DB_TABLE_FACE" WHERE face_uuid='%q'" +#define INSERT_FACE_TO_FACE "INSERT INTO "DB_TABLE_FACE" (face_uuid, media_uuid, face_rect_x , face_rect_y, face_rect_w, face_rect_h, orientation, face_tag) VALUES ('%q', '%q', %d, %d, %d, %d, %d, %Q);" +#define UPDATE_FACE_TO_FACE "UPDATE "DB_TABLE_FACE" SET face_rect_x=%d, face_rect_y=%d, face_rect_w=%d, face_rect_h=%d, orientation=%d, face_tag=%Q WHERE face_uuid='%q'" +#define SELECT_MEDIA_COUNT_FROM_MEDIA_BY_ID "SELECT COUNT(*) FROM "DB_TABLE_MEDIA_VIEW" WHERE media_uuid='%q' AND validity=1" +#define SELECT_FACE_COUNT_BY_MEDIA_ID "SELECT COUNT(*) FROM "FACE_MEDIA_JOIN" AND fa.media_uuid='%s'" +#define SELECT_FACE_LIST_BY_MEDIA_ID "SELECT fa.face_uuid, fa.media_uuid, fa.face_rect_x, fa.face_rect_y, fa.face_rect_w, fa.face_rect_h, fa.orientation, fa.face_tag FROM "FACE_MEDIA_JOIN" AND fa.media_uuid='%s'" + #define DEFAULT_MEDIA_STORAGE_ID "media" int _content_query_prepare(sqlite3_stmt **stmt, char *select_query, char *condition_query, char *option_query); @@ -647,6 +675,7 @@ int _media_db_get_playlist(filter_h filter, media_playlist_cb callback, void *us int _media_db_get_playlist_item(int playlist_id, filter_h filter, playlist_member_cb callback, void *user_data); int _media_db_get_tag(const char *media_id, filter_h filter, media_tag_cb callback, void *user_data); int _media_db_get_bookmark(const char *media_id, filter_h filter, media_bookmark_cb callback, void *user_data); +int _media_db_get_face(const char *media_id, filter_h filter, media_face_cb callback, void *user_data); int _media_db_get_group_item_count_by_id(int group_id, filter_h filter, group_list_e group_type, int *item_count); int _media_db_get_group_item_count(const char *group_name, filter_h filter, group_list_e group_type, int *item_count); int _media_db_get_group_item_by_id(int group_id, filter_h filter, media_info_cb callback, void *user_data, group_list_e group_type); diff --git a/src/media_content.c b/src/media_content.c index 98365d9..2a373c9 100755 --- a/src/media_content.c +++ b/src/media_content.c @@ -275,6 +275,10 @@ static int __media_content_create_attr_handle(void) ret = _media_filter_attribute_add(g_attr_handle, MEDIA_STORAGE_PATH, DB_FIELD_STORAGE_PATH); media_content_retv_if(ret != MEDIA_CONTENT_ERROR_NONE, ret); + /* Face */ + ret = _media_filter_attribute_add(g_attr_handle, MEDIA_FACE_TAG, DB_FIELD_FACE_TAG); + media_content_retv_if(ret != MEDIA_CONTENT_ERROR_NONE, ret); + return ret; } diff --git a/src/media_db.c b/src/media_db.c index c042b6e..6dde85e 100755 --- a/src/media_db.c +++ b/src/media_db.c @@ -699,6 +699,74 @@ int _media_db_get_bookmark(const char *media_id, filter_h filter, media_bookmark } +int _media_db_get_face(const char *media_id, filter_h filter, media_face_cb callback, void *user_data) +{ + int ret = MEDIA_CONTENT_ERROR_NONE; + char select_query[MAX_QUERY_SIZE] = {0, }; + char *condition_query = NULL; + char *option_query = NULL; + sqlite3_stmt *stmt = NULL; + attribute_h attr = NULL; + filter_s *_filter = (filter_s*)filter; + + attr = _content_get_attirbute_handle(); + + memset(select_query, 0x00, sizeof(select_query)); + + if((_filter != NULL) && STRING_VALID(_filter->storage_id)) + snprintf(select_query, sizeof(select_query), SELECT_FACE_LIST_BY_MEDIA_ID, _filter->storage_id, media_id); + else + snprintf(select_query, sizeof(select_query), SELECT_FACE_LIST_BY_MEDIA_ID, DB_TABLE_MEDIA_VIEW, media_id); + + ret = __media_db_make_query(filter, attr, select_query, sizeof(select_query), &condition_query, &option_query); + media_content_retv_if(ret != MEDIA_CONTENT_ERROR_NONE, ret); + + ret = _content_query_prepare(&stmt, select_query, condition_query, option_query); + SAFE_FREE(condition_query); + SAFE_FREE(option_query); + media_content_retv_if(ret != MEDIA_CONTENT_ERROR_NONE, ret); + + while(sqlite3_step(stmt) == SQLITE_ROW) + { + media_face_s *face = (media_face_s*)calloc(1, sizeof(media_face_s)); + + if(face == NULL) + { + media_content_error("OUT_OF_MEMORY(0x%08x)", MEDIA_CONTENT_ERROR_OUT_OF_MEMORY); + SQLITE3_FINALIZE(stmt); + return MEDIA_CONTENT_ERROR_OUT_OF_MEMORY; + } + + if(STRING_VALID((const char *)sqlite3_column_text(stmt, 0))) + face->face_id = strdup((const char *)sqlite3_column_text(stmt, 0)); + + if(STRING_VALID((const char *)sqlite3_column_text(stmt, 1))) + face->media_id = strdup((const char *)sqlite3_column_text(stmt, 1)); + + face->face_rect_x = (int)sqlite3_column_int(stmt, 2); + face->face_rect_y = (int)sqlite3_column_int(stmt, 3); + face->face_rect_w = (int)sqlite3_column_int(stmt, 4); + face->face_rect_h = (int)sqlite3_column_int(stmt, 5); + face->orientation= (int)sqlite3_column_int(stmt, 6); + + if(STRING_VALID((const char *)sqlite3_column_text(stmt, 7))) + face->face_tag = strdup((const char *)sqlite3_column_text(stmt, 7)); + + if(callback((media_face_h)face, user_data) == false) + { + media_face_destroy((media_face_h)face); + break; + } + + media_face_destroy((media_face_h)face); + } + + SQLITE3_FINALIZE(stmt); + + return ret; + +} + int _media_db_get_group_item_count_by_id(int group_id, filter_h filter, group_list_e group_type, int *item_count) { int ret = MEDIA_CONTENT_ERROR_NONE; @@ -809,6 +877,15 @@ int _media_db_get_group_item_count(const char *group_name, filter_h filter, grou SAFE_STRLCAT(select_query, tmp_query, sizeof(select_query)); } + else if (group_type == MEDIA_GROUP_FACE_BY_MEDIA_ID) + { + if((_filter != NULL) && STRING_VALID(_filter->storage_id)) + tmp_query = sqlite3_mprintf(SELECT_FACE_COUNT_BY_MEDIA_ID, _filter->storage_id, group_name); + else + tmp_query = sqlite3_mprintf(SELECT_FACE_COUNT_BY_MEDIA_ID, DB_TABLE_MEDIA_VIEW, group_name); + + SAFE_STRLCAT(select_query, tmp_query, sizeof(select_query)); + } else { media_content_error("INVALID_PARAMETER(0x%08x)", MEDIA_CONTENT_ERROR_INVALID_PARAMETER); diff --git a/src/media_face.c b/src/media_face.c new file mode 100755 index 0000000..10d8c89 --- /dev/null +++ b/src/media_face.c @@ -0,0 +1,316 @@ +/* +* Copyright (c) 2014 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 +#include + +int media_face_clone(media_face_h *dst, media_face_h src) +{ + media_face_s *_src = (media_face_s*)src; + + media_content_retvm_if(src == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid src handle"); + + media_face_s *_dst = (media_face_s *)calloc(1, sizeof(media_face_s)); + media_content_retvm_if(_dst == NULL, MEDIA_CONTENT_ERROR_OUT_OF_MEMORY, "OUT_OF_MEMORY"); + + if (STRING_VALID(_src->face_id)) + { + _dst->face_id = strdup(_src->face_id); + if(_dst->face_id== NULL) + { + media_face_destroy((media_face_h)_dst); + media_content_error("OUT_OF_MEMORY(0x%08x)", MEDIA_CONTENT_ERROR_OUT_OF_MEMORY); + return MEDIA_CONTENT_ERROR_OUT_OF_MEMORY; + } + } + + if (STRING_VALID(_src->media_id)) + { + _dst->media_id = strdup(_src->media_id); + if(_dst->media_id== NULL) + { + media_face_destroy((media_face_h)_dst); + media_content_error("OUT_OF_MEMORY(0x%08x)", MEDIA_CONTENT_ERROR_OUT_OF_MEMORY); + return MEDIA_CONTENT_ERROR_OUT_OF_MEMORY; + } + } + + _dst->face_rect_x = _src->face_rect_x; + _dst->face_rect_y = _src->face_rect_y; + _dst->face_rect_w = _src->face_rect_w; + _dst->face_rect_h = _src->face_rect_h; + _dst->orientation = _src->orientation; + + if (STRING_VALID(_src->face_tag)) + { + _dst->face_tag = strdup(_src->face_tag); + if(_dst->face_tag== NULL) + { + media_face_destroy((media_face_h)_dst); + media_content_error("OUT_OF_MEMORY(0x%08x)", MEDIA_CONTENT_ERROR_OUT_OF_MEMORY); + return MEDIA_CONTENT_ERROR_OUT_OF_MEMORY; + } + } + + *dst = (media_face_h)_dst; + + return MEDIA_CONTENT_ERROR_NONE; +} + +int media_face_destroy(media_face_h face) +{ + media_face_s *_face = (media_face_s*)face; + + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + + SAFE_FREE(_face->face_id); + SAFE_FREE(_face->media_id); + SAFE_FREE(_face->face_tag); + SAFE_FREE(_face); + + return MEDIA_CONTENT_ERROR_NONE; +} + +int media_face_get_face_id(media_face_h face, char **face_id) +{ + media_face_s* _face = (media_face_s*)face; + + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + + if(STRING_VALID(_face->face_id)) + { + *face_id = strdup(_face->face_id); + media_content_retvm_if(*face_id == NULL, MEDIA_CONTENT_ERROR_OUT_OF_MEMORY, "Out of memory"); + } + else + { + *face_id = NULL; + } + + return MEDIA_CONTENT_ERROR_NONE; +} + +int media_face_get_media_id(media_face_h face, char **media_id) +{ + media_face_s* _face = (media_face_s*)face; + + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + + if(STRING_VALID(_face->media_id)) + { + *media_id = strdup(_face->media_id); + media_content_retvm_if(*media_id == NULL, MEDIA_CONTENT_ERROR_OUT_OF_MEMORY, "Out of memory"); + } + else + { + *media_id = NULL; + } + + return MEDIA_CONTENT_ERROR_NONE; +} + +int media_face_get_face_rect(media_face_h face, unsigned int *rect_x, unsigned int *rect_y, unsigned int *rect_w, unsigned int *rect_h) +{ + media_face_s* _face = (media_face_s*)face; + + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + media_content_retvm_if(!(rect_x && rect_y && rect_w && rect_h), MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid rect"); + + *rect_x = _face->face_rect_x; + *rect_y = _face->face_rect_y; + *rect_w = _face->face_rect_w; + *rect_h = _face->face_rect_h; + + return MEDIA_CONTENT_ERROR_NONE; +} + +int media_face_get_orientation(media_face_h face, media_content_orientation_e *orientation) +{ + media_face_s* _face = (media_face_s*)face; + + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + media_content_retvm_if(orientation == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid orientation"); + + *orientation = _face->orientation; + + return MEDIA_CONTENT_ERROR_NONE; +} + +int media_face_get_tag(media_face_h face, char **tag) +{ + media_face_s* _face = (media_face_s*)face; + + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + + if (STRING_VALID(_face->face_tag)) + { + *tag = strdup(_face->face_tag); + media_content_retvm_if(*tag == NULL, MEDIA_CONTENT_ERROR_OUT_OF_MEMORY, "Out of memory"); + } + else + { + *tag = NULL; + } + + return MEDIA_CONTENT_ERROR_NONE; +} + +int media_face_create_handle(media_face_h *face) +{ + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + + media_face_s* _face = calloc(1, sizeof(media_face_s)); + media_content_retvm_if(_face == NULL, MEDIA_CONTENT_ERROR_OUT_OF_MEMORY, "Out of memory"); + + *face = (media_face_h)_face; + + return MEDIA_CONTENT_ERROR_NONE; +} + +int media_face_set_media_id(media_face_h face, const char *media_id) +{ + int ret = MEDIA_CONTENT_ERROR_NONE; + media_face_s* _face = (media_face_s*)face; + char *query_str = NULL; + sqlite3_stmt *stmt = NULL; + int item_count = 0; + + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + media_content_retvm_if(!STRING_VALID(media_id), MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "invalid media_id"); + + query_str = sqlite3_mprintf(SELECT_MEDIA_COUNT_FROM_MEDIA_BY_ID, media_id); + ret = _content_query_prepare(&stmt, query_str, NULL, NULL); + SQLITE3_SAFE_FREE(query_str); + media_content_retv_if(ret != MEDIA_CONTENT_ERROR_NONE, ret); + + while(sqlite3_step(stmt) == SQLITE_ROW) + { + item_count = (int)sqlite3_column_int(stmt, 0); + } + SQLITE3_FINALIZE(stmt); + + media_content_retvm_if(item_count == 0, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid media_id"); + + SAFE_FREE(_face->media_id); + + _face->media_id = strdup(media_id); + media_content_retvm_if(_face->media_id == NULL, MEDIA_CONTENT_ERROR_OUT_OF_MEMORY, "Out of memory"); + + return MEDIA_CONTENT_ERROR_NONE; +} + +int media_face_set_face_rect(media_face_h face, unsigned int rect_x, unsigned int rect_y, unsigned int rect_w, unsigned int rect_h) +{ + media_face_s* _face = (media_face_s*)face; + + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + media_content_retvm_if(rect_w == 0, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid rect_w"); + media_content_retvm_if(rect_h == 0, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid rect_h"); + + _face->face_rect_x = rect_x; + _face->face_rect_y = rect_y; + _face->face_rect_w = rect_w; + _face->face_rect_h = rect_h; + + return MEDIA_CONTENT_ERROR_NONE; +} + +int media_face_set_orientation(media_face_h face, media_content_orientation_e orientation) +{ + media_face_s* _face = (media_face_s*)face; + + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + + _face->orientation = orientation; + + return MEDIA_CONTENT_ERROR_NONE; +} + +int media_face_set_tag(media_face_h face, const char *tag) +{ + media_face_s* _face = (media_face_s*)face; + + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + + if (STRING_VALID(tag)) + _face->face_tag = strdup(tag); + else + _face->face_tag = NULL; + + return MEDIA_CONTENT_ERROR_NONE; +} + +int media_face_insert_to_db(media_face_h face) +{ + int ret = MEDIA_CONTENT_ERROR_NONE; + char *query_str = NULL; + char *face_uuid = NULL; + + media_face_s* _face = (media_face_s*)face; + + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + media_content_retvm_if(_face->media_id == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid media_id"); + media_content_retvm_if(_face->face_rect_w == 0, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid rect_w"); + media_content_retvm_if(_face->face_rect_w == 0, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid rect_h"); + + ret = media_svc_generate_uuid(&face_uuid); + media_content_retvm_if(ret != MS_MEDIA_ERR_NONE, MEDIA_CONTENT_ERROR_INVALID_OPERATION, "Fail to generate face_id"); + + SAFE_FREE(_face->face_id); + _face->face_id = strdup(face_uuid); + SAFE_FREE(face_uuid); + + query_str = sqlite3_mprintf(INSERT_FACE_TO_FACE, _face->face_id, _face->media_id, _face->face_rect_x, _face->face_rect_y, _face->face_rect_w, _face->face_rect_h, _face->orientation, _face->face_tag); + + ret = _content_query_sql(query_str); + SQLITE3_SAFE_FREE(query_str); + + return ret; +} + +int media_face_update_to_db(media_face_h face) +{ + int ret = MEDIA_CONTENT_ERROR_NONE; + char *query_str = NULL; + + media_face_s* _face = (media_face_s*)face; + + media_content_retvm_if(face == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid handle"); + media_content_retvm_if(_face->face_id == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid face_id"); + media_content_retvm_if(_face->media_id == NULL, MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "Invalid media_id"); + + query_str = sqlite3_mprintf(UPDATE_FACE_TO_FACE, _face->face_rect_x, _face->face_rect_y, _face->face_rect_w, _face->face_rect_h, _face->orientation, _face->face_tag, _face->face_id); + + ret = _content_query_sql(query_str); + SQLITE3_SAFE_FREE(query_str); + + return ret; +} + +int media_face_delete_from_db(const char *face_id) +{ + int ret = MEDIA_CONTENT_ERROR_NONE; + char *query_str = NULL; + + media_content_retvm_if(!STRING_VALID(face_id), MEDIA_CONTENT_ERROR_INVALID_PARAMETER, "invalid face_id"); + + query_str = sqlite3_mprintf(DELETE_FACE_FROM_FACE, face_id); + + ret = _content_query_sql(query_str); + SQLITE3_SAFE_FREE(query_str); + + return ret; +} diff --git a/src/media_info.c b/src/media_info.c index 5983791..7a16af8 100755 --- a/src/media_info.c +++ b/src/media_info.c @@ -1432,6 +1432,40 @@ int media_info_foreach_bookmark_from_db (const char *media_id, filter_h filter, return ret; } +int media_info_get_face_count_from_db(const char *media_id, filter_h filter, int *face_count) +{ + int ret = MEDIA_CONTENT_ERROR_NONE; + + if(STRING_VALID(media_id) && face_count) + { + ret = _media_db_get_group_item_count(media_id, filter, MEDIA_GROUP_FACE_BY_MEDIA_ID, face_count); + } + else + { + media_content_error("INVALID_PARAMETER(0x%08x)", MEDIA_CONTENT_ERROR_INVALID_PARAMETER); + ret = MEDIA_CONTENT_ERROR_INVALID_PARAMETER; + } + + return ret; +} + +int media_info_foreach_face_from_db (const char *media_id, filter_h filter, media_face_cb callback, void *user_data) +{ + int ret = MEDIA_CONTENT_ERROR_NONE; + + if((callback != NULL) && STRING_VALID(media_id)) + { + ret = _media_db_get_face(media_id, filter, callback, user_data); + } + else + { + media_content_error("INVALID_PARAMETER(0x%08x)", MEDIA_CONTENT_ERROR_INVALID_PARAMETER); + ret = MEDIA_CONTENT_ERROR_INVALID_PARAMETER; + } + + return ret; +} + int media_info_get_image(media_info_h media, image_meta_h *image) { int ret = MEDIA_CONTENT_ERROR_NONE; diff --git a/test/media-content_test.c b/test/media-content_test.c index eb57af2..da18896 100755 --- a/test/media-content_test.c +++ b/test/media-content_test.c @@ -3081,6 +3081,154 @@ int test_noti() return ret; } +bool media_face_test_cb(media_face_h face, void *user_data) +{ + char *face_id = NULL; + char *media_id = NULL; + unsigned int rect_x = 0; + unsigned int rect_y = 0; + unsigned int rect_w = 0; + unsigned int rect_h = 0; + int orientation = 0; + char *face_tag = NULL; + + media_face_get_face_id(face, &face_id); + media_face_get_media_id(face, &media_id); + media_face_get_face_rect(face, &rect_x, &rect_y, &rect_w, &rect_h); + media_face_get_orientation(face, &orientation); + media_face_get_tag(face, &face_tag); + + media_content_debug("face_id [%s] media_id [%s]", face_id, media_id); + media_content_debug("rect_x [%d] rect_y [%d] rect_w [%d] rect_h [%d] orientation [%d]", rect_x, rect_y, rect_w, rect_h, orientation); + media_content_debug("tag [%s]", face_tag); + + if (user_data != NULL) { + media_face_h new_face = NULL; + media_face_clone(&new_face, face); + + GList **list = (GList**)user_data; + *list = g_list_append(*list, new_face); + } + + SAFE_FREE(face_id); + SAFE_FREE(media_id); + SAFE_FREE(face_tag); + + return true; +} + +int test_face(void) +{ + int ret = MEDIA_CONTENT_ERROR_NONE; + filter_h filter = NULL; + GList *all_item_list = NULL; + int i = 0; + + ret = media_filter_create(&filter); + media_content_retvm_if(ret != MEDIA_CONTENT_ERROR_NONE, ret, "fail media_filter_create"); + + ret = media_filter_set_condition(filter, "MEDIA_TYPE = 0", MEDIA_CONTENT_COLLATE_DEFAULT); + if(ret != MEDIA_CONTENT_ERROR_NONE) { + media_filter_destroy(filter); + media_content_error("Fail to set condition"); + return ret; + } + + ret = media_info_foreach_media_from_db(filter, gallery_media_item_cb, &all_item_list); + if(ret != MEDIA_CONTENT_ERROR_NONE) { + media_content_error("media_info_foreach_media_from_db failed: %d", ret); + media_filter_destroy(filter); + return ret; + } + + for(i = 0; i < g_list_length(all_item_list); i++) { + media_info_h media_handle = NULL; + char *media_id = NULL; + int face_count = 0; + + media_handle = (media_info_h)g_list_nth_data(all_item_list, i); + + ret = media_info_get_media_id(media_handle, &media_id); + if(ret != MEDIA_CONTENT_ERROR_NONE) + media_content_error("media_info_get_media_id failed: %d", ret); + + ret = media_info_get_face_count_from_db(media_id, filter, &face_count); + if(ret != MEDIA_CONTENT_ERROR_NONE) + media_content_error("media_info_get_face_count_from_db failed: %d", ret); + + media_content_error("media_id [%s] face_count [%d]", media_id, face_count); + + ret = media_info_foreach_face_from_db(media_id, filter, media_face_test_cb, NULL); + if(ret != MEDIA_CONTENT_ERROR_NONE) + media_content_error("media_info_foreach_face_from_db failed: %d", ret); + + media_info_destroy(media_handle); + } + + media_filter_destroy(filter); + + return ret; +} + +int test_face_add_del(void) +{ + int ret = MEDIA_CONTENT_ERROR_NONE; + char *media_id = "ecca7366-e085-41d8-a12b-cbdfc2b9c5fc"; + + /* Insert Test */ + media_face_h face = NULL; + + char *face_tag = "test_face_tag"; + + ret = media_face_create_handle(&face); + media_content_retvm_if(ret != MEDIA_CONTENT_ERROR_NONE, ret, "fail media_face_create_handle"); + + ret = media_face_set_media_id(face, media_id); + ret = media_face_set_face_rect(face, 10, 12, 50, 100); + ret = media_face_set_orientation(face, 5); + ret = media_face_set_tag(face, face_tag); + + ret = media_face_insert_to_db(face); + ret = media_face_destroy(face); + + /* Update Test */ + GList *all_item_list = NULL; + filter_h filter = NULL; + ret = media_filter_create(&filter); + media_content_retvm_if(ret != MEDIA_CONTENT_ERROR_NONE, ret, "fail media_filter_create"); + + ret = media_filter_set_condition(filter, "MEDIA_FACE_TAG IS NOT NULL", MEDIA_CONTENT_COLLATE_DEFAULT); + if(ret != MEDIA_CONTENT_ERROR_NONE) { + media_filter_destroy(filter); + media_content_error("Fail to set condition"); + return ret; + } + + ret = media_info_foreach_face_from_db(media_id, filter, media_face_test_cb, &all_item_list); + + if (g_list_length(all_item_list) > 0 ) { + media_face_h face_handle = NULL; + face_handle = (media_face_h)g_list_nth_data(all_item_list, 0); + + ret = media_face_set_face_rect(face_handle, 20, 22, 70, 70); + ret = media_face_set_orientation(face_handle, 3); + ret = media_face_set_tag(face_handle, NULL); + ret = media_face_update_to_db(face_handle); + + media_face_destroy(face_handle); + } + + media_filter_destroy(filter); + + /* Delete Test */ + char *face_id = "5e58a3a8-f0b2-4c29-b799-b49a70dc2313"; + + /* Delete Test*/ + ret = media_face_delete_from_db(face_id); + + return ret; +} + int main(int argc, char *argv[]) { int ret = MEDIA_CONTENT_ERROR_NONE; -- 2.7.4