From e3319e5baee88cf1054386083a44889d1ce8e740 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Tue, 6 Sep 2016 11:30:57 +0300 Subject: [PATCH 01/16] Add raw audio formats. Fix class info for parser Change-Id: I7dd5446ec99a04bd61cb7a83e26a0023ea791a8a Signed-off-by: Volodymyr Brynza --- include/media_streamer_gst.h | 2 +- src/media_streamer_gst.c | 11 ++++++++--- src/media_streamer_node.c | 2 +- src/media_streamer_util.c | 7 +++++++ test/media_streamer_test.c | 15 ++++++++++++--- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/include/media_streamer_gst.h b/include/media_streamer_gst.h index d407829..37f2b2b 100644 --- a/include/media_streamer_gst.h +++ b/include/media_streamer_gst.h @@ -32,7 +32,7 @@ #define MEDIA_STREAMER_BIN_KLASS "Generic/Bin" #define MEDIA_STREAMER_QUEUE_KLASS "Generic" #define MEDIA_STREAMER_OVERLAY_KLASS "Filter/Editor" -#define MEDIA_STREAMER_PARSER_KLASS "Codec/Parser/Converter" +#define MEDIA_STREAMER_PARSER_KLASS "Codec/Parser" #define MEDIA_STREAMER_CONVERTER_KLASS "Filter/Converter" #define MEDIA_STREAMER_DECODER_KLASS "Codec/Decoder" #define MEDIA_STREAMER_SINK_KLASS "Sink" diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index 2fa751d..0c607d0 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -872,7 +872,6 @@ static gboolean __ms_feature_node_filter(GstPluginFeature *feature, gpointer dat const gchar *factory_klass = gst_element_factory_get_klass(factory); if (plug_info && g_strrstr(factory_klass, plug_info->info->klass_name)) { - if (GST_IS_CAPS(plug_info->src_caps)) src_can_accept = gst_element_factory_can_src_any_caps(factory, plug_info->src_caps); @@ -1699,8 +1698,14 @@ GstCaps *__ms_create_caps_from_fmt(media_format_h fmt) if (MEDIA_FORMAT_RAW == (mime & MEDIA_FORMAT_RAW)) caps = gst_caps_new_simple("audio/x-raw", "channels", G_TYPE_INT, channel, "format", G_TYPE_STRING, __ms_convert_mime_to_string_format(mime), "rate", G_TYPE_INT, samplerate, NULL); - else if (MEDIA_FORMAT_ENCODED == (mime & MEDIA_FORMAT_ENCODED)) - caps = gst_caps_new_simple(__ms_convert_mime_to_string_format(mime), "channels", G_TYPE_INT, channel, "rate", G_TYPE_INT, samplerate, NULL); + else if (MEDIA_FORMAT_ENCODED == (mime & MEDIA_FORMAT_ENCODED)) { + if (mime & MEDIA_FORMAT_AAC) + caps = gst_caps_new_simple(__ms_convert_mime_to_string_format(mime), "mpegversion", G_TYPE_INT, 4, NULL); + else if (mime & MEDIA_FORMAT_MP3) + caps = gst_caps_new_simple(__ms_convert_mime_to_string_format(mime), "mpegversion", G_TYPE_INT, 1, "layer", G_TYPE_INT, 3, NULL); + else + caps = gst_caps_new_simple(__ms_convert_mime_to_string_format(mime), "channels", G_TYPE_INT, channel, "rate", G_TYPE_INT, samplerate, NULL); + } caps_name = gst_caps_to_string(caps); ms_info("Creating Audio Caps from media format [%s]", caps_name); diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index e62408e..10f7e57 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -68,7 +68,7 @@ node_info_s nodes_info[] = { {"Filter/Effect/Video", "videorate"}, /* MEDIA_STREAMER_NODE_TYPE_VIDEO_RATE */ {"Filter/Converter/Video/Scaler", "videoscale"}, /* MEDIA_STREAMER_NODE_TYPE_VIDEO_SCALE */ {MEDIA_STREAMER_STRICT, "textoverlay"}, /* MEDIA_STREAMER_NODE_TYPE_TEXT_OVERLAY */ - {"Codec/Parser/Converter/Video", "h263parse"}, /* MEDIA_STREAMER_NODE_TYPE_PARSER */ + {"Codec/Parser", "h263parse"}, /* MEDIA_STREAMER_NODE_TYPE_PARSER */ {MEDIA_STREAMER_STRICT, "capsfilter"}, /* MEDIA_STREAMER_NODE_TYPE_FILTER */ {MEDIA_STREAMER_STRICT, "tee"}, /* MEDIA_STREAMER_NODE_TYPE_TEE */ {MEDIA_STREAMER_STRICT, "queue"}, /* MEDIA_STREAMER_NODE_TYPE_QUEUE */ diff --git a/src/media_streamer_util.c b/src/media_streamer_util.c index d639070..8272f50 100644 --- a/src/media_streamer_util.c +++ b/src/media_streamer_util.c @@ -38,6 +38,13 @@ format_s format_table[] = { {MEDIA_FORMAT_MP3, "audio/mpeg"}, /* Audio - RAW */ {MEDIA_FORMAT_PCM, "S16LE"}, + {MEDIA_FORMAT_PCM_S24LE, "S24LE"}, + {MEDIA_FORMAT_PCM_S32LE, "S32LE"}, + {MEDIA_FORMAT_PCM_S16BE, "S16BE"}, + {MEDIA_FORMAT_PCM_S24BE, "S24BE"}, + {MEDIA_FORMAT_PCM_S32BE, "S32BE"}, + {MEDIA_FORMAT_PCM_F32LE, "F32LE"}, + {MEDIA_FORMAT_PCM_F32BE, "F32BE"}, /* {MEDIA_FORMAT_PCMA, "audio/x-alaw"}, */ /* {MEDIA_FORMAT_PCMU, "audio/x-mulaw"}, */ /* Video - ENCODED */ diff --git a/test/media_streamer_test.c b/test/media_streamer_test.c index 6a25dbd..7a647e8 100644 --- a/test/media_streamer_test.c +++ b/test/media_streamer_test.c @@ -131,6 +131,7 @@ media_format_h vfmt_raw = NULL; media_format_h vfmt_encoded = NULL; media_format_h vfmt_aenc = NULL; media_format_h afmt_raw = NULL; +media_format_h afmt_araw = NULL; media_format_h afmt_encoded = NULL; media_format_h afmt_aenc = NULL; media_format_h tsfmt = NULL; @@ -325,6 +326,14 @@ static void create_formats(void) media_format_set_audio_channel(afmt_raw, AUDIO_CHANNEL); media_format_set_audio_samplerate(afmt_raw, AUDIO_SAMPLERATE); + /* Define audio raw format for adaptive streaming */ + media_format_create(&afmt_araw); + if (media_format_set_audio_mime(afmt_araw, MEDIA_FORMAT_PCM_F32LE) != MEDIA_FORMAT_ERROR_NONE) + g_print("media_format_set_audio_mime failed!"); + + media_format_set_audio_channel(afmt_araw, AUDIO_CHANNEL); + media_format_set_audio_samplerate(afmt_araw, AUDIO_SAMPLERATE); + /* Define audio encoded format */ media_format_create(&afmt_encoded); if (media_format_set_audio_mime(afmt_encoded, MEDIA_FORMAT_AMR_NB) != MEDIA_FORMAT_ERROR_NONE) @@ -714,7 +723,7 @@ static void _create_adaptive_server_manual() APPEND_NODE(video_dec); media_streamer_node_h audio_dec = NULL; - media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER, afmt_aenc, afmt_raw, &audio_dec); + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER, afmt_aenc, afmt_araw, &audio_dec); media_streamer_node_add(current_media_streamer, audio_dec); APPEND_NODE(audio_dec); @@ -724,7 +733,7 @@ static void _create_adaptive_server_manual() APPEND_NODE(video_enc); media_streamer_node_h audio_enc = NULL; - media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER, afmt_raw, afmt_aenc, &audio_enc); + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER, afmt_araw, afmt_aenc, &audio_enc); media_streamer_node_add(current_media_streamer, audio_enc); APPEND_NODE(audio_enc); @@ -788,7 +797,7 @@ static void _create_adaptive_playing_manual() APPEND_NODE(video_dec); media_streamer_node_h audio_dec = NULL; - media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER, afmt_aenc, afmt_raw, &audio_dec); + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER, afmt_aenc, afmt_araw, &audio_dec); media_streamer_node_add(current_media_streamer, audio_dec); APPEND_NODE(audio_dec); -- 2.7.4 From fd2da0a1749ab1a5e99d963ca7b6e0c7abac2b78 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Fri, 9 Sep 2016 15:29:03 +0300 Subject: [PATCH 02/16] Add parameter setting for adaptive sink node Change-Id: I616b6a2bf7db513791e3aaed1c3fe624dd782f0a Signed-off-by: Volodymyr Brynza --- include/media_streamer.h | 16 ++++++++++++++++ src/media_streamer_node.c | 21 +++++++++++++++------ test/media_streamer_test.c | 7 +++++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/include/media_streamer.h b/include/media_streamer.h index f25715b..bff337e 100644 --- a/include/media_streamer.h +++ b/include/media_streamer.h @@ -367,6 +367,22 @@ typedef enum { */ #define MEDIA_STREAMER_PARAM_EVAS_OBJECT "evas-object" +/** + * @brief Definition for segment location parameter of adaptive sink node. + * @details Path for writing playlist from + * Data type is string. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_SEGMENT_LOCATION "location" + +/** + * @brief Definition for playlist location parameter of adaptive sink node. + * @details Path for writing playlist from. Data type is string. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_PLAYLIST_LOCATION "playlist-location" /** * @brief Called when error occurs in media streamer. diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 10f7e57..b509e03 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -47,6 +47,8 @@ param_s param_table[] = { {MEDIA_STREAMER_PARAM_EVAS_OBJECT, "evas-object"}, {MEDIA_STREAMER_PARAM_VISIBLE, "visible"}, {MEDIA_STREAMER_PARAM_HOST, "host"}, + {MEDIA_STREAMER_PARAM_SEGMENT_LOCATION, "location"}, + {MEDIA_STREAMER_PARAM_PLAYLIST_LOCATION, "playlist-location"}, {NULL, NULL} }; @@ -528,12 +530,11 @@ int __ms_sink_node_create(media_streamer_node_s *node) plugin_name = __ms_ini_get_string("node type 2:adaptive", DEFAULT_ADAPTIVE_SINK); node->gst_element = __ms_element_create(plugin_name, "adaptive_sink"); - /* FIXME: need to be modified about path and the name of files */ - g_object_set(G_OBJECT(node->gst_element), - "max-files", 0, - "playlist-length", 0, - "playlist-location", "/tmp/playlist.m3u8", - "location", "/tmp/segment%05d.ts", NULL); + if (g_strrstr(plugin_name, "hlssink")) { + g_object_set(G_OBJECT(node->gst_element), + "max-files", 0, + "playlist-length", 0, NULL); + } break; default: ms_error("Error: invalid Sink node Type [%d]", node->subtype); @@ -974,6 +975,10 @@ int __ms_node_get_param_value(media_streamer_node_s *node, param_s *param, char string_val = g_strdup(g_value_get_boolean(&value) ? "true" : "false"); else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_HOST)) string_val = g_value_dup_string(&value); + else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_SEGMENT_LOCATION)) + string_val = g_value_dup_string(&value); + else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_PLAYLIST_LOCATION)) + string_val = g_value_dup_string(&value); *string_value = string_val; @@ -1043,6 +1048,10 @@ int __ms_node_set_param_value(media_streamer_node_s *ms_node, param_s *param, co g_object_set(ms_node->gst_element, param->origin_name, !g_ascii_strcasecmp(param_value, "true"), NULL); else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_HOST)) g_object_set(ms_node->gst_element, param->origin_name, param_value, NULL); + else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_SEGMENT_LOCATION)) + g_object_set(ms_node->gst_element, param->origin_name, param_value, NULL); + else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_PLAYLIST_LOCATION)) + g_object_set(ms_node->gst_element, param->origin_name, param_value, NULL); else { ms_info("Can not set parameter [%s] in the node [%s]", param->param_name, ms_node->name); ret = MEDIA_STREAMER_ERROR_INVALID_PARAMETER; diff --git a/test/media_streamer_test.c b/test/media_streamer_test.c index 7a647e8..0f1b6d5 100644 --- a/test/media_streamer_test.c +++ b/test/media_streamer_test.c @@ -97,6 +97,9 @@ typedef enum { #define AUDIO_CHANNEL 1 #define AUDIO_SAMPLERATE 8000 +#define DEFAULT_SEGMENT_PATH "/tmp/segment%05d.ts" +#define DEFAULT_PLAYLIST_PATH "/tmp/playlist.m3u8" + /*--------------------------------------------------------------------------- | GLOBAL VARIABLE DEFINITIONS: | ---------------------------------------------------------------------------*/ @@ -699,6 +702,8 @@ static void _create_adaptive_server() /*********************** videosink *********************************** */ media_streamer_node_h adaptive_sink = NULL; media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_ADAPTIVE, &adaptive_sink); + media_streamer_node_set_param(adaptive_sink, MEDIA_STREAMER_PARAM_SEGMENT_LOCATION, DEFAULT_SEGMENT_PATH); + media_streamer_node_set_param(adaptive_sink, MEDIA_STREAMER_PARAM_PLAYLIST_LOCATION, DEFAULT_PLAYLIST_PATH); media_streamer_node_add(current_media_streamer, adaptive_sink); APPEND_NODE(adaptive_sink); } @@ -744,6 +749,8 @@ static void _create_adaptive_server_manual() media_streamer_node_h adaptive_sink = NULL; media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_ADAPTIVE, &adaptive_sink); + media_streamer_node_set_param(adaptive_sink, MEDIA_STREAMER_PARAM_SEGMENT_LOCATION, DEFAULT_SEGMENT_PATH); + media_streamer_node_set_param(adaptive_sink, MEDIA_STREAMER_PARAM_PLAYLIST_LOCATION, DEFAULT_PLAYLIST_PATH); media_streamer_node_add(current_media_streamer, adaptive_sink); APPEND_NODE(adaptive_sink); -- 2.7.4 From b4d258af1cddc3dcafd6d396a641e5796231e68c Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Fri, 9 Sep 2016 17:09:31 +0300 Subject: [PATCH 03/16] [v0.1.8] add implementation of feature check when create node Change-Id: I48eee1b3378a9b49bb59978552a52dc46f9b68fe Signed-off-by: Volodymyr Brynza --- CMakeLists.txt | 4 +- doc/mediastreamer_doc.h | 25 +++++++- include/media_streamer.h | 6 +- packaging/capi-media-streamer.spec | 9 +-- src/media_streamer_node.c | 125 +++++++++++++++++++++++++++++++++++++ 5 files changed, 157 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e56979..c87ed30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,8 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(INC_DIR include) INCLUDE_DIRECTORIES(${INC_DIR}) -SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 cynara-client") -SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 cynara-client") +SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 cynara-client capi-system-info") +SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 cynara-client capi-system-info") INCLUDE(FindPkgConfig) pkg_check_modules(${fw_name} REQUIRED ${dependents}) diff --git a/doc/mediastreamer_doc.h b/doc/mediastreamer_doc.h index 3d07310..117e05b 100755 --- a/doc/mediastreamer_doc.h +++ b/doc/mediastreamer_doc.h @@ -25,16 +25,35 @@ /** * @ingroup CAPI_MEDIA_FRAMEWORK * @defgroup CAPI_MEDIA_STREAMER_MODULE Media Streamer - * @brief The @ref CAPI_MEDIA_STREAMER_MODULE APIs provides functions for building custom pipeline + * @brief The @ref CAPI_MEDIA_STREAMER_MODULE APIs provides functions for building custom player * * @section CAPI_MEDIA_STREAMER_MODULE_HEADER Required Header * \#include * * @section CAPI_MEDIA_STREAMER_MODULE_OVERVIEW Overview + * The Media Streamer API allows application developers to construct the custom player. + * It includes provides a way to handle media content by user speicific player. * * MEDIASTREAMER allows : - * Create streamer handle and elements to build custom pipeline. - * Application can create, add and link elements manually. + * - Application can decide input type of media source. + * - Application can decide output type of media content. + * - Application can create filter nodes considering requirements. + * - Application can set/get properties of each nodes. + * + * The Media Streamer API also notifies you by callback mechanism when state is changed. + * + * @section CAPI_MEDIA_STREAMER_MODULE_FEATURE Related Features + * This API is related with the following features:\n + * - http://tizen.org/feature/network.wifi\n + * - http://tizen.org/feature/network.telephony\n + * - http://tizen.org/feature/network.ethernet\n + * - http://tizen.org/feature/camera\n + * - http://tizen.org/feature/microphone + * + * 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 Feature Element. * */ diff --git a/include/media_streamer.h b/include/media_streamer.h index bff337e..2b3f9c7 100644 --- a/include/media_streamer.h +++ b/include/media_streamer.h @@ -103,7 +103,7 @@ typedef enum { MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_TEST, /**< Audio test src type */ MEDIA_STREAMER_NODE_SRC_TYPE_VIDEO_TEST, /**< Video test src type */ MEDIA_STREAMER_NODE_SRC_TYPE_CUSTOM, /**< Custom src type */ - MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE /**< Adaptive src type */ + MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE /**< Adaptive src type, Network internet feature is required */ } media_streamer_node_src_type_e; /** @@ -121,7 +121,7 @@ typedef enum { MEDIA_STREAMER_NODE_SINK_TYPE_EVAS, /**< EVAS sink type */ MEDIA_STREAMER_NODE_SINK_TYPE_FAKE, /**< Fake sink type */ MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM, /**< Custom sink type */ - MEDIA_STREAMER_NODE_SINK_TYPE_ADAPTIVE /**< Adaptive sink type */ + MEDIA_STREAMER_NODE_SINK_TYPE_ADAPTIVE /**< Adaptive sink type to generate fragmented files */ } media_streamer_node_sink_type_e; /** @@ -148,7 +148,7 @@ typedef enum { MEDIA_STREAMER_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ MEDIA_STREAMER_ERROR_INVALID_OPERATION = TIZEN_ERROR_INVALID_OPERATION, /**< Invalid operation */ MEDIA_STREAMER_ERROR_FILE_NO_SPACE_ON_DEVICE = TIZEN_ERROR_FILE_NO_SPACE_ON_DEVICE, /**< No space left on the device */ - MEDIA_STREAMER_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Not supported */ + MEDIA_STREAMER_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< The feature is not supported */ MEDIA_STREAMER_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */ MEDIA_STREAMER_ERROR_INVALID_STATE = TIZEN_ERROR_MEDIA_STREAMER | 0x01, /**< Invalid state */ MEDIA_STREAMER_ERROR_CONNECTION_FAILED = TIZEN_ERROR_MEDIA_STREAMER | 0x02, /**< Connection failed */ diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index d0c2ad1..22d40d3 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -1,6 +1,6 @@ Name: capi-media-streamer -Summary: A Media Streamer library in Tizen Native API -Version: 0.1.7 +Summary: A Media Streamer API +Version: 0.1.8 Release: 0 Group: Multimedia/API License: Apache-2.0 @@ -21,13 +21,14 @@ BuildRequires: pkgconfig(gstreamer-app-1.0) BuildRequires: pkgconfig(iniparser) BuildRequires: pkgconfig(bundle) BuildRequires: pkgconfig(cynara-client) +BuildRequires: pkgconfig(capi-system-info) %description A MediaStreamer library in Tizen Native API. %package devel -Summary: Multimedia Streamer Library in Tizen Native API (Development) -Group: TO_BE/FILLED_IN +Summary: Multimedia Streamer API (Development) +Group: Multimedia/Development Requires: %{name} = %{version}-%{release} %description devel diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index b509e03..efd7905 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -18,6 +18,7 @@ #include #include #include +#include #define SMACK_LABEL_LEN 255 #define DEFAULT_URI_SCHEME_LENGTH 10 @@ -373,6 +374,118 @@ static int __ms_node_check_priveleges(media_streamer_node_s *node) return ret; } +static int __ms_node_check_feature(media_streamer_node_s *node) +{ +#define _FEATURE_NAME_WIFI "http://tizen.org/feature/network.wifi" +#define _FEATURE_NAME_TELEPHONY "http://tizen.org/feature/network.telephony" +#define _FEATURE_NAME_ETHERNET "http://tizen.org/feature/network.ethernet" +#define _FEATURE_NAME_CAMERA "http://tizen.org/feature/camera" +#define _FEATURE_NAME_MICROPHONE "http://tizen.org/feature/microphone" + + int ret = MEDIA_STREAMER_ERROR_NONE; + bool enabled = FALSE; + bool supported = FALSE; + + if (node->type == MEDIA_STREAMER_NODE_TYPE_SRC) { + switch (node->subtype) { + case MEDIA_STREAMER_NODE_SRC_TYPE_HTTP: + case MEDIA_STREAMER_NODE_SRC_TYPE_RTSP: + case MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE: + if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(_FEATURE_NAME_WIFI, &enabled)) { + ms_info("wifi status = %d", enabled); + if (enabled) + supported = TRUE; + } else { + ms_error("SYSTEM_INFO_ERROR"); + } + + if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(_FEATURE_NAME_TELEPHONY, &enabled)) { + ms_info("telephony status = %d", enabled); + if (enabled) + supported = TRUE; + } else { + ms_error("SYSTEM_INFO_ERROR"); + } + + if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(_FEATURE_NAME_ETHERNET, &enabled)) { + ms_info("ethernet status = %d", enabled); + if (enabled) + supported = TRUE; + } else { + ms_error("SYSTEM_INFO_ERROR"); + } + if (!supported) + ret = MEDIA_STREAMER_ERROR_NOT_SUPPORTED; + break; + case MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_CAPTURE: + if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(_FEATURE_NAME_MICROPHONE, &enabled)) { + ms_info("ethernet status = %d", enabled); + if (enabled) + supported = TRUE; + } else { + ms_error("SYSTEM_INFO_ERROR"); + } + if (!supported) + ret = MEDIA_STREAMER_ERROR_NOT_SUPPORTED; + break; + case MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA: + case MEDIA_STREAMER_NODE_SRC_TYPE_VIDEO_CAPTURE: + if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(_FEATURE_NAME_CAMERA, &enabled)) { + ms_info("ethernet status = %d", enabled); + if (enabled) + supported = TRUE; + } else { + ms_error("SYSTEM_INFO_ERROR"); + } + if (!supported) + ret = MEDIA_STREAMER_ERROR_NOT_SUPPORTED; + break; + default: + ms_info("For current Src Node [%s] subtype [%d] privileges are not needed", node->name, node->subtype); + break; + } + } + + if (node->type == MEDIA_STREAMER_NODE_TYPE_SINK) { + switch (node->subtype) { + case MEDIA_STREAMER_NODE_SINK_TYPE_HTTP: + case MEDIA_STREAMER_NODE_SINK_TYPE_RTSP: + /* case MEDIA_STREAMER_NODE_SINK_TYPE_ADAPTIVE: */ + if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(_FEATURE_NAME_WIFI, &enabled)) { + ms_info("wifi status = %d", enabled); + if (enabled) + supported = TRUE; + } else { + ms_error("SYSTEM_INFO_ERROR"); + } + + if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(_FEATURE_NAME_TELEPHONY, &enabled)) { + ms_info("telephony status = %d", enabled); + if (enabled) + supported = TRUE; + } else { + ms_error("SYSTEM_INFO_ERROR"); + } + + if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(_FEATURE_NAME_ETHERNET, &enabled)) { + ms_info("ethernet status = %d", enabled); + if (enabled) + supported = TRUE; + } else { + ms_error("SYSTEM_INFO_ERROR"); + } + if (!supported) + ret = MEDIA_STREAMER_ERROR_NOT_SUPPORTED; + break; + default: + ms_info("For current Sink Node [%s] subtype [%d] privileges are not needed", node->name, node->subtype); + break; + } + } + + return ret; +} + int __ms_src_node_create(media_streamer_node_s *node) { ms_retvm_if(node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); @@ -386,6 +499,12 @@ int __ms_src_node_create(media_streamer_node_s *node) return ret; } + ret = __ms_node_check_feature(node); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("Error getting feature for Src Node"); + return ret; + } + switch (node->subtype) { case MEDIA_STREAMER_NODE_SRC_TYPE_FILE: plugin_name = __ms_ini_get_string("node type 1:file", DEFAULT_FILE_SOURCE); @@ -489,6 +608,12 @@ int __ms_sink_node_create(media_streamer_node_s *node) return ret; } + ret = __ms_node_check_feature(node); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("Error getting feature for Sink Node"); + return ret; + } + switch (node->subtype) { case MEDIA_STREAMER_NODE_SINK_TYPE_FILE: plugin_name = __ms_ini_get_string("node type 2:file", DEFAULT_FILE_SINK); -- 2.7.4 From d3de5ee775b3166069609c6023f0fb43fc1df38f Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Mon, 26 Sep 2016 12:38:38 +0900 Subject: [PATCH 04/16] [v0.1.9] remove api reference warning Change-Id: I86319c8602b546fe91bc7fc2a46a6c300ddc72c9 --- include/media_streamer.h | 8 ++++---- packaging/capi-media-streamer.spec | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/media_streamer.h b/include/media_streamer.h index 2b3f9c7..8abd217 100644 --- a/include/media_streamer.h +++ b/include/media_streamer.h @@ -586,7 +586,7 @@ int media_streamer_src_unset_buffer_status_cb(media_streamer_node_h source); * @brief Registers a callback function to be called when the custom sink is ready for data processing. * @details This function can be called only for MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM sink type * @since_tizen 3.0 - * @param [in] sink Media streamer sink handle + * @param [in] sink Media streamer sink node handle * @param [in] callback Callback function pointer * @param [in] user_data The user data passed from the code where * media_streamer_sink_set_data_ready_cb() was invoked @@ -607,7 +607,7 @@ int media_streamer_sink_set_data_ready_cb(media_streamer_node_h sink, media_stre /** * @brief Unregisters the sink data ready callback function. * @since_tizen 3.0 - * @param [in] streamer Media streamer handle + * @param [in] sink Media streamer sink node handle * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful @@ -641,7 +641,7 @@ int media_streamer_sink_set_eos_cb(media_streamer_node_h sink, media_streamer_si /** * @brief Unregisters the sink end-of-stream callback function. * @since_tizen 3.0 - * @param [in] streamer Media streamer handle + * @param [in] sink Media streamer sink node handle * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful @@ -681,7 +681,7 @@ int media_streamer_create(media_streamer_h *streamer); * by calling media_streamer_create() or media_streamer_unprepare(). * @pre At least one src and one sink should be added and linked in the streamer * by calling media_streamer_node_create_src(), media_streamer_node_create_sink() and media_streamer_node_link(). - * @post The media streamer state will be #MEDIA_STREANER_STATE_READY. + * @post The media streamer state will be #MEDIA_STREAMER_STATE_READY. * @see media_streamer_unprepare() * @see media_streamer_create() */ diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 22d40d3..254db7e 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -1,6 +1,6 @@ Name: capi-media-streamer Summary: A Media Streamer API -Version: 0.1.8 +Version: 0.1.9 Release: 0 Group: Multimedia/API License: Apache-2.0 -- 2.7.4 From 74521c14ae107894402745a2f2bad13736d15b0c Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Thu, 29 Sep 2016 16:45:15 +0900 Subject: [PATCH 05/16] [v0.1.10] fix svace issue Change-Id: Ia7d1753b60a542f77e4228ad81f215b81c960649 --- packaging/capi-media-streamer.spec | 2 +- src/media_streamer_gst.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 254db7e..dd22bbc 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -1,6 +1,6 @@ Name: capi-media-streamer Summary: A Media Streamer API -Version: 0.1.9 +Version: 0.1.10 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index 0c607d0..0f25ac2 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -2103,6 +2103,9 @@ int __ms_find_type(media_streamer_s *ms_streamer, GstElement *src_element) GstPad *src_pad = gst_element_get_static_pad(src_element, "src"); typefind = gst_element_factory_make ("typefind", "typefinder"); + ms_retvm_if(typefind == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, + "Error creating element [typefind]"); + __ms_bin_add_element(ms_streamer->topology_bin, typefind, TRUE); gst_element_sync_state_with_parent(typefind); -- 2.7.4 From c9402eb39505065518b92f0eedea30998a5e584d Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Fri, 30 Sep 2016 12:12:20 +0900 Subject: [PATCH 06/16] [v0.1.10] fix typo Change-Id: I5b3fa22263d20276ab17c1b37c1498d951fcb82f --- src/media_streamer_node.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index efd7905..eb1a4b8 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -419,7 +419,7 @@ static int __ms_node_check_feature(media_streamer_node_s *node) break; case MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_CAPTURE: if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(_FEATURE_NAME_MICROPHONE, &enabled)) { - ms_info("ethernet status = %d", enabled); + ms_info("microphone status = %d", enabled); if (enabled) supported = TRUE; } else { @@ -431,7 +431,7 @@ static int __ms_node_check_feature(media_streamer_node_s *node) case MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA: case MEDIA_STREAMER_NODE_SRC_TYPE_VIDEO_CAPTURE: if (SYSTEM_INFO_ERROR_NONE == system_info_get_platform_bool(_FEATURE_NAME_CAMERA, &enabled)) { - ms_info("ethernet status = %d", enabled); + ms_info("camera status = %d", enabled); if (enabled) supported = TRUE; } else { -- 2.7.4 From aa12ecb7fc18cc9a0fe7ae1d33d2d91e877461c4 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Wed, 5 Oct 2016 11:32:51 +0300 Subject: [PATCH 07/16] change video encoder caps for adaptive server case Change-Id: I6cf0c0b3bb84f8701e3f526a74239d4eba1ce194 Signed-off-by: Volodymyr Brynza --- src/media_streamer_gst.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index 0f25ac2..6d16d14 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -730,7 +730,7 @@ static int __ms_adaptive_sink_prepare(media_streamer_s * ms_streamer) {"Codec/Muxer", "mpegtsmux"}, /* MEDIA_STREAMER_NODE_TYPE_MUXER */ }; - GstCaps *video_enc_src_caps = gst_caps_new_empty_simple("video/x-h264"); + GstCaps *video_enc_src_caps = gst_caps_new_empty_simple("video/mpeg"); GstCaps *video_enc_sink_caps = gst_caps_new_empty_simple("video/x-raw"); node_plug_s video_enc_plug_info = {&(nodes_info[0]), video_enc_src_caps, video_enc_sink_caps, NULL}; GstElement *video_enc = __ms_node_element_create(&video_enc_plug_info, MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER); -- 2.7.4 From 5c4a5e929baf21c23044cd98a3b063b80a154947 Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Thu, 3 Nov 2016 10:31:03 +0900 Subject: [PATCH 08/16] [v0.1.11][ACR-819] remove evas sink type Change-Id: If7c1ae8bc0bc78f7c50a6f3f922eac1d54d6b47e Signed-off-by: Eunhae Choi --- include/media_streamer.h | 12 ------------ include/media_streamer_util.h | 1 - packaging/capi-media-streamer.spec | 2 +- src/media_streamer_node.c | 7 ------- 4 files changed, 1 insertion(+), 21 deletions(-) diff --git a/include/media_streamer.h b/include/media_streamer.h index 8abd217..fec5ae3 100644 --- a/include/media_streamer.h +++ b/include/media_streamer.h @@ -118,7 +118,6 @@ typedef enum { MEDIA_STREAMER_NODE_SINK_TYPE_HTTP, /**< Http sink type, Network internet feature is required */ MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO, /**< Audio sink type */ MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY,/**< Overlay sink type */ - MEDIA_STREAMER_NODE_SINK_TYPE_EVAS, /**< EVAS sink type */ MEDIA_STREAMER_NODE_SINK_TYPE_FAKE, /**< Fake sink type */ MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM, /**< Custom sink type */ MEDIA_STREAMER_NODE_SINK_TYPE_ADAPTIVE /**< Adaptive sink type to generate fragmented files */ @@ -357,17 +356,6 @@ typedef enum { #define MEDIA_STREAMER_PARAM_HOST "host" /** - * @brief Definition for evas image object of evas sink node - * @details It is a object to draw video frame on. - * Needs to check EFL APIs to create evas object. - * Data type is Pointer. - * @since_tizen 3.0 - * @see media_streamer_node_get_params - - */ -#define MEDIA_STREAMER_PARAM_EVAS_OBJECT "evas-object" - -/** * @brief Definition for segment location parameter of adaptive sink node. * @details Path for writing playlist from * Data type is string. diff --git a/include/media_streamer_util.h b/include/media_streamer_util.h index 16347dc..b4b8625 100644 --- a/include/media_streamer_util.h +++ b/include/media_streamer_util.h @@ -152,7 +152,6 @@ typedef struct { #define DEFAULT_APP_SOURCE "appsrc" #define DEFAULT_AUDIO_SINK "pulsesink" #define DEFAULT_VIDEO_SINK "waylandsink" -#define DEFAULT_EVAS_SINK "evaspixmapsink" #define DEFAULT_VIDEO_SCALE "videoscale" #define DEFAULT_VIDEO_CONVERT "videoconvert" #define DEFAULT_VIDEO_RATE "videorate" diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index dd22bbc..85986b0 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -1,6 +1,6 @@ Name: capi-media-streamer Summary: A Media Streamer API -Version: 0.1.10 +Version: 0.1.11 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index eb1a4b8..9671e5c 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -45,7 +45,6 @@ param_s param_table[] = { {MEDIA_STREAMER_PARAM_ROTATE, "rotate"}, {MEDIA_STREAMER_PARAM_FLIP, "flip"}, {MEDIA_STREAMER_PARAM_DISPLAY_GEOMETRY_METHOD, "display-geometry-method"}, - {MEDIA_STREAMER_PARAM_EVAS_OBJECT, "evas-object"}, {MEDIA_STREAMER_PARAM_VISIBLE, "visible"}, {MEDIA_STREAMER_PARAM_HOST, "host"}, {MEDIA_STREAMER_PARAM_SEGMENT_LOCATION, "location"}, @@ -634,10 +633,6 @@ int __ms_sink_node_create(media_streamer_node_s *node) plugin_name = __ms_ini_get_string("node type 2:overlay", DEFAULT_VIDEO_SINK); node->gst_element = __ms_element_create(plugin_name, NULL); break; - case MEDIA_STREAMER_NODE_SINK_TYPE_EVAS: - plugin_name = __ms_ini_get_string("node type 2:evas", DEFAULT_EVAS_SINK); - node->gst_element = __ms_element_create(plugin_name, NULL); - break; case MEDIA_STREAMER_NODE_SINK_TYPE_FAKE: plugin_name = __ms_ini_get_string("node type 2:fake", DEFAULT_FAKE_SINK); node->gst_element = __ms_element_create(plugin_name, NULL); @@ -1167,8 +1162,6 @@ int __ms_node_set_param_value(media_streamer_node_s *ms_node, param_s *param, co g_object_set(ms_node->gst_element, param->origin_name, (int)strtol(param_value, NULL, 10), NULL); else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_DISPLAY_GEOMETRY_METHOD)) g_object_set(ms_node->gst_element, param->origin_name, (int)strtol(param_value, NULL, 10), NULL); - else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_EVAS_OBJECT)) - g_object_set(ms_node->gst_element, param->origin_name, (gpointer)param_value, NULL); else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_VISIBLE)) g_object_set(ms_node->gst_element, param->origin_name, !g_ascii_strcasecmp(param_value, "true"), NULL); else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_HOST)) -- 2.7.4 From 1041769eb01fe626dd8924e5b1f09bb5f8c10d7f Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Mon, 7 Nov 2016 17:39:03 +0900 Subject: [PATCH 09/16] [v0.1.11] apply tizen coding rule Change-Id: Ifcfe9918e54526716bcbebb2d45a25963cec555a --- src/media_streamer_gst.c | 21 ++++++++++----------- src/media_streamer_node.c | 5 +++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index 6d16d14..39a1a14 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -26,9 +26,9 @@ #define MEDIASTREAMER_DECODEBIN_TYPE_DECODER "video_decoder" typedef enum { - MEDIA_STREAMER_SINK_BIN_NORMAL, - MEDIA_STREAMER_SINK_BIN_RTP_SERVER, - MEDIA_STREAMER_SINK_BIN_ADAPTIVE, + MEDIA_STREAMER_SINK_BIN_NORMAL, + MEDIA_STREAMER_SINK_BIN_RTP_SERVER, + MEDIA_STREAMER_SINK_BIN_ADAPTIVE, } media_streamer_sink_bin_type_e; static int __ms_adaptive_sink_prepare(media_streamer_s * ms_streamer); @@ -719,7 +719,7 @@ GstElement *__ms_element_create(const char *plugin_name, const char *name) static void __hlsdemux_pad_added_cb(GstElement *demux, GstPad *pad, gpointer data) { GstPad *gp = GST_PAD(data); - gst_ghost_pad_set_target (GST_GHOST_PAD(gp), pad); + gst_ghost_pad_set_target(GST_GHOST_PAD(gp), pad); } static int __ms_adaptive_sink_prepare(media_streamer_s * ms_streamer) @@ -852,7 +852,7 @@ int __ms_adaptive_element_prepare(media_streamer_node_s *ms_node, bool auto_plug G_CALLBACK(__hlsdemux_pad_added_cb), gp, 0); } else { GstPad *manifest_src_pad = gst_element_get_static_pad(manifest_src, "src"); - gst_ghost_pad_set_target (GST_GHOST_PAD(gp), manifest_src_pad); + gst_ghost_pad_set_target(GST_GHOST_PAD(gp), manifest_src_pad); } return MEDIA_STREAMER_ERROR_NONE; @@ -1169,9 +1169,8 @@ GstElement *__ms_audio_encoder_element_create(node_plug_s *plug_info, media_stre if (!audio_encoder) audio_encoder = __ms_element_create_by_registry(&plug_info_encoder, type); - if (g_strrstr(gst_element_get_name(audio_encoder), "aac")) { + if (g_strrstr(gst_element_get_name(audio_encoder), "aac")) g_object_set(audio_encoder, "compliance", -2, NULL); - } /* Creating bin - Audio Encoder */ GstElement *audio_enc_bin = gst_bin_new("audio_encoder"); @@ -2085,7 +2084,7 @@ static void __ms_typefound_cb(GstElement *typefind, guint probability, GstCaps * gchar *type; GstPad *src_pad = gst_element_get_static_pad(typefind, "src"); - type = gst_caps_to_string (caps); + type = gst_caps_to_string(caps); if (g_strrstr(type, "video/mpegts") && adaptive_sink) { __ms_link_two_elements(typefind, src_pad, adaptive_sink->gst_element); } else { @@ -2094,7 +2093,7 @@ static void __ms_typefound_cb(GstElement *typefind, guint probability, GstCaps * } MS_SAFE_UNREF(src_pad); - g_free (type); + g_free(type); } int __ms_find_type(media_streamer_s *ms_streamer, GstElement *src_element) @@ -2102,14 +2101,14 @@ int __ms_find_type(media_streamer_s *ms_streamer, GstElement *src_element) GstElement *typefind = NULL; GstPad *src_pad = gst_element_get_static_pad(src_element, "src"); - typefind = gst_element_factory_make ("typefind", "typefinder"); + typefind = gst_element_factory_make("typefind", "typefinder"); ms_retvm_if(typefind == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating element [typefind]"); __ms_bin_add_element(ms_streamer->topology_bin, typefind, TRUE); gst_element_sync_state_with_parent(typefind); - g_signal_connect (typefind, "have-type", G_CALLBACK (__ms_typefound_cb), ms_streamer); + g_signal_connect(typefind, "have-type", G_CALLBACK(__ms_typefound_cb), ms_streamer); __ms_link_two_elements(src_element, src_pad, typefind); diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 9671e5c..ec58cf2 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -762,7 +762,7 @@ static void _src_node_prepare(const GValue *item, gpointer user_data) GstElement *found_element = NULL; if (__ms_src_need_typefind(src_pad)) { - __ms_find_type(ms_streamer,src_element); + __ms_find_type(ms_streamer, src_element); MS_SAFE_UNREF(src_element); } else { /* Check the source element`s pad type */ @@ -795,7 +795,8 @@ static void _src_node_prepare(const GValue *item, gpointer user_data) MS_SAFE_UNREF(src_pad); } -static gboolean demux_find(gpointer key, gpointer value, gpointer user_data) { +static gboolean demux_find(gpointer key, gpointer value, gpointer user_data) +{ return g_strrstr((char *)key, "demux") != NULL; } -- 2.7.4 From 349bd52b407d00999a71e6e26b258aeaaa2e2456 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Tue, 8 Nov 2016 13:50:05 +0200 Subject: [PATCH 10/16] Added "display" property for overlay video sink Change-Id: I6ba4212c81ed0e32a3a4c68369f9f206547425ee Signed-off-by: Volodymyr Brynza (cherry picked from commit 754fdcc29b9e958dc221e68eaee2c9546ad635ab) --- CMakeLists.txt | 5 +- include/media_streamer.h | 9 ++ include/media_streamer_priv.h | 9 ++ packaging/capi-media-streamer.spec | 7 ++ src/media_streamer_node.c | 249 ++++++++++++++++++++++++++++++++++++- test/CMakeLists.txt | 2 +- test/media_streamer_test.c | 133 ++++++++++++++++++-- 7 files changed, 400 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c87ed30..01c0703 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,8 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(INC_DIR include) INCLUDE_DIRECTORIES(${INC_DIR}) -SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 cynara-client capi-system-info") -SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 cynara-client capi-system-info") +SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary") +SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary") INCLUDE(FindPkgConfig) pkg_check_modules(${fw_name} REQUIRED ${dependents}) @@ -100,4 +100,3 @@ ADD_CUSTOM_COMMAND( ) ENDIF(UNIX) - diff --git a/include/media_streamer.h b/include/media_streamer.h index fec5ae3..f011fe4 100644 --- a/include/media_streamer.h +++ b/include/media_streamer.h @@ -338,6 +338,15 @@ typedef enum { #define MEDIA_STREAMER_PARAM_DISPLAY_GEOMETRY_METHOD "display-geometry-method" /** + * @brief Definition for display parameter of sink node. + * @details It is a object to draw video frame on. + * Data type is Pointer. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_DISPLAY "display" + +/** * @brief Definition for visible parameter of sink node * @details Draws screen or blacks out. * Data type is boolean and default value is true(visible). diff --git a/include/media_streamer_priv.h b/include/media_streamer_priv.h index c559c1a..8ffe1c4 100755 --- a/include/media_streamer_priv.h +++ b/include/media_streamer_priv.h @@ -132,6 +132,15 @@ typedef struct { void *callbacks_structure; } media_streamer_node_s; +typedef struct _media_streamer_wl_info_s { + int parent_id; + int window_x; + int window_y; + int window_width; + int window_height; + void *evas_obj; +} media_streamer_wl_info_s; + /* Private functions definition */ /** diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 85986b0..716fcb8 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -22,6 +22,13 @@ BuildRequires: pkgconfig(iniparser) BuildRequires: pkgconfig(bundle) BuildRequires: pkgconfig(cynara-client) BuildRequires: pkgconfig(capi-system-info) +#BuildRequires: pkgconfig(libtbm) +BuildRequires: pkgconfig(tizen-extension-client) +BuildRequires: pkgconfig(elementary) +BuildRequires: pkgconfig(ecore) +BuildRequires: pkgconfig(evas) +BuildRequires: pkgconfig(ecore-wayland) +BuildRequires: pkgconfig(appcore-efl) %description A MediaStreamer library in Tizen Native API. diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index ec58cf2..874afa9 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -19,6 +19,11 @@ #include #include #include +#include +#include +#include +#include +#include #define SMACK_LABEL_LEN 255 #define DEFAULT_URI_SCHEME_LENGTH 10 @@ -45,6 +50,7 @@ param_s param_table[] = { {MEDIA_STREAMER_PARAM_ROTATE, "rotate"}, {MEDIA_STREAMER_PARAM_FLIP, "flip"}, {MEDIA_STREAMER_PARAM_DISPLAY_GEOMETRY_METHOD, "display-geometry-method"}, + {MEDIA_STREAMER_PARAM_DISPLAY, "display"}, {MEDIA_STREAMER_PARAM_VISIBLE, "visible"}, {MEDIA_STREAMER_PARAM_HOST, "host"}, {MEDIA_STREAMER_PARAM_SEGMENT_LOCATION, "location"}, @@ -762,7 +768,7 @@ static void _src_node_prepare(const GValue *item, gpointer user_data) GstElement *found_element = NULL; if (__ms_src_need_typefind(src_pad)) { - __ms_find_type(ms_streamer, src_element); + __ms_find_type(ms_streamer,src_element); MS_SAFE_UNREF(src_element); } else { /* Check the source element`s pad type */ @@ -795,8 +801,7 @@ static void _src_node_prepare(const GValue *item, gpointer user_data) MS_SAFE_UNREF(src_pad); } -static gboolean demux_find(gpointer key, gpointer value, gpointer user_data) -{ +static gboolean demux_find(gpointer key, gpointer value, gpointer user_data) { return g_strrstr((char *)key, "demux") != NULL; } @@ -1108,6 +1113,242 @@ int __ms_node_get_param_value(media_streamer_node_s *node, param_s *param, char return ret; } +static void __global(void *data, struct wl_registry *registry, + uint32_t name, const char *interface, uint32_t version) +{ + struct tizen_surface **tz_surface = NULL; + + if (!data) { + LOGE("NULL data"); + return; + } + + tz_surface = (struct tizen_surface **)data; + + if (!interface) { + LOGW("NULL interface"); + return; + } + + if (strcmp(interface, "tizen_surface") == 0) { + LOGD("binding tizen surface for wayland"); + + *tz_surface = wl_registry_bind(registry, name, &tizen_surface_interface, version); + if (*tz_surface == NULL) + LOGE("failed to bind"); + + LOGD("done"); + } + + return; +} + +static void __global_remove(void *data, struct wl_registry *wl_registry, uint32_t name) +{ + LOGD("enter"); + return; +} + +static const struct wl_registry_listener _media_streamer_wl_registry_listener = { + __global, + __global_remove +}; + +void __parent_id_getter(void *data, struct tizen_resource *tizen_resource, uint32_t id) +{ + if (!data) { + LOGE("NULL data"); + return; + } + + *((unsigned int *)data) = id; + + LOGD("[CLIENT] got parent_id [%u] from server", id); + + return; +} + +static const struct tizen_resource_listener _media_streamer_tz_resource_listener = { + __parent_id_getter +}; + +int _media_streamer_get_wl_info(Evas_Object *obj, media_streamer_wl_info_s *wl_info) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + Ecore_Wl_Window *window = NULL; + struct wl_display *display = NULL; + struct wl_display *display_wrapper = NULL; + struct wl_surface *surface = NULL; + struct wl_registry *registry = NULL; + struct wl_event_queue *queue = NULL; + struct tizen_surface *tz_surface = NULL; + struct tizen_resource *tz_resource = NULL; + + if (!obj || !wl_info) { + LOGE("NULL parameter %p %p", obj, wl_info); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + window = elm_win_wl_window_get(obj); + if (!window) { + LOGE("failed to get wayland window"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto _DONE; + } + + surface = (struct wl_surface *)ecore_wl_window_surface_get(window); + if (!surface) { + LOGE("failed to get wayland surface"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto _DONE; + } + + display = (struct wl_display *)ecore_wl_display_get(); + if (!display) { + LOGE("failed to get wayland display"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto _DONE; + } + + display_wrapper = wl_proxy_create_wrapper(display); + if (!display_wrapper) { + LOGE("failed to create wl display wrapper"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto _DONE; + } + + queue = wl_display_create_queue(display); + if (!queue) { + LOGE("failed to create wl display queue"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto _DONE; + } + + wl_proxy_set_queue((struct wl_proxy *)display_wrapper, queue); + + registry = wl_display_get_registry(display_wrapper); + if (!registry) { + LOGE("failed to get wayland registry"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto _DONE; + } + + wl_registry_add_listener(registry, &_media_streamer_wl_registry_listener, &tz_surface); + + wl_display_dispatch_queue(display, queue); + wl_display_roundtrip_queue(display, queue); + + if (!tz_surface) { + LOGE("failed to get tizen surface"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto _DONE; + } + + /* Get parent_id which is unique in a entire systemw. */ + tz_resource = tizen_surface_get_tizen_resource(tz_surface, surface); + if (!tz_resource) { + LOGE("failed to get tizen resurce"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto _DONE; + } + + wl_info->parent_id = 0; + + tizen_resource_add_listener(tz_resource, &_media_streamer_tz_resource_listener, &wl_info->parent_id); + + wl_display_roundtrip_queue(display, queue); + + if (wl_info->parent_id > 0) { + int rotation = 0; + Ecore_Evas *ecore_evas = NULL; + ret = MEDIA_STREAMER_ERROR_NONE; + + wl_info->evas_obj = obj; + + evas_object_geometry_get(obj, &wl_info->window_x, &wl_info->window_y, + &wl_info->window_width, &wl_info->window_height); + + ecore_evas = ecore_evas_ecore_evas_get(evas_object_evas_get(obj)); + if (ecore_evas) { + rotation = ecore_evas_rotation_get(ecore_evas); + if (rotation == 90 || rotation == 270) { + int temp = wl_info->window_width; + + LOGD("swap width and height %d, %d", wl_info->window_width, wl_info->window_height); + + wl_info->window_width = wl_info->window_height; + wl_info->window_height = temp; + } + } else { + LOGW("failed to get ecore_evas.. skip rotation check"); + } + + LOGD("evas object : %p, rotation : %d, parent id : %u, window : %d,%d,%dx%d", + wl_info->evas_obj, rotation, wl_info->parent_id, + wl_info->window_x, wl_info->window_y, + wl_info->window_width, wl_info->window_height); + } else { + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + LOGE("failed to get parent id"); + } + +_DONE: + if (tz_surface) { + tizen_surface_destroy(tz_surface); + tz_surface = NULL; + } + + if (tz_resource) { + tizen_resource_destroy(tz_resource); + tz_resource = NULL; + } + + if (registry) { + wl_registry_destroy(registry); + registry = NULL; + } + + if (queue) { + wl_event_queue_destroy(queue); + queue = NULL; + } + + if (display_wrapper) { + wl_proxy_wrapper_destroy(display_wrapper); + display_wrapper = NULL; + } + + return ret; +} + +/** + * @brief Set display for video sink. + * + * @sinse_tizen 3.0 + */ +int __ms_node_set_display(media_streamer_node_s *ms_node, const char *param_value) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + Evas_Object *obj = NULL; + media_streamer_wl_info_s wl_info; + + obj = (Evas_Object *)param_value; + + /* get wayland parent id */ + if (_media_streamer_get_wl_info(obj, &wl_info) != MEDIA_STREAMER_ERROR_NONE) { + LOGE("failed to get wayland info"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + LOGD("wayland global surface id : %d", wl_info.parent_id); + + gst_video_overlay_set_wl_window_wl_surface_id(GST_VIDEO_OVERLAY(ms_node->gst_element), (guintptr)wl_info.parent_id); + gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(ms_node->gst_element), + wl_info.window_x, wl_info.window_y, wl_info.window_width, wl_info.window_height); + + return ret; +} + int __ms_node_set_param_value(media_streamer_node_s *ms_node, param_s *param, const char *param_value) { ms_retvm_if(!ms_node || !param || !param_value, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); @@ -1163,6 +1404,8 @@ int __ms_node_set_param_value(media_streamer_node_s *ms_node, param_s *param, co g_object_set(ms_node->gst_element, param->origin_name, (int)strtol(param_value, NULL, 10), NULL); else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_DISPLAY_GEOMETRY_METHOD)) g_object_set(ms_node->gst_element, param->origin_name, (int)strtol(param_value, NULL, 10), NULL); + else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_DISPLAY)) + ret = __ms_node_set_display(ms_node, param_value); else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_VISIBLE)) g_object_set(ms_node->gst_element, param->origin_name, !g_ascii_strcasecmp(param_value, "true"), NULL); else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_HOST)) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9cf8385..e6a8af0 100755 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,7 +6,7 @@ INCLUDE_DIRECTORIES(../include) link_directories(${CMAKE_SOURCE_DIR}/../) INCLUDE(FindPkgConfig) -pkg_check_modules(${fw_test} REQUIRED glib-2.0) +pkg_check_modules(${fw_test} REQUIRED glib-2.0 elementary evas ecore appcore-efl) FOREACH(flag ${${fw_test}_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") ENDFOREACH(flag) diff --git a/test/media_streamer_test.c b/test/media_streamer_test.c index 0f1b6d5..309a134 100644 --- a/test/media_streamer_test.c +++ b/test/media_streamer_test.c @@ -19,9 +19,17 @@ #include #include +#include +#include +#include #include +#ifdef PACKAGE +#undef PACKAGE +#endif +#define PACKAGE "media_streamer_test" + typedef enum { MENU_STATE_UNKNOWN = 0, MENU_STATE_MAIN_MENU, @@ -113,8 +121,6 @@ media_streamer_node_h g_nodes[MAX_NODES_COUNT] = { 0, }; int g_node_counter = 0; #define APPEND_NODE(x) {g_nodes[g_node_counter++] = x; } -GMainLoop *g_loop; - gchar *g_broadcast_address = NULL; int g_seek_pos = 0; int g_time = 0; @@ -140,6 +146,24 @@ media_format_h afmt_aenc = NULL; media_format_h tsfmt = NULL; media_format_h qtfmt = NULL; +static int app_create(void *data); +static int app_terminate(void *data); + +struct _appdata { + Evas_Object *win; + Evas_Object *eo; + Evas_Object *bg; + Evas_Object *rect; +}; +typedef struct _appdata appdata; + +struct appcore_ops ops = { + .create = app_create, + .terminate = app_terminate, +}; + +appdata ad; + static void streamer_error_cb(media_streamer_h streamer, media_streamer_error_e error, void *user_data) { g_print("Media Streamer posted error [%d] \n", error); @@ -417,6 +441,7 @@ static void _create_file_playing() media_streamer_node_h video_sink = NULL; media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY, &video_sink); media_streamer_node_add(current_media_streamer, video_sink); + media_streamer_node_set_param(video_sink, MEDIA_STREAMER_PARAM_DISPLAY, (void*)ad.win); APPEND_NODE(video_sink); /*********************** audiosink *********************************** */ @@ -444,6 +469,7 @@ static void _create_file_sub_playing() media_streamer_node_h video_sink = NULL; media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY, &video_sink); media_streamer_node_add(current_media_streamer, video_sink); + media_streamer_node_set_param(video_sink, MEDIA_STREAMER_PARAM_DISPLAY, (void*)ad.win); APPEND_NODE(video_sink); /*********************** audiosink *********************************** */ @@ -475,6 +501,7 @@ static void _create_http_playing() media_streamer_node_h video_sink = NULL; media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY, &video_sink); media_streamer_node_add(current_media_streamer, video_sink); + media_streamer_node_set_param(video_sink, MEDIA_STREAMER_PARAM_DISPLAY, (void*)ad.win); APPEND_NODE(video_sink); /*********************** audiosink *********************************** */ @@ -612,6 +639,7 @@ static void _create_rtp_client(media_streamer_node_h rtp_bin) media_streamer_node_h video_sink = NULL; media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY, &video_sink); media_streamer_node_add(current_media_streamer, video_sink); + media_streamer_node_set_param(video_sink, MEDIA_STREAMER_PARAM_DISPLAY, (void*)ad.win); APPEND_NODE(video_sink); /* ====================Linking Video Client=========================== */ @@ -660,6 +688,7 @@ static void _create_rtp_client_autoplug(media_streamer_node_h rtp_bin) media_streamer_node_h video_sink = NULL; media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY, &video_sink); media_streamer_node_add(current_media_streamer, video_sink); + media_streamer_node_set_param(video_sink, MEDIA_STREAMER_PARAM_DISPLAY, (void*)ad.win); APPEND_NODE(video_sink); g_print("== success client_autoplug video part \n"); @@ -775,6 +804,7 @@ static void _create_adaptive_playing() media_streamer_node_h video_sink = NULL; media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY, &video_sink); media_streamer_node_add(current_media_streamer, video_sink); + media_streamer_node_set_param(video_sink, MEDIA_STREAMER_PARAM_DISPLAY, (void*)ad.win); APPEND_NODE(video_sink); /*********************** audiosink *********************************** */ @@ -812,6 +842,7 @@ static void _create_adaptive_playing_manual() media_streamer_node_h video_sink = NULL; media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY, &video_sink); media_streamer_node_add(current_media_streamer, video_sink); + media_streamer_node_set_param(video_sink, MEDIA_STREAMER_PARAM_DISPLAY, (void*)ad.win); APPEND_NODE(video_sink); /*********************** audiosink *********************************** */ @@ -950,7 +981,7 @@ void reset_current_menu_state(void) void quit() { reset_current_menu_state(); - g_main_loop_quit(g_loop); + elm_exit(); } static void display_getting_ip_menu(void) @@ -1696,19 +1727,107 @@ gboolean input(GIOChannel *channel) return TRUE; } +static int app_create(void *data) +{ + appdata *app_data = data; + int w = 0; + int h = 0; + Evas_Object *win = NULL; + Evas_Object *eo = NULL; + Evas_Object *bg = NULL; + Evas_Object *rect = NULL; + + if (app_data == NULL) { + g_print("\t\nappdata is NULL\n"); + return 0; + } + + /* use gl backend */ + elm_config_accel_preference_set("opengl"); + + win = elm_win_add(NULL, PACKAGE, ELM_WIN_BASIC); + if (win) { + elm_win_title_set(win, PACKAGE); + elm_win_borderless_set(win, EINA_TRUE); + elm_win_screen_size_get(win, NULL, NULL, &w, &h); + g_print("\n\tscreen size %dx%d\n\n", w, h); + evas_object_resize(win, w, h); + elm_win_autodel_set(win, EINA_TRUE); + elm_win_alpha_set(win, EINA_TRUE); + } else { + g_print("\n\tfailed to get window\n\n"); + return 1; + } + + bg = elm_bg_add(win); + if (bg) { + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + } else { + g_print("\n\tfailed to get elm bg\n\n"); + return 1; + } + + rect = evas_object_rectangle_add(evas_object_evas_get(win)); + if (rect) { + evas_object_color_set(rect, 0, 0, 0, 0); + evas_object_render_op_set(rect, EVAS_RENDER_COPY); + } else { + g_print("\n\tfailed to get rectangle\n\n"); + return 1; + } + + elm_win_resize_object_add(win, rect); + evas_object_size_hint_weight_set(rect, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(rect); + + /* Create evas image object for EVAS surface */ + eo = evas_object_image_add(evas_object_evas_get(win)); + evas_object_image_size_set(eo, w, h); + evas_object_image_fill_set(eo, 0, 0, w, h); + evas_object_resize(eo, w, h); + evas_object_show(eo); + + elm_win_activate(win); + evas_object_show(win); + + app_data->win = win; + app_data->eo = eo; + + display_menu(); + + return 0; +} + +static int app_terminate(void *data) +{ + appdata *app_data = data; + + if (app_data == NULL) { + g_print("\n\tappdata is NULL\n"); + return 0; + } + + return 0; +} + int main(int argc, char **argv) { + int bret; + GIOChannel *stdin_channel; stdin_channel = g_io_channel_unix_new(0); g_io_channel_set_flags(stdin_channel, G_IO_FLAG_NONBLOCK, NULL); g_io_add_watch(stdin_channel, G_IO_IN, (GIOFunc) input, NULL); - display_menu(); + memset(&ad, 0x0, sizeof(appdata)); + ops.data = &ad; + + bret = appcore_efl_main(PACKAGE, &argc, &argv, &ops); - g_loop = g_main_loop_new(NULL, FALSE); - g_main_loop_run(g_loop); + g_print("\n\treturn appcore_efl : %d\n\n", bret); - g_main_loop_unref(g_loop); g_io_channel_unref(stdin_channel); return 0; } -- 2.7.4 From c8a7401634ce51481c80bd40176765a8f07ebc74 Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Thu, 24 Nov 2016 16:16:45 +0900 Subject: [PATCH 11/16] [ACR-844] Add Interrupt cb API Change-Id: I21ff9004aafbd53a8f3222d9f98411e8ca8967d6 --- include/media_streamer.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/include/media_streamer.h b/include/media_streamer.h index f011fe4..ca518ee 100644 --- a/include/media_streamer.h +++ b/include/media_streamer.h @@ -166,6 +166,16 @@ typedef enum { } media_streamer_custom_buffer_status_e; /** + * @brief Enumeration for media streamer's interruption type. + * + * @since_tizen 3.0 + */ +typedef enum { + MEDIA_STREAMER_INTERRUPTED_BY_RESOURCE_CONFLICT, /**< Interrupted by a resource conflict */ + MEDIA_STREAMER_INTERRUPTED_BY_SECURITY, /**< Interrupted by a security policy */ +} media_streamer_interrupted_code_e; + +/** * @brief Definition for "camera-id" parameter of source node. * @details Index number of camera to activate. * Data type is integer and default value is 0. @@ -472,6 +482,16 @@ typedef void (*media_streamer_sink_eos_cb)(media_streamer_node_h node, void *use typedef void (*media_streamer_position_changed_cb)(void *user_data); /** + * @brief Called when the media streamer is interrupted. + * @since_tizen 3.0 + * @param[in] error_code The interrupted error code + * @param[in] user_data The user data passed from the callback registration function + * @see media_streamer_set_interrupted_cb() + * @see media_streamer_unset_interrupted_cb() + */ +typedef void (*media_streamer_interrupted_cb)(media_streamer_interrupted_code_e code, void *user_data); + +/** * @brief Registers a error callback function to be invoked when an error occurs. * @details Following error codes can be delivered by error callback. * #MEDIA_STREAMER_ERROR_INVALID_OPERATION, @@ -544,6 +564,36 @@ int media_streamer_set_state_change_cb(media_streamer_h streamer, media_streamer int media_streamer_unset_state_change_cb(media_streamer_h streamer); /** + * @brief Registers a callback function to be invoked when the media streamer is interrupted. + * @since_tizen 3.0 + * @param[in] streamer Media streamer handle + * @param[in] callback The callback function to register + * @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_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @post media_streamer_interrupted_cb() will be invoked. + * @see media_streamer_unset_interrupted_cb() + * @see #media_streamer_interrupted_code_e + */ +int media_streamer_set_interrupted_cb(media_streamer_h streamer, media_streamer_interrupted_cb callback, void *user_data); + +/** + * @brief Unregisters the callback function. + * @since_tizen 3.0 + * @param[in] streamer Media streamer handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @see media_streamer_set_interrupted_cb() + */ +int media_streamer_unset_interrupted_cb(media_streamer_h streamer); + +/** * @brief Registers a callback function to be invoked when buffer underrun or overflow is occurred. * @details This function can be called only for MEDIA_STREAMER_NODE_SRC_TYPE_CUSTOM source type * @since_tizen 3.0 -- 2.7.4 From e80f13f7e477027275dc4671b987dbc08e390640 Mon Sep 17 00:00:00 2001 From: Oleksandr Popov Date: Mon, 5 Dec 2016 18:35:48 +0200 Subject: [PATCH 12/16] Added implementation of interruption by resource manager Signed-off-by: Oleksandr Popov Change-Id: I213f1aa51bf6e051baf0a435f268c2798124d558 (cherry picked from commit c252c62a3ea4e82a304a8b32c53d8ab9a1fd5afa) --- CMakeLists.txt | 4 +- include/media_streamer_gst.h | 4 +- include/media_streamer_node.h | 3 + include/media_streamer_node_resources.h | 36 +++ include/media_streamer_priv.h | 9 + include/media_streamer_resource.h | 84 +++++ include/media_streamer_util.h | 33 +- packaging/capi-media-streamer.spec | 2 + src/media_streamer.c | 35 ++ src/media_streamer_gst.c | 45 ++- src/media_streamer_node.c | 202 ++++++++++-- src/media_streamer_node_resources.c | 268 ++++++++++++++++ src/media_streamer_priv.c | 183 ++++++++++- src/media_streamer_resource.c | 550 ++++++++++++++++++++++++++++++++ src/media_streamer_util.c | 43 +++ test/media_streamer_test.c | 16 +- 16 files changed, 1453 insertions(+), 64 deletions(-) create mode 100644 include/media_streamer_node_resources.h create mode 100644 include/media_streamer_resource.h create mode 100644 src/media_streamer_node_resources.c create mode 100644 src/media_streamer_resource.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 01c0703..0c7e7c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,8 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(INC_DIR include) INCLUDE_DIRECTORIES(${INC_DIR}) -SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary") -SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary") +SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary murphy-resource murphy-glib") +SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary murphy-resource murphy-glib") INCLUDE(FindPkgConfig) pkg_check_modules(${fw_name} REQUIRED ${dependents}) diff --git a/include/media_streamer_gst.h b/include/media_streamer_gst.h index 37f2b2b..11b1da8 100644 --- a/include/media_streamer_gst.h +++ b/include/media_streamer_gst.h @@ -182,14 +182,14 @@ GstElement *__ms_combine_next_element(GstElement *previous_element, GstPad *prev * * @since_tizen 3.0 */ -void __ms_element_lock_state(const GValue *item, gpointer user_data); +gboolean __ms_element_lock_state(const GValue *item, GValue *ret, gpointer user_data); /** * @brief Unlocks gst_element being contained in GValue data. * * @since_tizen 3.0 */ -void __ms_element_unlock_state(const GValue *item, gpointer user_data); +gboolean __ms_element_unlock_state(const GValue *item, GValue *ret, gpointer user_data); /** * @brief Creates pipeline, bus and src/sink/topology bins. diff --git a/include/media_streamer_node.h b/include/media_streamer_node.h index eb89d8c..f79f9e5 100644 --- a/include/media_streamer_node.h +++ b/include/media_streamer_node.h @@ -128,3 +128,6 @@ int __ms_node_set_param_value(media_streamer_node_s *ms_node, param_s *param, co * @since_tizen 3.0 */ int __ms_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, media_format_h fmt); + +gboolean _ms_node_resouces_acquire_iter(const GValue *item, GValue *ret, gpointer user_data); +gboolean _ms_node_resouces_release_iter(const GValue *item, GValue *ret, gpointer user_data); diff --git a/include/media_streamer_node_resources.h b/include/media_streamer_node_resources.h new file mode 100644 index 0000000..2f4dd12 --- /dev/null +++ b/include/media_streamer_node_resources.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015-2016 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_STREAMER_NODE_RESOURCE_H__ +#define __MEDIA_STREAMER_NODE_RESOURCE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int __ms_node_resouces_init(media_streamer_node_s *node); +int __ms_node_resouces_deinit(media_streamer_node_s *node); +int _ms_node_resource_aquire(media_streamer_node_s *node); +int _ms_node_resource_release(media_streamer_node_s *node); + +#ifdef __cplusplus +} +#endif + +#endif /* __MEDIA_STREAMER_NODE_RESOURCE_H__ */ diff --git a/include/media_streamer_priv.h b/include/media_streamer_priv.h index 8ffe1c4..14a45f7 100755 --- a/include/media_streamer_priv.h +++ b/include/media_streamer_priv.h @@ -27,6 +27,7 @@ extern "C" { #include #include +#include struct media_streamer_node_s; @@ -110,6 +111,10 @@ typedef struct { media_streamer_callback_s error_cb; media_streamer_callback_s state_changed_cb; media_streamer_callback_s seek_done_cb; + media_streamer_callback_s interrupted_cb; + + gboolean is_interrupted; + media_streamer_resource_manager_s resource_manager; } media_streamer_s; /** @@ -130,6 +135,8 @@ typedef struct { GList *sig_list; void *callbacks_structure; + + media_streamer_resource_manager_s resource_manager; } media_streamer_node_s; typedef struct _media_streamer_wl_info_s { @@ -185,6 +192,8 @@ int __ms_create(media_streamer_s *ms_streamer); */ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e state); +int __ms_release_resources(media_streamer_s *ms_streamer); + #ifdef __cplusplus } diff --git a/include/media_streamer_resource.h b/include/media_streamer_resource.h new file mode 100644 index 0000000..27da5ca --- /dev/null +++ b/include/media_streamer_resource.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015-2016 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_STREAMER_RESOURCE_H__ +#define __MEDIA_STREAMER_RESOURCE_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MEDIA_STREAMER_RESOURCE_TIMEOUT 5 + +#define MEDIA_STREAMER_GET_RESOURCE_LOCK(rm) (&((media_streamer_resource_manager_s *)rm)->lock) +#define MEDIA_STREAMER_RESOURCE_LOCK(rm) (g_mutex_lock(MEDIA_STREAMER_GET_RESOURCE_LOCK(rm))) +#define MEDIA_STREAMER_RESOURCE_UNLOCK(rm) (g_mutex_unlock(MEDIA_STREAMER_GET_RESOURCE_LOCK(rm))) + +#define MEDIA_STREAMER_GET_RESOURCE_COND(rm) (&((media_streamer_resource_manager_s *)rm)->cond) +#define MEDIA_STREAMER_RESOURCE_WAIT(rm) g_cond_wait(MEDIA_STREAMER_GET_RESOURCE_COND(rm), MEDIA_STREAMER_GET_RESOURCE_LOCK(rm) +#define MEDIA_STREAMER_RESOURCE_WAIT_UNTIL(rm, end_time) \ + g_cond_wait_until(MEDIA_STREAMER_GET_RESOURCE_COND(rm), MEDIA_STREAMER_GET_RESOURCE_LOCK(rm), end_time) +#define MEDIA_STREAMER_RESOURCE_SIGNAL(rm) g_cond_signal(MEDIA_STREAMER_GET_RESOURCE_COND(rm)); + +typedef enum { + RESOURCE_TYPE_NONE, + RESOURCE_TYPE_VIDEO_DECODER, + RESOURCE_TYPE_CAMERA, + RESOURCE_TYPE_VIDEO_OVERLAY, +} media_streamer_resource_type_e; + +typedef enum { + RESOURCE_STATE_ERROR = -1, + RESOURCE_STATE_NONE, + RESOURCE_STATE_INITIALIZED, + RESOURCE_STATE_PREPARED, + RESOURCE_STATE_ACQUIRED, + RESOURCE_STATE_MAX, +} media_streamer_resource_state_e; + +typedef struct _media_streamer_resource_manager_s media_streamer_resource_manager_s; +typedef gboolean (*resource_relese_cb) (media_streamer_resource_manager_s *resource_manager, void *user_data); + +struct _media_streamer_resource_manager_s { + mrp_mainloop_t *mloop; + mrp_res_context_t *context; + mrp_res_resource_set_t *rset; + media_streamer_resource_state_e state; + bool is_connected; + void *user_data; + bool by_rm_cb; + GCond cond; + GMutex lock; + + /* Release cb */ + resource_relese_cb release_cb; +}; + +int _ms_resource_manager_init(media_streamer_resource_manager_s *resource_manager, resource_relese_cb release_cb, void *user_data); +int _ms_resource_manager_prepare(media_streamer_resource_manager_s *resource_manager, media_streamer_resource_type_e resource_type); +int _ms_resource_manager_acquire(media_streamer_resource_manager_s *resource_manager); +int _ms_resource_manager_release(media_streamer_resource_manager_s *resource_manager); +int _ms_resource_manager_unprepare(media_streamer_resource_manager_s *resource_manager); +int _ms_resource_manager_deinit(media_streamer_resource_manager_s *resource_manager); +int _ms_resource_manager_get_state(media_streamer_resource_manager_s *resource_manager, media_streamer_resource_state_e *state); + +#ifdef __cplusplus +} +#endif + +#endif /* __MEDIA_STREAMER_RESOURCE_H__ */ diff --git a/include/media_streamer_util.h b/include/media_streamer_util.h index b4b8625..2b44cdf 100644 --- a/include/media_streamer_util.h +++ b/include/media_streamer_util.h @@ -17,6 +17,8 @@ #ifndef __MEDIA_STREAMER_UTIL_H__ #define __MEDIA_STREAMER_UTIL_H__ +#include + #include #include #include @@ -45,33 +47,33 @@ extern "C" { #define ms_debug(fmt, arg...) \ do { \ - LOGD(FONT_COLOR_RESET""fmt"", ##arg); \ + LOGD(FONT_COLOR_RESET""fmt""FONT_COLOR_RESET, ##arg); \ } while (0) #define ms_info(fmt, arg...) \ do { \ - LOGI(FONT_COLOR_GREEN""fmt"", ##arg); \ + LOGI(FONT_COLOR_GREEN""fmt""FONT_COLOR_RESET, ##arg); \ } while (0) #define ms_error(fmt, arg...) \ do { \ - LOGE(FONT_COLOR_RED""fmt"", ##arg); \ + LOGE(FONT_COLOR_RED""fmt""FONT_COLOR_RESET, ##arg); \ } while (0) #define ms_debug_fenter() \ do { \ - LOGD(FONT_COLOR_YELLOW""); \ + LOGD(FONT_COLOR_YELLOW""FONT_COLOR_RESET); \ } while (0) #define ms_debug_fleave() \ do { \ - LOGD(FONT_COLOR_PURPLE""); \ + LOGD(FONT_COLOR_PURPLE""FONT_COLOR_RESET); \ } while (0) #define ms_retm_if(expr, fmt, arg...) \ do { \ if (expr) { \ - LOGE(FONT_COLOR_RED""fmt"", ##arg); \ + LOGE(FONT_COLOR_RED""fmt""FONT_COLOR_RESET, ##arg); \ return; \ } \ } while (0) @@ -79,7 +81,7 @@ extern "C" { #define ms_retvm_if(expr, val, fmt, arg...) \ do { \ if (expr) { \ - LOGE(FONT_COLOR_RED""fmt"", ##arg); \ + LOGE(FONT_COLOR_RED""fmt""FONT_COLOR_RESET, ##arg); \ return(val); \ } \ } while (0) @@ -109,8 +111,8 @@ typedef struct __media_streamer_ini { gboolean generate_dot; gboolean use_decodebin; gchar **exclude_elem_names; + gchar **resource_required_elem_names; gchar **gst_args; - } media_streamer_ini_t; /** @@ -215,14 +217,6 @@ typedef struct { #define MEDIA_STREAMER_DEFAULT_DOT_DIR "/tmp" -#define MS_BIN_FOREACH_ELEMENTS(bin, fn, streamer) \ - do { \ - GstIterator *iter = gst_bin_iterate_elements(GST_BIN(bin)); \ - if (gst_iterator_foreach(iter, fn, streamer) != GST_ITERATOR_DONE) \ - ms_error("Error while iterating elements in bin [%s]!", GST_ELEMENT_NAME(bin)); \ - gst_iterator_free(iter); \ - } while (0) - #define MS_BIN_UNPREPARE(bin) \ if (!__ms_bin_remove_elements(ms_streamer, bin)) {\ ms_debug("Got a few errors during unprepare [%s] bin.", GST_ELEMENT_NAME(bin));\ @@ -340,6 +334,13 @@ void __ms_param_value_destroy(gpointer data); */ int __ms_node_uri_path_check(const char *file_uri); +/** + * @brief Iterates func over all elements contained within a bin. + * + * @since_tizen 3.0 + */ +int __ms_bin_foreach_elements(GstBin *bin, GstIteratorFoldFunction func, void *user_data); + #ifdef __cplusplus } #endif diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 716fcb8..7443f3b 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -29,6 +29,8 @@ BuildRequires: pkgconfig(ecore) BuildRequires: pkgconfig(evas) BuildRequires: pkgconfig(ecore-wayland) BuildRequires: pkgconfig(appcore-efl) +BuildRequires: pkgconfig(murphy-resource) +BuildRequires: pkgconfig(murphy-glib) %description A MediaStreamer library in Tizen Native API. diff --git a/src/media_streamer.c b/src/media_streamer.c index 8bd592f..73ba7dc 100644 --- a/src/media_streamer.c +++ b/src/media_streamer.c @@ -251,6 +251,8 @@ int media_streamer_create(media_streamer_h *streamer) /* create streamer lock */ g_mutex_init(&ms_streamer->mutex_lock); + g_mutex_lock(&ms_streamer->mutex_lock); + ret = __ms_create(ms_streamer); if (ret != MEDIA_STREAMER_ERROR_NONE) { ms_error("Error creating Media Streamer"); @@ -263,6 +265,8 @@ int media_streamer_create(media_streamer_h *streamer) ret = __ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_IDLE); *streamer = ms_streamer; + g_mutex_unlock(&ms_streamer->mutex_lock); + ms_info("Media Streamer created successfully"); return ret; } @@ -712,3 +716,34 @@ int media_streamer_node_get_param(media_streamer_node_h node, const char *param_ return ret; } + +int media_streamer_set_interrupted_cb(media_streamer_h streamer, media_streamer_interrupted_cb callback, void *user_data) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(callback == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Callback is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + ms_streamer->interrupted_cb.callback = callback; + ms_streamer->interrupted_cb.user_data = user_data; + + g_mutex_unlock(&ms_streamer->mutex_lock); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_unset_interrupted_cb(media_streamer_h streamer) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + ms_streamer->interrupted_cb.callback = NULL; + ms_streamer->interrupted_cb.user_data = NULL; + + g_mutex_unlock(&ms_streamer->mutex_lock); + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index 39a1a14..f3961d4 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -465,6 +465,28 @@ static gint __decodebin_autoplug_select_cb(GstElement * bin, GstPad * pad, GstCa } + if (ms_streamer->ini.resource_required_elem_names) { + /* Try to acuire resources before adding element */ + int index = 0; + for ( ; ms_streamer->ini.resource_required_elem_names[index]; ++index) { + if (g_strrstr(factory_name, ms_streamer->ini.resource_required_elem_names[index])) { + ms_debug("Decodebin: trying to acquire resource for [%s] element", factory_name); + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_prepare(&ms_streamer->resource_manager, RESOURCE_TYPE_VIDEO_DECODER)) { + ms_error("Failed to prepare resources for [%s] element", factory_name); + return GST_AUTOPLUG_SELECT_SKIP; + } + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_acquire(&ms_streamer->resource_manager)) { + ms_error("Failed to acquire resources for [%s] element", factory_name); + return GST_AUTOPLUG_SELECT_SKIP; + } + } + } + } + return result; } @@ -979,6 +1001,7 @@ GstElement *__ms_node_element_create(node_plug_s *plug_info, media_streamer_node GstElement *gst_element = NULL; const gchar *src_type, *sink_type; + MS_GET_CAPS_TYPE(plug_info->src_caps, src_type); MS_GET_CAPS_TYPE(plug_info->sink_caps, sink_type); @@ -1474,15 +1497,16 @@ static GstPadProbeReturn __ms_element_event_probe(GstPad * pad, GstPadProbeInfo return GST_PAD_PROBE_PASS; } -void __ms_element_lock_state(const GValue *item, gpointer user_data) +gboolean __ms_element_lock_state(const GValue *item, GValue *ret, gpointer user_data) { GstElement *sink_element = GST_ELEMENT(g_value_get_object(item)); - ms_retm_if(!sink_element, "Handle is NULL"); + g_value_set_boolean(ret, FALSE); + ms_retvm_if(!sink_element, FALSE, "Handle is NULL"); GstPad *sink_pad = gst_element_get_static_pad(sink_element, "sink"); if (!sink_pad) { ms_info("Failed to get static pad of element [%s]", GST_ELEMENT_NAME(sink_element)); - return; + return FALSE; } if (!gst_pad_is_blocked(sink_pad)) { int probe_id = gst_pad_add_probe(sink_pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, __ms_element_event_probe, NULL, NULL); @@ -1492,19 +1516,24 @@ void __ms_element_lock_state(const GValue *item, gpointer user_data) ms_info("Pad [%s] of element [%s] is already locked", GST_PAD_NAME(sink_pad), GST_ELEMENT_NAME(sink_element)); } MS_SAFE_UNREF(sink_pad); + + g_value_set_boolean(ret, TRUE); + + return TRUE; } -void __ms_element_unlock_state(const GValue *item, gpointer user_data) +gboolean __ms_element_unlock_state(const GValue *item, GValue *ret, gpointer user_data) { GstElement *sink_element = GST_ELEMENT(g_value_get_object(item)); - ms_retm_if(!sink_element, "Handle is NULL"); + g_value_set_boolean(ret, FALSE); + ms_retvm_if(!sink_element, FALSE, "Handle is NULL"); GValue *val = (GValue *) g_object_get_data(G_OBJECT(sink_element), "pad_sink"); if (val) { GstPad *sink_pad = gst_element_get_static_pad(sink_element, "sink"); if (!sink_pad) { ms_info("Failed to get static pad of element [%s]", GST_ELEMENT_NAME(sink_element)); - return; + return FALSE; } if (gst_pad_is_blocked(sink_pad)) { ms_info("Removing locking probe [%d] ID on [%s] pad of [%s] element", g_value_get_int(val), GST_PAD_NAME(sink_pad), GST_ELEMENT_NAME(sink_element)); @@ -1514,6 +1543,10 @@ void __ms_element_unlock_state(const GValue *item, gpointer user_data) } MS_SAFE_UNREF(sink_pad); } + + g_value_set_boolean(ret, TRUE); + + return TRUE; } static gboolean __ms_bus_cb(GstBus *bus, GstMessage *message, gpointer userdata) diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 874afa9..a87724f 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -240,6 +241,7 @@ int __ms_node_create(media_streamer_node_s *node, media_format_h in_fmt, media_f GstCaps *src_caps = out_fmt ? __ms_create_caps_from_fmt(out_fmt) : NULL; node_plug_s plug_info = {&(nodes_info[node->type]), src_caps, sink_caps, NULL}; + ms_info("Creating node with info: klass_name[%s]; default[%s]", plug_info.info->klass_name, plug_info.info->default_name); @@ -247,13 +249,19 @@ int __ms_node_create(media_streamer_node_s *node, media_format_h in_fmt, media_f if (node->gst_element) node->name = gst_element_get_name(node->gst_element); else - ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; if (src_caps) - gst_caps_unref(src_caps); + gst_caps_unref(src_caps); if (sink_caps) - gst_caps_unref(sink_caps); + gst_caps_unref(sink_caps); + + ret = __ms_node_resouces_init(node); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to init resources for node [%s]", node->name); + return ret; + } return ret; } @@ -310,7 +318,7 @@ static int __ms_node_check_priveleges(media_streamer_node_s *node) privilege = "http://tizen.org/privilege/camera"; break; default: - ms_info("For current Src Node [%s] subtype [%d] privileges are not needed", node->name, node->subtype); + ms_info(" [%s] subtype [%d] privileges are not needed", node->name, node->subtype); break; } } @@ -446,7 +454,7 @@ static int __ms_node_check_feature(media_streamer_node_s *node) ret = MEDIA_STREAMER_ERROR_NOT_SUPPORTED; break; default: - ms_info("For current Src Node [%s] subtype [%d] privileges are not needed", node->name, node->subtype); + ms_info("For current Src Node subtype [%d] privileges are not needed", node->subtype); break; } } @@ -483,7 +491,7 @@ static int __ms_node_check_feature(media_streamer_node_s *node) ret = MEDIA_STREAMER_ERROR_NOT_SUPPORTED; break; default: - ms_info("For current Sink Node [%s] subtype [%d] privileges are not needed", node->name, node->subtype); + ms_info("For current Sink Node subtype [%d] privileges are not needed", node->subtype); break; } } @@ -560,11 +568,15 @@ int __ms_src_node_create(media_streamer_node_s *node) MS_SAFE_FREE(plugin_name); - if (ret == MEDIA_STREAMER_ERROR_NONE) { - if (node->gst_element == NULL) - ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; - else - node->name = gst_element_get_name(node->gst_element); + if (node->gst_element == NULL) + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + else + node->name = gst_element_get_name(node->gst_element); + + ret = __ms_node_resouces_init(node); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to init resources for node [%s]", node->name); + return ret; } return ret; @@ -670,10 +682,16 @@ int __ms_sink_node_create(media_streamer_node_s *node) MS_SAFE_FREE(plugin_name); if (node->gst_element == NULL) - ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; else node->name = gst_element_get_name(node->gst_element); + ret = __ms_node_resouces_init(node); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to init resources for node [%s]", node->name); + return ret; + } + return ret; } @@ -684,6 +702,10 @@ void __ms_node_destroy(media_streamer_node_s *node) /* Disconnects and clean all node signals */ g_list_free_full(node->sig_list, __ms_signal_destroy); + /* Deinitialize resource manager */ + if (MEDIA_STREAMER_ERROR_NONE != __ms_node_resouces_deinit(node)) + ms_error("Failed to deinitialize resource manager"); + MS_SAFE_UNREF(node->gst_element); MS_SAFE_FREE(node->name); MS_SAFE_FREE(node->callbacks_structure); @@ -751,24 +773,29 @@ node_info_s * __ms_node_get_klass_by_its_type(media_streamer_node_type_e element return &nodes_info[it_klass]; } -static void _src_node_prepare(const GValue *item, gpointer user_data) +static gboolean _src_node_prepare(const GValue *item, GValue *ret, gpointer user_data) { media_streamer_s *ms_streamer = (media_streamer_s *) user_data; GstElement *src_element = GST_ELEMENT(g_value_get_object(item)); g_object_ref(src_element); + g_value_set_boolean(ret, FALSE); media_streamer_node_s *found_node = (media_streamer_node_s *) g_hash_table_lookup(ms_streamer->nodes_table, GST_ELEMENT_NAME(src_element)); - if (!found_node) - return; + if (!found_node) { + /* If we fail to found corresonding node inside streamer + then apprently this element doesn't require resources. */ + ms_debug("Failed to found corresonding node [%s] inside streamer", GST_ELEMENT_NAME(src_element)); + g_value_set_boolean(ret, TRUE); + return TRUE; + } - ms_retm_if(!ms_streamer || !src_element, "Handle is NULL"); ms_debug("Autoplug: found src element [%s]", GST_ELEMENT_NAME(src_element)); GstPad *src_pad = gst_element_get_static_pad(src_element, "src"); GstElement *found_element = NULL; if (__ms_src_need_typefind(src_pad)) { - __ms_find_type(ms_streamer,src_element); + __ms_find_type(ms_streamer, src_element); MS_SAFE_UNREF(src_element); } else { /* Check the source element`s pad type */ @@ -777,7 +804,8 @@ static void _src_node_prepare(const GValue *item, gpointer user_data) if (gst_pad_is_linked(src_pad)) { MS_SAFE_UNREF(src_pad); MS_SAFE_UNREF(src_element); - return; + g_value_set_boolean(ret, TRUE); + return TRUE; } /* It is media streamer Server part */ if (MS_ELEMENT_IS_VIDEO(new_pad_type) || MS_ELEMENT_IS_IMAGE(new_pad_type)) { @@ -799,9 +827,19 @@ static void _src_node_prepare(const GValue *item, gpointer user_data) MS_SAFE_UNREF(found_element); } MS_SAFE_UNREF(src_pad); + + g_value_set_boolean(ret, TRUE); + + return TRUE; } -static gboolean demux_find(gpointer key, gpointer value, gpointer user_data) { +static gboolean _sink_node_prepare(const GValue *item, GValue *ret, gpointer user_data) +{ + return __ms_element_lock_state(item, ret, user_data); +} + +static gboolean demux_find(gpointer key, gpointer value, gpointer user_data) +{ return g_strrstr((char *)key, "demux") != NULL; } @@ -816,7 +854,9 @@ int __ms_pipeline_prepare(media_streamer_s *ms_streamer) if (rtp_node) { ret = __ms_rtp_element_prepare(rtp_node) ? MEDIA_STREAMER_ERROR_NONE : MEDIA_STREAMER_ERROR_INVALID_PARAMETER; } else if (demux) { - ret = __ms_demux_element_prepare(ms_streamer, demux) ? MEDIA_STREAMER_ERROR_NONE : MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + ret = __ms_demux_element_prepare(ms_streamer, demux); + if (MEDIA_STREAMER_ERROR_NONE != ret) + ms_error("Failed to prepare demux element"); } else { GstBin *nodes_bin = GST_BIN(ms_streamer->src_bin); if (nodes_bin->numchildren == 0) { @@ -831,21 +871,36 @@ int __ms_pipeline_prepare(media_streamer_s *ms_streamer) } if (adaptive_src) { - if (GST_BIN(ms_streamer->topology_bin)->numchildren == 0) { + if (GST_BIN(ms_streamer->topology_bin)->numchildren == 0) ret = __ms_adaptive_element_prepare(adaptive_src, true); - } else { + else ret = __ms_adaptive_element_prepare(adaptive_src, false); - } } - MS_BIN_FOREACH_ELEMENTS(ms_streamer->sink_bin, __ms_element_lock_state, ms_streamer); - MS_BIN_FOREACH_ELEMENTS(ms_streamer->src_bin, _src_node_prepare, ms_streamer); + if (ret != MEDIA_STREAMER_ERROR_NONE) + goto prepare_fail; + + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->sink_bin), _sink_node_prepare, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to prepare nodes within sink bin"); + goto prepare_fail; + } + + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->src_bin), _src_node_prepare, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to prepare nodes within src bin"); + goto prepare_fail; + } ret = __ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_READY); if (ret != MEDIA_STREAMER_ERROR_NONE) - __ms_pipeline_unprepare(ms_streamer); + goto prepare_fail; return ret; + +prepare_fail: + __ms_pipeline_unprepare(ms_streamer); + return ret; } static gboolean __ms_bin_remove_elements(media_streamer_s *ms_streamer, GstElement *bin) @@ -881,6 +936,7 @@ static gboolean __ms_bin_remove_elements(media_streamer_s *ms_streamer, GstEleme it_res = gst_iterator_next(bin_iterator, &element); } } + g_value_unset(&element); gst_iterator_free(bin_iterator); @@ -898,11 +954,37 @@ int __ms_pipeline_unprepare(media_streamer_s *ms_streamer) ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); int ret = MEDIA_STREAMER_ERROR_NONE; - __ms_element_set_state(ms_streamer->pipeline, GST_STATE_NULL); - ms_streamer->state = MEDIA_STREAMER_STATE_IDLE; - ms_streamer->pend_state = ms_streamer->state; + ret = __ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_IDLE); + if (ret != MEDIA_STREAMER_ERROR_NONE) + ms_error("Failed to unprepare pipeline"); + + if (!ms_streamer->is_interrupted) { + media_streamer_resource_state_e res_state = RESOURCE_STATE_ERROR; + ret = _ms_resource_manager_get_state(&ms_streamer->resource_manager, + &res_state); + if (ret != MEDIA_STREAMER_ERROR_NONE) + ms_error("Failed to get state of resource manager"); + + if (RESOURCE_STATE_ACQUIRED == res_state) { + ret = _ms_resource_manager_release(&ms_streamer->resource_manager); + if (ret != MEDIA_STREAMER_ERROR_NONE) + ms_error("Failed to release resources"); + } - MS_BIN_FOREACH_ELEMENTS(ms_streamer->sink_bin, __ms_element_unlock_state, ms_streamer); + ret = _ms_resource_manager_get_state(&ms_streamer->resource_manager, + &res_state); + if (ret != MEDIA_STREAMER_ERROR_NONE) + ms_error("Failed to get state of resource manager"); + + if (RESOURCE_STATE_PREPARED == res_state) { + ret = _ms_resource_manager_unprepare(&ms_streamer->resource_manager); + if (ret != MEDIA_STREAMER_ERROR_NONE) + ms_error("Failed to unprepare resources"); + } + + /* Unprepare resources in case of failure */ + __ms_release_resources(ms_streamer); + } /* Disconnects and clean all autoplug signals */ g_list_free_full(ms_streamer->autoplug_sig_list, __ms_signal_destroy); @@ -1456,3 +1538,63 @@ int __ms_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, return ret; } + +gboolean _ms_node_resouces_acquire_iter(const GValue *item, GValue *ret, gpointer user_data) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) user_data; + media_streamer_node_s *node = NULL; + GstElement *element = NULL; + g_value_set_boolean(ret, FALSE); + + element = GST_ELEMENT(g_value_get_object(item)); + g_object_ref(element); + + node = (media_streamer_node_s *) g_hash_table_lookup(ms_streamer->nodes_table, + GST_ELEMENT_NAME(element)); + if (!node) { + /* If we fail to found corresonding node inside streamer + then apprently this element doesn't require resources */ + ms_info("Failed to found corresonding node [%s] inside streamer", GST_ELEMENT_NAME(element)); + g_value_set_boolean(ret, TRUE); + return TRUE; + } + + if (MEDIA_STREAMER_ERROR_NONE != _ms_node_resource_aquire(node)) { + ms_error("Failed to acquire resource for node [%s]", node->name); + return FALSE; + } + + g_value_set_boolean(ret, TRUE); + + return TRUE; +} + +gboolean _ms_node_resouces_release_iter(const GValue *item, GValue *ret, gpointer user_data) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) user_data; + media_streamer_node_s *node = NULL; + GstElement *element = NULL; + g_value_set_boolean(ret, FALSE); + + element = GST_ELEMENT(g_value_get_object(item)); + g_object_ref(element); + + node = (media_streamer_node_s *) g_hash_table_lookup(ms_streamer->nodes_table, + GST_ELEMENT_NAME(element)); + if (!node) { + /* If we fail to found corresonding node inside streamer + then apprently this element doesn't require resources. */ + ms_debug("Failed to found corresonding node [%s] inside streamer", GST_ELEMENT_NAME(element)); + g_value_set_boolean(ret, TRUE); + return TRUE; + } + + if (MEDIA_STREAMER_ERROR_NONE != _ms_node_resource_release(node)) { + ms_error("Failed to release resource for node [%s]", node->name); + return FALSE; + } + + g_value_set_boolean(ret, TRUE); + + return TRUE; +} diff --git a/src/media_streamer_node_resources.c b/src/media_streamer_node_resources.c new file mode 100644 index 0000000..5dabe15 --- /dev/null +++ b/src/media_streamer_node_resources.c @@ -0,0 +1,268 @@ +/* + * 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 + +#include +#include +#include +#include +#include + +static gboolean __ms_resource_relese_cb( + media_streamer_resource_manager_s *resource_manager, + void *user_data) +{ + ms_retvm_if(user_data == NULL, FALSE, "user_data is NULL"); + + media_streamer_node_s *node = (media_streamer_node_s *) user_data; + media_streamer_s *streamer = (media_streamer_s *) node->parent_streamer; + ms_info("Received resource_release_cb from node [%s]", node->name); + + /* Here we perform action to release resources relases that + were previoursly acquired. Basically what we need to do is + to unprepare media streamer. Whithout calling release function + on every acquired resource. */ + g_mutex_lock(&streamer->mutex_lock); + streamer->is_interrupted = TRUE; + if (MEDIA_STREAMER_ERROR_NONE != + __ms_pipeline_unprepare(streamer)) { + ms_error("Failed to unprepare streamer"); + streamer->is_interrupted = FALSE; + g_mutex_unlock(&streamer->mutex_lock); + return FALSE; + } + streamer->is_interrupted = FALSE; + + /* Call interrupted_cb with appropriate code */ + media_streamer_interrupted_cb interrupted_cb = + (media_streamer_interrupted_cb) streamer->interrupted_cb.callback; + if (interrupted_cb) { + interrupted_cb(MEDIA_STREAMER_INTERRUPTED_BY_RESOURCE_CONFLICT, + streamer->interrupted_cb.user_data); + } else { + ms_info("Interuption will not be handled because interrupted_cb is NULL"); + } + g_mutex_unlock(&streamer->mutex_lock); + + return TRUE; +} + +static void __ms_node_get_resources_needed(media_streamer_node_s *node, + media_streamer_resource_type_e *resource) { + media_streamer_node_type_e type = node->type; + int subtype = node->subtype; + + ms_debug("Checking resources for node type %d, subtype %d", type, subtype); + + /* Check for node types */ + switch (type) { + case MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER: + break; + case MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER: + *resource = RESOURCE_TYPE_VIDEO_DECODER; + break; + case MEDIA_STREAMER_NODE_TYPE_SRC: + if (MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA == subtype) + *resource = RESOURCE_TYPE_CAMERA; + break; + case MEDIA_STREAMER_NODE_TYPE_SINK: + if (MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY == subtype) + *resource = RESOURCE_TYPE_VIDEO_OVERLAY; + break; + default: + break; + } +} + +int __ms_node_resouces_init(media_streamer_node_s *node) +{ + media_streamer_resource_type_e resource = RESOURCE_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Check if node require resource manager */ + __ms_node_get_resources_needed(node, &resource); + if (RESOURCE_TYPE_NONE == resource) { + ms_info("No resource is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + /* Initialize resource manager */ + ret = _ms_resource_manager_init(&node->resource_manager, + __ms_resource_relese_cb, node); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("Failed to initialize resource manager for Node"); + return ret; + } + + return ret; +} + +int __ms_node_resouces_deinit(media_streamer_node_s *node) +{ + media_streamer_resource_type_e resource = RESOURCE_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Check if node require resource manager */ + __ms_node_get_resources_needed(node, &resource); + if (RESOURCE_TYPE_NONE == resource) { + ms_info("No resource is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + /* Deinitialize resource manager */ + ret = _ms_resource_manager_deinit(&node->resource_manager); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("Failed to deinitialize resource manager for Src Node"); + return ret; + } + + return ret; +} + +int __ms_node_resouces_prepare(media_streamer_node_s *node, media_streamer_resource_type_e resource) +{ + media_streamer_resource_state_e resource_state = RESOURCE_STATE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + + ret = _ms_resource_manager_get_state(&node->resource_manager, &resource_state); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("Failed to get state from resource menager"); + return ret; + } else { + if (RESOURCE_STATE_NONE == resource_state || + RESOURCE_STATE_ERROR == resource_state) { + ms_error("Wrong resource manager state %d", resource_state); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else if (RESOURCE_STATE_INITIALIZED == resource_state) { + /* For every node we should call resource manager function to resource */ + ret = _ms_resource_manager_prepare(&node->resource_manager, resource); + } else { + ms_info("Resource state is %d. No need to prepare", resource_state); + return MEDIA_STREAMER_ERROR_NONE; + } + } + + return ret; +} + +int __ms_node_resouces_unprepare(media_streamer_node_s *node, media_streamer_resource_type_e resource) +{ + media_streamer_resource_state_e resource_state = RESOURCE_STATE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + + ret = _ms_resource_manager_get_state(&node->resource_manager, &resource_state); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("Failed to get state from resource menager"); + return ret; + } else { + if (RESOURCE_STATE_PREPARED == resource_state) { + /* For every node we should call resource manager function to resource */ + ret = _ms_resource_manager_unprepare(&node->resource_manager); + } else { + ms_error("Wrong resource manager state %d", resource_state); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } + + return ret; +} + +int _ms_node_resource_aquire(media_streamer_node_s *node) +{ + media_streamer_resource_state_e resource_state = RESOURCE_STATE_NONE; + media_streamer_resource_type_e resource = RESOURCE_TYPE_NONE; + + /* Check if node require resource manager */ + __ms_node_get_resources_needed(node, &resource); + if (RESOURCE_TYPE_NONE == resource) { + ms_info("No resource is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (MEDIA_STREAMER_ERROR_NONE != __ms_node_resouces_prepare(node, resource)) { + ms_error("Failed to prepare resources for Node [%p]", node); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_get_state(&node->resource_manager, &resource_state)) { + ms_error("Failed to get state from resource menager"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + ms_debug("Resource manager state %d", resource_state); + } + + ms_debug("Acquire resource for node [%s]", node->name); + + if (RESOURCE_STATE_PREPARED != resource_state) { + ms_debug("Resources were not prepared %d. Skipping...", resource_state); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_acquire(&node->resource_manager)) { + ms_error("Failed to acquire resources for node [%s]", node->name); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + return MEDIA_STREAMER_ERROR_NONE; +} + +int _ms_node_resource_release(media_streamer_node_s *node) +{ + media_streamer_resource_state_e resource_state = RESOURCE_STATE_NONE; + media_streamer_resource_type_e resource = RESOURCE_TYPE_NONE; + + /* Check if node require resource manager */ + __ms_node_get_resources_needed(node, &resource); + if (RESOURCE_TYPE_NONE == resource) { + ms_info("No resource is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_get_state(&node->resource_manager, &resource_state)) { + ms_error("Failed to get state from resource menager"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + ms_debug("Resource manager state %d", resource_state); + } + + ms_debug("Release resources for node [%s]", node->name); + + if (RESOURCE_STATE_ACQUIRED != resource_state) { + ms_debug("Resources were not acquired %d. Skipping...", resource_state); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_release(&node->resource_manager)) { + ms_error("Failed to release resources for node [%s]", node->name); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if (MEDIA_STREAMER_ERROR_NONE != __ms_node_resouces_unprepare(node, resource)) { + ms_error("Failed to unprepare resources for Node [%p]", node); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_priv.c b/src/media_streamer_priv.c index 47dd4bb..3fe8485 100644 --- a/src/media_streamer_priv.c +++ b/src/media_streamer_priv.c @@ -18,9 +18,13 @@ #include "media_streamer_util.h" #include "media_streamer_node.h" #include "media_streamer_gst.h" +#include "media_streamer_resource.h" #define GST_TIME_TO_MSEC(t) (t == GST_CLOCK_TIME_NONE ? t : (int)(((GstClockTime)(t)) / GST_MSECOND)) +int __ms_change_resources_state(media_streamer_s *ms_streamer, media_streamer_state_e state); +static gboolean media_streamer_resource_relese_cb(media_streamer_resource_manager_s *resource_manager, void *user_data); + int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e state) { int ret = MEDIA_STREAMER_ERROR_NONE; @@ -28,6 +32,14 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_retvm_if(ms_streamer->state == state, MEDIA_STREAMER_ERROR_NONE, "Media streamer already in this state"); + if (!ms_streamer->is_interrupted) { + ret = __ms_change_resources_state(ms_streamer, state); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to change resources state for streamer %p", ms_streamer); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } + switch (state) { case MEDIA_STREAMER_STATE_NONE: /* @@ -43,9 +55,10 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat * Unlink all gst_elements, set pipeline into state NULL */ ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_NULL); - MS_BIN_FOREACH_ELEMENTS(ms_streamer->sink_bin, __ms_element_unlock_state, ms_streamer); - ms_streamer->pend_state = MEDIA_STREAMER_STATE_NONE; + __ms_bin_foreach_elements(GST_BIN(ms_streamer->sink_bin), __ms_element_unlock_state, ms_streamer); + ms_streamer->pend_state = MEDIA_STREAMER_STATE_IDLE; ms_streamer->state = state; + break; case MEDIA_STREAMER_STATE_READY: ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PAUSED); @@ -53,7 +66,7 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat break; case MEDIA_STREAMER_STATE_PLAYING: ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PLAYING); - MS_BIN_FOREACH_ELEMENTS(ms_streamer->sink_bin, __ms_element_unlock_state, ms_streamer); + __ms_bin_foreach_elements(GST_BIN(ms_streamer->sink_bin), __ms_element_unlock_state, ms_streamer); ms_streamer->pend_state = MEDIA_STREAMER_STATE_PLAYING; break; case MEDIA_STREAMER_STATE_PAUSED: @@ -77,6 +90,14 @@ int __ms_create(media_streamer_s *ms_streamer) ms_streamer->nodes_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, __ms_node_remove_from_table); ms_retvm_if(ms_streamer->nodes_table == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating hash table"); + if (MEDIA_STREAMER_ERROR_NONE != _ms_resource_manager_init( + &ms_streamer->resource_manager, + media_streamer_resource_relese_cb, + ms_streamer)) { + ms_error("Failed to init resource manager for media streamer"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + return __ms_pipeline_create(ms_streamer); } @@ -155,9 +176,165 @@ int __ms_streamer_destroy(media_streamer_s *ms_streamer) if (ms_streamer->ini.exclude_elem_names) g_strfreev(ms_streamer->ini.exclude_elem_names); + /* Clean up resource required elements list */ + if (ms_streamer->ini.resource_required_elem_names) + g_strfreev(ms_streamer->ini.resource_required_elem_names); + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_deinit(&ms_streamer->resource_manager)) { + ms_error("Failed to deinit resource manager for media streamer"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + g_mutex_unlock(&ms_streamer->mutex_lock); g_mutex_clear(&ms_streamer->mutex_lock); MS_SAFE_FREE(ms_streamer); return ret; } + +int __ms_aquire_resources(media_streamer_s *ms_streamer) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Acquire resources for src bin */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->src_bin), + _ms_node_resouces_acquire_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to acquire resources for src bin"); + return ret; + } + + /* Acquire resources for topology bin. If user doesn't + add nodes explicitly they will be acquired later. + For example when decodebin is used resources are quired + when 'autoplug-select' signal is triggered for new GstElement. */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->topology_bin), + _ms_node_resouces_acquire_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to acquire resources for topology bin"); + return ret; + } + + /* Acquire resources for src bin */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->sink_bin), + _ms_node_resouces_acquire_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to acquire resources for sink bin"); + return ret; + } + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_release_resources(media_streamer_s *ms_streamer) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Release resources for src bin */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->src_bin), + _ms_node_resouces_release_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to release resources for src bin"); + return ret; + } + + /* Release resources for topology bin. Here we also consider + nodes that were not added by user explicitly (e.g. decodebin + was used). */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->topology_bin), + _ms_node_resouces_release_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to release resources for topology bin"); + return ret; + } + + /* Release resources for src bin */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->sink_bin), + _ms_node_resouces_release_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to release resources for sink bin"); + return ret; + } + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_change_resources_state(media_streamer_s *ms_streamer, media_streamer_state_e state) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* According to state graph we need to handle only this two states + * and different transotions into them */ + if (state == MEDIA_STREAMER_STATE_IDLE) { + switch (ms_streamer->pend_state) { + case MEDIA_STREAMER_STATE_READY: + case MEDIA_STREAMER_STATE_PAUSED: + case MEDIA_STREAMER_STATE_PLAYING: + /* After unprepare function call */ + ret = __ms_release_resources(ms_streamer); + break; + case MEDIA_STREAMER_STATE_NONE: + case MEDIA_STREAMER_STATE_IDLE: + /* We do not considering double unprepare */ + case MEDIA_STREAMER_STATE_SEEKING: + default: + break; + } + } else if (state == MEDIA_STREAMER_STATE_READY) { + switch (ms_streamer->pend_state) { + case MEDIA_STREAMER_STATE_IDLE: + /* After prepare function */ + ret = __ms_aquire_resources(ms_streamer); + break; + case MEDIA_STREAMER_STATE_PAUSED: + case MEDIA_STREAMER_STATE_PLAYING: + case MEDIA_STREAMER_STATE_NONE: + case MEDIA_STREAMER_STATE_SEEKING: + default: + break; + } + } else { + ms_debug("Ignoring state for resource managements"); + } + + return ret; +} + +static gboolean media_streamer_resource_relese_cb( + media_streamer_resource_manager_s *resource_manager, + void *user_data) +{ + ms_retvm_if(user_data == NULL, FALSE, "user_data is NULL"); + + media_streamer_s *streamer = (media_streamer_s *) user_data; + ms_info("Reseived release_cb for streamer %p", streamer); + + /* Here we perform action to release resources relases that + were previoursly acquired (dynamically created case). + Basically what we need to do is to unprepare media streamer. + Whithout calling release function on every acquired resource. */ + g_mutex_lock(&streamer->mutex_lock); + streamer->is_interrupted = TRUE; + if (MEDIA_STREAMER_ERROR_NONE != + __ms_pipeline_unprepare(streamer)) { + ms_error("Failed to unprepare streamer"); + streamer->is_interrupted = FALSE; + g_mutex_unlock(&streamer->mutex_lock); + return FALSE; + } + streamer->is_interrupted = FALSE; + + /* Call interrupted_cb with appropriate code */ + media_streamer_interrupted_cb interrupted_cb = + (media_streamer_interrupted_cb) streamer->interrupted_cb.callback; + if (interrupted_cb) { + interrupted_cb(MEDIA_STREAMER_INTERRUPTED_BY_RESOURCE_CONFLICT, + streamer->interrupted_cb.user_data); + } else { + ms_info("Interuption will not be handled because interrupted_cb is NULL"); + } + g_mutex_unlock(&streamer->mutex_lock); + + return TRUE; +} diff --git a/src/media_streamer_resource.c b/src/media_streamer_resource.c new file mode 100644 index 0000000..4d84082 --- /dev/null +++ b/src/media_streamer_resource.c @@ -0,0 +1,550 @@ +/* + * Copyright (c) 2016 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 "media_streamer_util.h" +#include "media_streamer_resource.h" +#include "media_streamer_priv.h" +#include + +#define MRP_APP_CLASS_FOR_MSTREAMER "media" +#define MRP_RESOURCE_TYPE_MANDATORY TRUE +#define MRP_RESOURCE_TYPE_EXCLUSIVE FALSE + +enum { + MRP_RESOURCE_FOR_VIDEO_OVERLAY, + MRP_RESOURCE_FOR_CAMERA, + MRP_RESOURCE_FOR_VIDEO_DECODER, + MRP_RESOURCE_MAX, +}; +const char* resource_str[MRP_RESOURCE_MAX] = { + "video_overlay", + "camera", + "video_decoder", +}; + +#define MEDIA_STREAMER_WAIT_CONNECTION_TIMEOUT 5 + +#define MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(x_ms_resource_manager) \ +do { \ + if (!x_ms_resource_manager) { \ + ms_error("no resource manager instance");\ + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; \ + } \ +} while (0); + +static int __ms_resource_manager_wait_connection(media_streamer_resource_manager_s *resource_manager) +{ + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + if (resource_manager->is_connected) { + ms_debug("Already connected to resource server"); + } else { + gint64 end_time = g_get_monotonic_time() + MEDIA_STREAMER_RESOURCE_TIMEOUT*G_TIME_SPAN_SECOND; + + ms_debug("Not connected to resource server yet. Waiting..."); + + if (!g_cond_wait_until(&resource_manager->cond, + &resource_manager->lock, end_time)) { + ms_error("Could not connect to resource server"); + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + if (resource_manager->is_connected) + ms_debug("Successfully connected to resource server!"); + else { + ms_error("Failed to connect to resource server"); + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } + } + + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + return MEDIA_STREAMER_ERROR_NONE; +} + +static char *state_to_str(mrp_res_resource_state_t st) +{ + char *state = "unknown"; + switch (st) { + case MRP_RES_RESOURCE_ACQUIRED: + state = "acquired"; + break; + case MRP_RES_RESOURCE_LOST: + state = "lost"; + break; + case MRP_RES_RESOURCE_AVAILABLE: + state = "available"; + break; + case MRP_RES_RESOURCE_PENDING: + state = "pending"; + break; + case MRP_RES_RESOURCE_ABOUT_TO_LOOSE: + state = "about to loose"; + break; + } + return state; +} + +static void mrp_state_callback(mrp_res_context_t *context, mrp_res_error_t err, void *user_data) +{ + int i = 0; + const mrp_res_resource_set_t *rset; + mrp_res_resource_t *resource; + media_streamer_resource_manager_s* resource_manager = NULL; + + if (user_data == NULL) { + ms_error(" - user data is null"); + return; + } + resource_manager = (media_streamer_resource_manager_s *) user_data; + + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + if (err != MRP_RES_ERROR_NONE) { + ms_error(" - error message received from Murphy, err(0x%x)", err); + g_cond_signal(&resource_manager->cond); + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + return; + } + + switch (context->state) { + case MRP_RES_CONNECTED: + ms_debug(" - connected to Murphy"); + if ((rset = mrp_res_list_resources(context)) != NULL) { + mrp_res_string_array_t *resource_names; + resource_names = mrp_res_list_resource_names(rset); + if (!resource_names) { + ms_error(" - no resources available"); + return; + } + for (i = 0; i < resource_names->num_strings; i++) { + resource = mrp_res_get_resource_by_name(rset, resource_names->strings[i]); + if (resource) + ms_debug(" - available resource: %s", resource->name); + } + mrp_res_free_string_array(resource_names); + } + resource_manager->is_connected = TRUE; + g_cond_signal(&resource_manager->cond); + break; + case MRP_RES_DISCONNECTED: + ms_debug(" - disconnected from Murphy"); + if (resource_manager->rset) { + mrp_res_delete_resource_set(resource_manager->rset); + resource_manager->rset = NULL; + } + mrp_res_destroy(resource_manager->context); + resource_manager->context = NULL; + resource_manager->is_connected = FALSE; + g_cond_signal(&resource_manager->cond); + break; + } + + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + + return; +} + +static void mrp_rset_state_callback(mrp_res_context_t *cx, const mrp_res_resource_set_t *rs, void *user_data) +{ + int i = 0; + media_streamer_resource_manager_s *resource_manager = (media_streamer_resource_manager_s *)user_data; + mrp_res_resource_t *res; + + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + if (!mrp_res_equal_resource_set(rs, resource_manager->rset)) { + ms_info("- resource set(%p) is not same as this resource_manager handle's(%p)", rs, resource_manager->rset); + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + return; + } + + ms_debug(" - resource set state of resource_manager(%p) is changed to [%s]", resource_manager, state_to_str(rs->state)); + for (i = 0; i < MRP_RESOURCE_MAX; i++) { + res = mrp_res_get_resource_by_name(rs, resource_str[i]); + if (res == NULL) + ms_info(" -- %s not present in resource set", resource_str[i]); + else + ms_info(" -- resource name [%s] -> [%s]'", res->name, state_to_str(res->state)); + } + + mrp_res_delete_resource_set(resource_manager->rset); + resource_manager->rset = mrp_res_copy_resource_set(rs); + + if (rs->state == MRP_RES_RESOURCE_ACQUIRED) { + ms_debug(" - resource set is acquired"); + resource_manager->state = RESOURCE_STATE_ACQUIRED; + MEDIA_STREAMER_RESOURCE_SIGNAL(resource_manager); + } else if ((resource_manager->state >= RESOURCE_STATE_ACQUIRED) && + (rs->state == MRP_RES_RESOURCE_AVAILABLE)) { + ms_debug(" - resource set is released"); + resource_manager->state = RESOURCE_STATE_PREPARED; + MEDIA_STREAMER_RESOURCE_SIGNAL(resource_manager); + } + + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); +} + + +static void mrp_resource_release_cb(mrp_res_context_t *cx, const mrp_res_resource_set_t *rs, void *user_data) +{ + int i = 0; + media_streamer_resource_manager_s *resource_manager = NULL; + mrp_res_resource_t *res; + + if (user_data == NULL) { + ms_error("- user_data is null"); + return; + } + resource_manager = (media_streamer_resource_manager_s *) user_data; + + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + if (!mrp_res_equal_resource_set(rs, resource_manager->rset)) { + ms_info("- resource set(%p) is not same as this resource_manager handle's(%p)", + rs, resource_manager->rset); + return; + } + + ms_debug(" - resource set state of resource manager (%p) is changed to [%s]", + resource_manager, state_to_str(rs->state)); + for (i = 0; i < MRP_RESOURCE_MAX; i++) { + res = mrp_res_get_resource_by_name(rs, resource_str[i]); + if (res == NULL) + ms_info(" -- %s not present in resource set", resource_str[i]); + else + ms_debug(" -- resource name [%s] -> [%s] %d'", res->name, + state_to_str(res->state), res->state); + } + + if (resource_manager->release_cb) { + if (!resource_manager->release_cb(resource_manager, resource_manager->user_data)) { + ms_error("release_cb failed"); + } else { + ms_info("release_cb is fine"); + } + } else { + ms_error("release cb is NULL. Something wrong happens..."); + } + + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + + return; +} + +static int create_rset(media_streamer_resource_manager_s *resource_manager) +{ + if (resource_manager->rset) { + ms_error(" - resource set was already created"); + return MEDIA_STREAMER_ERROR_INVALID_STATE; + } + + resource_manager->rset = + mrp_res_create_resource_set(resource_manager->context, + MRP_APP_CLASS_FOR_MSTREAMER, + mrp_rset_state_callback, + (void*)resource_manager); + if (resource_manager->rset == NULL) { + ms_error(" - could not create resource set"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if (!mrp_res_set_autorelease(TRUE, resource_manager->rset)) + ms_info(" - could not set autorelease flag!"); + + return MEDIA_STREAMER_ERROR_NONE; +} + +static int include_resource(media_streamer_resource_manager_s *resource_manager, const char *resource_name) +{ + mrp_res_resource_t *resource = NULL; + resource = mrp_res_create_resource(resource_manager->rset, + resource_name, + MRP_RESOURCE_TYPE_MANDATORY, + MRP_RESOURCE_TYPE_EXCLUSIVE); + if (resource == NULL) { + ms_error(" - could not include resource[%s]", resource_name); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + ms_debug(" - include resource[%s]", resource_name); + + return MEDIA_STREAMER_ERROR_NONE; +} + +static int set_resource_release_cb(media_streamer_resource_manager_s *resource_manager) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + bool mrp_ret = FALSE; + + if (resource_manager->rset) { + if (MRP_RES_RESOURCE_PENDING == resource_manager->rset->state) { + /* FIXME: This workarond is only temporary solution. + When resource set is acquired again after lost the state is 'available' + and no 'pending'. Thus we skip setting reelease callback as it already + was set. */ + mrp_ret = mrp_res_set_release_callback(resource_manager->rset, mrp_resource_release_cb, resource_manager); + if (!mrp_ret) { + ms_error(" - could not set release callback"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } + } else { + ms_error(" - resource set is null"); + ret = MEDIA_STREAMER_ERROR_INVALID_STATE; + } + + return ret; +} + +int _ms_resource_manager_init(media_streamer_resource_manager_s *resource_manager, + resource_relese_cb release_cb, void *user_data) +{ + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + ms_retvm_if(release_cb == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, + "release_cb is NULL"); + + g_mutex_init(&resource_manager->lock); + g_cond_init(&resource_manager->cond); + + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + GMainContext *mrp_ctx = g_main_context_new(); + if (!mrp_ctx) { + ms_error("- could not create main context for resource manager"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + GMainLoop *mrp_loop = g_main_loop_new(mrp_ctx, TRUE); + g_main_context_unref(mrp_ctx); + if (!mrp_loop) { + ms_error("- could not create glib mainloop for resource manager"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + resource_manager->mloop = mrp_mainloop_glib_get(mrp_loop); + g_main_loop_unref(mrp_loop); + if (resource_manager->mloop) { + resource_manager->context = mrp_res_create(resource_manager->mloop, + mrp_state_callback, resource_manager); + + if (resource_manager->context == NULL) { + ms_error(" - could not get context for resource manager"); + mrp_mainloop_destroy(resource_manager->mloop); + resource_manager->mloop = NULL; + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + resource_manager->user_data = user_data; + } else { + ms_error("- could not get mainloop for resource manager"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + resource_manager->release_cb = release_cb; + resource_manager->state = RESOURCE_STATE_INITIALIZED; + + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int _ms_resource_manager_prepare(media_streamer_resource_manager_s *resource_manager, media_streamer_resource_type_e resource_type) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + __ms_resource_manager_wait_connection(resource_manager); + + if (!resource_manager->rset) + ret = create_rset(resource_manager); + + if (ret == MEDIA_STREAMER_ERROR_NONE) { + switch (resource_type) { + case RESOURCE_TYPE_VIDEO_OVERLAY: + ret = include_resource(resource_manager, resource_str[MRP_RESOURCE_FOR_VIDEO_OVERLAY]); + break; + case RESOURCE_TYPE_VIDEO_DECODER: + ret = include_resource(resource_manager, resource_str[MRP_RESOURCE_FOR_VIDEO_DECODER]); + break; + case RESOURCE_TYPE_CAMERA: + ret = include_resource(resource_manager, resource_str[MRP_RESOURCE_FOR_CAMERA]); + break; + case RESOURCE_TYPE_NONE: + default: + ms_error("Wrong resource type %d", resource_type); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + break; + } + } + + if (MEDIA_STREAMER_ERROR_NONE == ret) { + resource_manager->state = RESOURCE_STATE_PREPARED; + } else { + resource_manager->state = RESOURCE_STATE_ERROR; + } + + return ret; +} + +int _ms_resource_manager_acquire(media_streamer_resource_manager_s *resource_manager) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + __ms_resource_manager_wait_connection(resource_manager); + + if (resource_manager->rset == NULL) { + ms_error("- could not acquire resource, resource set is null"); + ret = MEDIA_STREAMER_ERROR_INVALID_STATE; + } else { + ret = set_resource_release_cb(resource_manager); + if (ret) { + ms_error("- could not set resource release cb, ret(%d)", ret); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + ret = mrp_res_acquire_resource_set(resource_manager->rset); + if (ret) { + ms_error("- could not acquire resource, ret(%d)", ret); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + gint64 end_time = g_get_monotonic_time() + MEDIA_STREAMER_RESOURCE_TIMEOUT*G_TIME_SPAN_SECOND; + + ms_debug("- acquire resource waiting..%p till %lld", resource_manager, end_time); + if (!MEDIA_STREAMER_RESOURCE_WAIT_UNTIL(resource_manager, end_time)) { + ms_error("- could not acquire resource"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + ms_debug("- resources are acquired"); + } + } + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + } + } + + return ret; +} + +int _ms_resource_manager_release(media_streamer_resource_manager_s *resource_manager) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + __ms_resource_manager_wait_connection(resource_manager); + + if (resource_manager->rset == NULL) { + ms_error("- could not release resource, resource set is null"); + ret = MEDIA_STREAMER_ERROR_INVALID_STATE; + } else { + if (resource_manager->rset->state != MRP_RES_RESOURCE_ACQUIRED) { + ms_error("- could not release resource, resource set state is [%s]", state_to_str(resource_manager->rset->state)); + ret = MEDIA_STREAMER_ERROR_INVALID_STATE; + } else { + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + ret = mrp_res_release_resource_set(resource_manager->rset); + if (ret) { + ms_error("- could not release resource, ret(%d)", ret); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + gint64 end_time = g_get_monotonic_time() + MEDIA_STREAMER_RESOURCE_TIMEOUT*G_TIME_SPAN_SECOND; + + ms_debug("- release resource waiting..%p till %lld", resource_manager, end_time); + if (!MEDIA_STREAMER_RESOURCE_WAIT_UNTIL(resource_manager, end_time)) { + ms_info("- could not release resource in time"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + ms_debug("- resources are released"); + } + } + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + } + } + + return ret; +} + +int _ms_resource_manager_unprepare(media_streamer_resource_manager_s *resource_manager) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + __ms_resource_manager_wait_connection(resource_manager); + + if (resource_manager->rset == NULL) { + ms_error("- could not unprepare for resource_manager, _ms_resource_manager_prepare() first"); + ret = MEDIA_STREAMER_ERROR_INVALID_STATE; + } else { + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + mrp_res_delete_resource_set(resource_manager->rset); + resource_manager->rset = NULL; + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + } + + resource_manager->state = RESOURCE_STATE_INITIALIZED; + + return ret; +} + +int _ms_resource_manager_deinit(media_streamer_resource_manager_s *resource_manager) +{ + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + __ms_resource_manager_wait_connection(resource_manager); + + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + if (resource_manager->rset) { + if (resource_manager->rset->state == MRP_RES_RESOURCE_ACQUIRED) { + if (mrp_res_release_resource_set(resource_manager->rset)) + ms_error("- could not release resource"); + } + mrp_res_delete_resource_set(resource_manager->rset); + resource_manager->rset = NULL; + } + + if (resource_manager->context) { + mrp_res_destroy(resource_manager->context); + resource_manager->context = NULL; + } + + if (resource_manager->mloop) { + mrp_mainloop_destroy(resource_manager->mloop); + resource_manager->mloop = NULL; + } + + resource_manager->release_cb = NULL; + + resource_manager->state = RESOURCE_STATE_NONE; + + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + + g_mutex_clear(&resource_manager->lock); + g_cond_clear(&resource_manager->cond); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int _ms_resource_manager_get_state(media_streamer_resource_manager_s *resource_manager, media_streamer_resource_state_e *state) +{ + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + ms_retvm_if(state == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, + "state is NULL"); + + ms_debug("resource_state is %d", resource_manager->state); + + *state = resource_manager->state; + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_util.c b/src/media_streamer_util.c index 8272f50..4ea599f 100644 --- a/src/media_streamer_util.c +++ b/src/media_streamer_util.c @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -160,6 +161,8 @@ void __ms_load_ini_settings(media_streamer_ini_t *ini) /* Read exclude elements list */ __ms_ini_read_list("general:exclude elements", &ini->exclude_elem_names); + /* Read resource require elements list */ + __ms_ini_read_list("general:resource elements", &ini->resource_required_elem_names); /* Read gstreamer arguments list */ __ms_ini_read_list("general:gstreamer arguments", &ini->gst_args); @@ -327,3 +330,43 @@ int __ms_node_uri_path_check(const char *file_uri) return MEDIA_STREAMER_ERROR_NONE; } + +int __ms_bin_foreach_elements(GstBin *bin, GstIteratorFoldFunction func, void *user_data) +{ + media_streamer_s *streamer = (media_streamer_s *) user_data; + + if (!GST_BIN_NUMCHILDREN(bin)) { + ms_debug("No elements were added to bin [%s]. Skipping... ", + GST_ELEMENT_NAME(bin)); + return MEDIA_STREAMER_STATE_NONE; + } + + GstIterator *iter = gst_bin_iterate_recurse(bin); + GValue ret = G_VALUE_INIT; + GstIteratorResult result = GST_ITERATOR_DONE; + + g_value_init(&ret, G_TYPE_BOOLEAN); + result = gst_iterator_fold(iter, func, &ret, streamer); + gst_iterator_free(iter); + + switch (result) { + case GST_ITERATOR_RESYNC: + case GST_ITERATOR_ERROR: + ms_error("Error while iterating elements in bin [%s]!", + GST_ELEMENT_NAME(bin)); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + break; + case GST_ITERATOR_DONE: + case GST_ITERATOR_OK: + /* Check for last return value */ + if (!g_value_get_boolean(&ret)) { + ms_error("Failed to prepare one of nodes"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + break; + default: + break; + } + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/test/media_streamer_test.c b/test/media_streamer_test.c index 309a134..3c8d834 100644 --- a/test/media_streamer_test.c +++ b/test/media_streamer_test.c @@ -182,7 +182,12 @@ static void streamer_seek_cb(void *user_data) static void streamer_changed_cb(media_streamer_h streamer, media_streamer_state_e previous_state, media_streamer_state_e current_state, void *user_data) { - g_print("Media Streamer State changed [%d] -> [%d]", previous_state, current_state); + g_print("Media Streamer State changed [%d] -> [%d]\n", previous_state, current_state); +} + +static void streamer_interrubted_cb(media_streamer_interrupted_code_e code, void *user_data) +{ + g_print("Media Streamer was interrupted with code [%d]\n", code); } static void _create(media_streamer_h *streamer) @@ -215,6 +220,7 @@ static void _prepare(void) } media_streamer_set_state_change_cb(current_media_streamer, streamer_changed_cb, NULL); + media_streamer_set_interrupted_cb(current_media_streamer, streamer_interrubted_cb, NULL); g_print("== success prepare \n"); } @@ -290,13 +296,13 @@ static void _destroy(media_streamer_h streamer) int ret = MEDIA_STREAMER_ERROR_NONE; if (streamer == NULL) { - g_print("media streamer already destroyed"); + g_print("media streamer already destroyed\n"); return; } ret = media_streamer_destroy(streamer); if (ret != MEDIA_STREAMER_ERROR_NONE) { - g_print("Fail to destroy media streamer"); + g_print("Fail to destroy media streamer\n"); return; } @@ -313,7 +319,7 @@ static void _destroy(media_streamer_h streamer) static void create_formats(void) { if (!vfmt_raw || !vfmt_encoded || !afmt_raw) - g_print("Formats already created!"); + g_print("Formats already created!\n"); /* Define video raw format */ media_format_create(&vfmt_raw); @@ -1551,7 +1557,7 @@ void _interpret_getting_uri_menu(char *cmd) return; } - g_print("_interpret_getting_uri_menu %d %d %d", g_menu_state, g_sub_menu_state, g_scenario_mode); + g_print("_interpret_getting_uri_menu %d %d %d\n", g_menu_state, g_sub_menu_state, g_scenario_mode); if (g_menu_state == MENU_STATE_PLAYING_MENU) { if (g_scenario_mode == SCENARIO_MODE_FILE_SUBTITLE_VIDEO_AUDIO) { g_sub_menu_state = SUBMENU_STATE_GETTING_SUBFILE_URI; -- 2.7.4 From 73a6be599b809791ca3f094cc2902a789c168751 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Thu, 8 Dec 2016 13:48:09 +0200 Subject: [PATCH 13/16] Implement DPM requests for camera and mic Change-Id: Ic1e57ca37017a0aac694a457e5b62b00ba0cf55b Signed-off-by: Volodymyr Brynza (cherry picked from commit b79012ad96b65afc7f54debd6e5fb6ce1788b43a) --- CMakeLists.txt | 4 +- include/media_streamer_node.h | 1 + include/media_streamer_node_policy.h | 40 +++++++ include/media_streamer_priv.h | 3 + packaging/capi-media-streamer.spec | 1 + src/media_streamer_node.c | 41 +++++++ src/media_streamer_node_policy.c | 204 +++++++++++++++++++++++++++++++++++ src/media_streamer_node_resources.c | 2 +- src/media_streamer_priv.c | 47 ++++++++ 9 files changed, 340 insertions(+), 3 deletions(-) create mode 100644 include/media_streamer_node_policy.h create mode 100644 src/media_streamer_node_policy.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c7e7c5..04a307d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,8 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(INC_DIR include) INCLUDE_DIRECTORIES(${INC_DIR}) -SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary murphy-resource murphy-glib") -SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary murphy-resource murphy-glib") +SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary murphy-resource murphy-glib dpm") +SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary murphy-resource murphy-glib dpm") INCLUDE(FindPkgConfig) pkg_check_modules(${fw_name} REQUIRED ${dependents}) diff --git a/include/media_streamer_node.h b/include/media_streamer_node.h index f79f9e5..add8a37 100644 --- a/include/media_streamer_node.h +++ b/include/media_streamer_node.h @@ -131,3 +131,4 @@ int __ms_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, gboolean _ms_node_resouces_acquire_iter(const GValue *item, GValue *ret, gpointer user_data); gboolean _ms_node_resouces_release_iter(const GValue *item, GValue *ret, gpointer user_data); +gboolean _ms_node_policy_check_iter(const GValue *item, GValue *ret, gpointer user_data); diff --git a/include/media_streamer_node_policy.h b/include/media_streamer_node_policy.h new file mode 100644 index 0000000..5f9adef --- /dev/null +++ b/include/media_streamer_node_policy.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015-2016 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_STREAMER_NODE_POLICY_H__ +#define __MEDIA_STREAMER_NODE_POLICY_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + POLICY_TYPE_NONE, + POLICY_TYPE_CAMERA, + POLICY_TYPE_MIC, +} media_streamer_policy_type_e; + +int __ms_node_policy_init(media_streamer_node_s *node); +int __ms_node_policy_deinit(media_streamer_node_s *node); +int _ms_node_policy_check(media_streamer_node_s *node); + +#ifdef __cplusplus +} +#endif + +#endif /* __MEDIA_STREAMER_NODE_POLICY_H__ */ diff --git a/include/media_streamer_priv.h b/include/media_streamer_priv.h index 14a45f7..bbfd37b 100755 --- a/include/media_streamer_priv.h +++ b/include/media_streamer_priv.h @@ -24,6 +24,7 @@ extern "C" { #include #include +#include #include #include @@ -137,6 +138,8 @@ typedef struct { void *callbacks_structure; media_streamer_resource_manager_s resource_manager; + device_policy_manager_h dpm_handle; + int policy_changed_cb_id; } media_streamer_node_s; typedef struct _media_streamer_wl_info_s { diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 7443f3b..317b737 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -31,6 +31,7 @@ BuildRequires: pkgconfig(ecore-wayland) BuildRequires: pkgconfig(appcore-efl) BuildRequires: pkgconfig(murphy-resource) BuildRequires: pkgconfig(murphy-glib) +BuildRequires: pkgconfig(dpm) %description A MediaStreamer library in Tizen Native API. diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index a87724f..ced5323 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -579,6 +580,12 @@ int __ms_src_node_create(media_streamer_node_s *node) return ret; } + ret = __ms_node_policy_init(node); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to init policy for node [%s]", node->name); + return ret; + } + return ret; } @@ -702,6 +709,10 @@ void __ms_node_destroy(media_streamer_node_s *node) /* Disconnects and clean all node signals */ g_list_free_full(node->sig_list, __ms_signal_destroy); + /* Deinitialize policy manager */ + if (MEDIA_STREAMER_ERROR_NONE != __ms_node_policy_deinit(node)) + ms_error("Failed to deinitialize policy manager"); + /* Deinitialize resource manager */ if (MEDIA_STREAMER_ERROR_NONE != __ms_node_resouces_deinit(node)) ms_error("Failed to deinitialize resource manager"); @@ -1598,3 +1609,33 @@ gboolean _ms_node_resouces_release_iter(const GValue *item, GValue *ret, gpointe return TRUE; } + +gboolean _ms_node_policy_check_iter(const GValue *item, GValue *ret, gpointer user_data) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) user_data; + media_streamer_node_s *node = NULL; + GstElement *element = NULL; + g_value_set_boolean(ret, FALSE); + + element = GST_ELEMENT(g_value_get_object(item)); + g_object_ref(element); + + node = (media_streamer_node_s *) g_hash_table_lookup(ms_streamer->nodes_table, + GST_ELEMENT_NAME(element)); + if (!node) { + /* If we fail to found corresonding node inside streamer + then apprently this element doesn't require resources */ + ms_info("Failed to found corresonding node [%s] inside streamer", GST_ELEMENT_NAME(element)); + g_value_set_boolean(ret, TRUE); + return TRUE; + } + + if (MEDIA_STREAMER_ERROR_NONE != _ms_node_policy_check(node)) { + ms_error("Failed to check policy for node [%s]", node->name); + return FALSE; + } + + g_value_set_boolean(ret, TRUE); + + return TRUE; +} diff --git a/src/media_streamer_node_policy.c b/src/media_streamer_node_policy.c new file mode 100644 index 0000000..90628b9 --- /dev/null +++ b/src/media_streamer_node_policy.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2016 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 + +#include +#include +#include +#include + +#define DPM_ALLOWED 1 +#define DPM_DISALLOWED 0 + +enum { + DPM_POLICY_FOR_CAMERA, + DPM_POLICY_FOR_MIC, + DPM_POLICY_MAX, +}; +const char* policy_str[DPM_POLICY_MAX] = { + "camera", + "microphone", +}; + +static void __ms_node_get_dpm_check_needed(media_streamer_node_s *node, + media_streamer_policy_type_e *policy) { + int subtype = node->subtype; + + ms_debug("Checking policy for node type %d, subtype %d", node->type, subtype); + + /* Check for node types */ + switch (subtype) { + case MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA: + case MEDIA_STREAMER_NODE_SRC_TYPE_VIDEO_CAPTURE: + *policy = POLICY_TYPE_CAMERA; + break; + case MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_CAPTURE: + *policy = POLICY_TYPE_MIC; + break; + default: + break; + } +} + +static void __ms_node_policy_changed_cb(const char *name, const char *value, void *user_data) +{ + if (user_data == NULL) + return; + + media_streamer_node_s *node = (media_streamer_node_s *) user_data; + media_streamer_s *streamer = (media_streamer_s *) node->parent_streamer; + ms_info("Received policy_changed_cb from node [%s]", node->name); + + /* Here we perform action to release resources relases that + were previoursly acquired. Basically what we need to do is + to unprepare media streamer.*/ + g_mutex_lock(&streamer->mutex_lock); + streamer->is_interrupted = TRUE; + if (MEDIA_STREAMER_ERROR_NONE != + __ms_pipeline_unprepare(streamer)) { + ms_error("Failed to unprepare streamer"); + streamer->is_interrupted = FALSE; + g_mutex_unlock(&streamer->mutex_lock); + return; + } + streamer->is_interrupted = FALSE; + + /* Call interrupted_cb with appropriate code */ + media_streamer_interrupted_cb interrupted_cb = + (media_streamer_interrupted_cb) streamer->interrupted_cb.callback; + if (interrupted_cb) { + interrupted_cb(MEDIA_STREAMER_INTERRUPTED_BY_SECURITY, + streamer->interrupted_cb.user_data); + } else { + ms_info("Interuption will not be handled because interrupted_cb is NULL"); + } + g_mutex_unlock(&streamer->mutex_lock); +} + +int __ms_node_policy_init(media_streamer_node_s *node) +{ + media_streamer_policy_type_e policy = POLICY_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + const char *policy_name = NULL; + + /* Check if node require policy manager */ + __ms_node_get_dpm_check_needed(node, &policy); + if (POLICY_TYPE_NONE == policy) { + ms_info("No policy is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + switch (policy) { + case POLICY_TYPE_CAMERA: + policy_name = policy_str[DPM_POLICY_FOR_CAMERA]; + break; + case POLICY_TYPE_MIC: + policy_name = policy_str[DPM_POLICY_FOR_MIC]; + break; + default: + break; + } + /* Initialize policy manager */ + node->dpm_handle = dpm_manager_create(); + if (node->dpm_handle) { + int dpm_ret = DPM_ERROR_NONE; + dpm_ret = dpm_add_policy_changed_cb(node->dpm_handle, policy_name, + __ms_node_policy_changed_cb, (void *)node, &node->policy_changed_cb_id); + + if (dpm_ret != DPM_ERROR_NONE) { + ms_error("add DPM changed cb failed, keep going"); + node->policy_changed_cb_id = 0; + } + ms_debug("DPM initialized"); + } + + return ret; +} + +int __ms_node_policy_deinit(media_streamer_node_s *node) +{ + media_streamer_policy_type_e policy = POLICY_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Check if node require policy manager */ + __ms_node_get_dpm_check_needed(node, &policy); + if (POLICY_TYPE_NONE == policy) { + ms_info("No policy is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (node->dpm_handle) { + if (node->policy_changed_cb_id > 0) { + dpm_remove_policy_changed_cb(node->dpm_handle, node->policy_changed_cb_id); + } else { + ms_info("invalid dpm cb id"); + } + ms_debug("DPM released"); + } + + dpm_manager_destroy(node->dpm_handle); + node->dpm_handle = NULL; + + return ret; +} + +int _ms_node_policy_check(media_streamer_node_s *node) +{ + media_streamer_policy_type_e policy = POLICY_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + int dpm_state = DPM_ALLOWED; + int dpm_ret = DPM_ERROR_NONE; + + /* Check if node require policy manager */ + __ms_node_get_dpm_check_needed(node, &policy); + if (POLICY_TYPE_NONE == policy) { + ms_info("No policy is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (node->dpm_handle == NULL) { + ms_error("DPM manager handle is NULL"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + switch (policy) { + case POLICY_TYPE_CAMERA: + dpm_ret = dpm_restriction_get_camera_state(node->dpm_handle, &dpm_state); + break; + case POLICY_TYPE_MIC: + dpm_ret = dpm_restriction_get_microphone_state(node->dpm_handle, &dpm_state); + break; + default: + break; + } + + if (dpm_ret == DPM_ERROR_NONE) { + ms_info("DPM state - %d", dpm_state); + if (dpm_state == DPM_DISALLOWED) { + ms_error("Policy disallowed by DPM"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } else { + ms_info("get DPM state failed, continue too work"); + } + + return ret; +} diff --git a/src/media_streamer_node_resources.c b/src/media_streamer_node_resources.c index 5dabe15..3c1545a 100644 --- a/src/media_streamer_node_resources.c +++ b/src/media_streamer_node_resources.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 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. diff --git a/src/media_streamer_priv.c b/src/media_streamer_priv.c index 3fe8485..a6b995d 100644 --- a/src/media_streamer_priv.c +++ b/src/media_streamer_priv.c @@ -23,6 +23,7 @@ #define GST_TIME_TO_MSEC(t) (t == GST_CLOCK_TIME_NONE ? t : (int)(((GstClockTime)(t)) / GST_MSECOND)) int __ms_change_resources_state(media_streamer_s *ms_streamer, media_streamer_state_e state); +int __ms_change_policy_state(media_streamer_s *ms_streamer, media_streamer_state_e state); static gboolean media_streamer_resource_relese_cb(media_streamer_resource_manager_s *resource_manager, void *user_data); int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e state) @@ -33,6 +34,11 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat ms_retvm_if(ms_streamer->state == state, MEDIA_STREAMER_ERROR_NONE, "Media streamer already in this state"); if (!ms_streamer->is_interrupted) { + ret = __ms_change_policy_state(ms_streamer, state); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to change policy state for streamer %p", ms_streamer); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } ret = __ms_change_resources_state(ms_streamer, state); if (MEDIA_STREAMER_ERROR_NONE != ret) { ms_error("Failed to change resources state for streamer %p", ms_streamer); @@ -338,3 +344,44 @@ static gboolean media_streamer_resource_relese_cb( return TRUE; } + +int __ms_check_policy(media_streamer_s *ms_streamer) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Acquire resources for src bin */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->src_bin), + _ms_node_policy_check_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to check policies for src bin"); + return ret; + } + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_change_policy_state(media_streamer_s *ms_streamer, media_streamer_state_e state) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* According to state graph we need to handle only this state + * and different transotions into them */ + if (state == MEDIA_STREAMER_STATE_READY) { + switch (ms_streamer->pend_state) { + case MEDIA_STREAMER_STATE_IDLE: + /* After prepare function */ + ret = __ms_check_policy(ms_streamer); + break; + case MEDIA_STREAMER_STATE_PAUSED: + case MEDIA_STREAMER_STATE_PLAYING: + case MEDIA_STREAMER_STATE_NONE: + case MEDIA_STREAMER_STATE_SEEKING: + default: + break; + } + } else { + ms_debug("Ignoring state for policy managements"); + } + + return ret; +} -- 2.7.4 From 526c4fde1380d5fcdfa70a0a8c320c10af3094c8 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Mon, 19 Dec 2016 22:31:44 +0200 Subject: [PATCH 14/16] Add Murphy loop quit to prevent polling after destroy Change-Id: I789b032fced4b95a767b4efcda92c54fb5c2cd12 Signed-off-by: Volodymyr Brynza (cherry picked from commit 7c16b0bd37214f99f2bb3dd1a46d67bd87961484) --- src/media_streamer_resource.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/media_streamer_resource.c b/src/media_streamer_resource.c index 4d84082..6f99048 100644 --- a/src/media_streamer_resource.c +++ b/src/media_streamer_resource.c @@ -520,6 +520,7 @@ int _ms_resource_manager_deinit(media_streamer_resource_manager_s *resource_mana } if (resource_manager->mloop) { + mrp_mainloop_quit(resource_manager->mloop, 0); mrp_mainloop_destroy(resource_manager->mloop); resource_manager->mloop = NULL; } -- 2.7.4 From 81d4e447b82db4346069405ecfcfaeaf1fc0b388 Mon Sep 17 00:00:00 2001 From: Oleksandr Popov Date: Tue, 27 Dec 2016 19:00:21 +0200 Subject: [PATCH 15/16] Add platform check before resource manager initialization Change-Id: I001fbd14fe4589db030a69e6fd985a32460ac6da Signed-off-by: Oleksandr Popov --- include/media_streamer_resource.h | 2 +- src/media_streamer_node_resources.c | 58 +++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/include/media_streamer_resource.h b/include/media_streamer_resource.h index 27da5ca..2cefdc8 100644 --- a/include/media_streamer_resource.h +++ b/include/media_streamer_resource.h @@ -52,7 +52,7 @@ typedef enum { } media_streamer_resource_state_e; typedef struct _media_streamer_resource_manager_s media_streamer_resource_manager_s; -typedef gboolean (*resource_relese_cb) (media_streamer_resource_manager_s *resource_manager, void *user_data); +typedef gboolean (*resource_relese_cb)(media_streamer_resource_manager_s *resource_manager, void *user_data); struct _media_streamer_resource_manager_s { mrp_mainloop_t *mloop; diff --git a/src/media_streamer_node_resources.c b/src/media_streamer_node_resources.c index 3c1545a..5e96813 100644 --- a/src/media_streamer_node_resources.c +++ b/src/media_streamer_node_resources.c @@ -16,6 +16,8 @@ #include +#include + #include #include #include @@ -61,6 +63,41 @@ static gboolean __ms_resource_relese_cb( return TRUE; } +static gboolean __ms_node_resources_is_needed_by_platform(media_streamer_node_s *node) +{ + media_streamer_node_type_e type = node->type; + int subtype = node->subtype; + char *model_name, *platform_processor; + gboolean ret = FALSE; + + /* Checking for model_name and processor because some resources + are platform dependent */ + system_info_get_platform_string("http://tizen.org/system/model_name", &model_name); + system_info_get_platform_string("http://tizen.org/system/platform.processor", &platform_processor); + ms_info("Check for resources for model_name %s, platform.processor %s", model_name, platform_processor); + + switch (type) { + case MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER: + case MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER: + if (!g_strcmp0(model_name, "Emulator") || + !g_strcmp0(platform_processor, "Emulator")) + ret = FALSE; + break; + case MEDIA_STREAMER_NODE_TYPE_SRC: + if (MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA == subtype) + ret = TRUE; + break; + case MEDIA_STREAMER_NODE_TYPE_SINK: + if (MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY == subtype) + ret = TRUE; + break; + default: + break; + } + + return ret; +} + static void __ms_node_get_resources_needed(media_streamer_node_s *node, media_streamer_resource_type_e *resource) { media_streamer_node_type_e type = node->type; @@ -101,6 +138,13 @@ int __ms_node_resouces_init(media_streamer_node_s *node) return MEDIA_STREAMER_ERROR_NONE; } + /* Check if platform requires resource (e.g. Emulator) */ + if (!__ms_node_resources_is_needed_by_platform(node)) { + ms_info("Platform doesn't require resource for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + /* Initialize resource manager */ ret = _ms_resource_manager_init(&node->resource_manager, __ms_resource_relese_cb, node); @@ -125,6 +169,13 @@ int __ms_node_resouces_deinit(media_streamer_node_s *node) return MEDIA_STREAMER_ERROR_NONE; } + /* Check if platform requires resource (e.g. Emulator) */ + if (!__ms_node_resources_is_needed_by_platform(node)) { + ms_info("Platform doesn't require resource for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + /* Deinitialize resource manager */ ret = _ms_resource_manager_deinit(&node->resource_manager); if (ret != MEDIA_STREAMER_ERROR_NONE) { @@ -196,6 +247,13 @@ int _ms_node_resource_aquire(media_streamer_node_s *node) return MEDIA_STREAMER_ERROR_NONE; } + /* Check if platform requires resource (e.g. Emulator) */ + if (!__ms_node_resources_is_needed_by_platform(node)) { + ms_info("Platform doesn't require resource for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + if (MEDIA_STREAMER_ERROR_NONE != __ms_node_resouces_prepare(node, resource)) { ms_error("Failed to prepare resources for Node [%p]", node); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; -- 2.7.4 From 0a187c0051812dbe8e6c2f12c189cac7c2b239ae Mon Sep 17 00:00:00 2001 From: Oleksandr Popov Date: Tue, 27 Dec 2016 19:39:48 +0200 Subject: [PATCH 16/16] Added missing condition for resource management check Signed-off-by: Oleksandr Popov Change-Id: I700bad3752224583d04762081689b48188a5ec74 --- src/media_streamer_node_resources.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/media_streamer_node_resources.c b/src/media_streamer_node_resources.c index 5e96813..2f69001 100644 --- a/src/media_streamer_node_resources.c +++ b/src/media_streamer_node_resources.c @@ -82,6 +82,8 @@ static gboolean __ms_node_resources_is_needed_by_platform(media_streamer_node_s if (!g_strcmp0(model_name, "Emulator") || !g_strcmp0(platform_processor, "Emulator")) ret = FALSE; + else + ret = TRUE; break; case MEDIA_STREAMER_NODE_TYPE_SRC: if (MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA == subtype) -- 2.7.4