From 12648d4b18cf998352f0ac19840b38595abbc4ae Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Fri, 17 Jun 2016 13:45:54 +0900 Subject: [PATCH 01/16] add return val of permission checking Change-Id: I1c75dc9fb4bc84e059d10cef281631e645168461 --- src/media_streamer_node.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 22bf15d..6443f0d 100755 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -939,7 +939,8 @@ int __ms_node_set_param_value(media_streamer_node_s *ms_node, param_s *param, co else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_IS_LIVE_STREAM)) 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_URI)) { - if (!__ms_node_uri_path_check(param_value)) + ret = __ms_node_uri_path_check(param_value); + if (ret == MEDIA_STREAMER_ERROR_NONE) g_object_set(ms_node->gst_element, param->origin_name, param_value, NULL); } else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_USER_AGENT)) g_object_set(ms_node->gst_element, param->origin_name, param_value, NULL); -- 2.7.4 From 6935491fc415ab83bb3d89633282eabfc9a55502 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Fri, 17 Jun 2016 12:56:01 +0300 Subject: [PATCH 02/16] Fix coverage issue Change-Id: Iecbc1fcaacb930578906025cf5bdff3f6c8ff2d8 Signed-off-by: Volodymyr Brynza --- include/media_streamer_gst.h | 7 ------ src/media_streamer_gst.c | 53 -------------------------------------------- src/media_streamer_node.c | 1 + 3 files changed, 1 insertion(+), 60 deletions(-) diff --git a/include/media_streamer_gst.h b/include/media_streamer_gst.h index 671f8da..50e809d 100644 --- a/include/media_streamer_gst.h +++ b/include/media_streamer_gst.h @@ -68,13 +68,6 @@ GstElement *__ms_bin_find_element_by_klass(GstElement *sink_bin, GstElement *pre GstPad *source_pad, const gchar *klass_name, const gchar *bin_name); /** - * @brief Creates GstElement by klass name. - * - * @since_tizen 3.0 - */ -GstElement *__ms_create_element_by_registry(GstPad *src_pad, const gchar *klass_name); - -/** * @brief Creates GstElement by plugin name. * * @since_tizen 3.0 diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index 89ba38d..444fdf8 100755 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -368,59 +368,6 @@ int __ms_factory_rank_compare(GstPluginFeature * first_feature, GstPluginFeature return (gst_plugin_feature_get_rank(second_feature) - gst_plugin_feature_get_rank(first_feature)); } -gboolean __ms_feature_filter(GstPluginFeature * feature, gpointer data) -{ - if (!GST_IS_ELEMENT_FACTORY(feature)) - return FALSE; - return TRUE; -} - -GstElement *__ms_create_element_by_registry(GstPad * src_pad, const gchar * klass_name) -{ - const GList *pads; - GstElement *next_element = NULL; - - GstCaps *new_pad_caps = gst_pad_query_caps(src_pad, NULL); - - GList *factories = gst_registry_feature_filter(gst_registry_get(), - (GstPluginFeatureFilter) __ms_feature_filter, FALSE, NULL); - factories = g_list_sort(factories, (GCompareFunc) __ms_factory_rank_compare); - GList *factories_iter = factories; - - for (; factories_iter != NULL; factories_iter = factories_iter->next) { - GstElementFactory *factory = GST_ELEMENT_FACTORY(factories_iter->data); - - if (g_strrstr(gst_element_factory_get_klass(GST_ELEMENT_FACTORY(factory)), klass_name)) { - for (pads = gst_element_factory_get_static_pad_templates(factory); pads != NULL; pads = pads->next) { - - GstCaps *intersect_caps = NULL; - GstCaps *static_caps = NULL; - GstStaticPadTemplate *pad_temp = pads->data; - - if (pad_temp->presence != GST_PAD_ALWAYS || pad_temp->direction != GST_PAD_SINK) - continue; - - if (GST_IS_CAPS(&pad_temp->static_caps.caps)) - static_caps = gst_caps_ref(pad_temp->static_caps.caps); - else - static_caps = gst_caps_from_string(pad_temp->static_caps.string); - - intersect_caps = gst_caps_intersect_full(new_pad_caps, static_caps, GST_CAPS_INTERSECT_FIRST); - - if (!gst_caps_is_empty(intersect_caps)) { - if (!next_element) - next_element = __ms_element_create(GST_OBJECT_NAME(factory), NULL); - } - gst_caps_unref(intersect_caps); - gst_caps_unref(static_caps); - } - } - } - gst_caps_unref(new_pad_caps); - gst_plugin_feature_list_free(factories); - return next_element; -} - GstElement *__ms_combine_next_element(GstElement *previous_element, GstPad *prev_elem_src_pad, GstElement *bin_to_find_in, media_streamer_node_type_e node_type) { if (!previous_element) diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 6443f0d..1b5b53e 100755 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -362,6 +362,7 @@ int __ms_src_node_create(media_streamer_node_s *node) case MEDIA_STREAMER_NODE_SRC_TYPE_CUSTOM: plugin_name = __ms_ini_get_string("node type 1:custom", DEFAULT_APP_SOURCE); node->gst_element = __ms_element_create(DEFAULT_APP_SOURCE, NULL); + g_object_set(G_OBJECT(node->gst_element), "emit-signals", TRUE, NULL); __ms_signal_create(&node->sig_list, node->gst_element, "need-data", G_CALLBACK(__ms_src_start_feed_cb), node); __ms_signal_create(&node->sig_list, node->gst_element, "enough-data", G_CALLBACK(__ms_src_stop_feed_cb), node); break; -- 2.7.4 From a46692eca227b7e6c82c7c92bb8423cf3ba88398 Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Mon, 20 Jun 2016 16:47:47 +0900 Subject: [PATCH 03/16] fix svace issue Change-Id: I837f6070aff96726f6862bcd2c71e60b7351a69f --- src/media_streamer_gst.c | 24 ++++++++++++++++++++---- src/media_streamer_node.c | 16 +++++++++++----- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index 89ba38d..76e5349 100755 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -691,9 +691,11 @@ static void __ms_rtpbin_pad_added_cb(GstElement * src, GstPad * new_pad, gpointe if (source_pad_name != NULL) { GstPad *source_pad = gst_element_get_static_pad(ms_node->gst_element, source_pad_name); - gst_ghost_pad_set_target(GST_GHOST_PAD(source_pad), new_pad); - if (__ms_sink_bin_prepare(ms_streamer, source_pad, src_pad_type)) { + if (source_pad) + gst_ghost_pad_set_target(GST_GHOST_PAD(source_pad), new_pad); + + if (source_pad && __ms_sink_bin_prepare(ms_streamer, source_pad, src_pad_type)) { __ms_element_set_state(ms_node->gst_element, GST_STATE_PLAYING); __ms_generate_dots(ms_streamer->pipeline, "rtpbin_playing"); } else { @@ -1274,6 +1276,12 @@ static GstPadProbeReturn __ms_element_event_probe(GstPad * pad, GstPadProbeInfo { GstElement *parent_element = gst_pad_get_parent_element(pad); GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info); + + if (!parent_element) { + ms_error("filed to get parent_elem"); + return GST_PAD_PROBE_PASS; + } + if (GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM) { if (GST_EVENT_TYPE(event) == GST_EVENT_BUFFERSIZE) { GValue *val_ = (GValue *) g_object_get_data(G_OBJECT(parent_element), "pad_sink"); @@ -1292,6 +1300,10 @@ void __ms_element_lock_state(const GValue *item, gpointer user_data) ms_retm_if(!sink_element, "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; + } 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); MS_SET_INT_PARAM(sink_element, "pad_sink", probe_id); @@ -1310,6 +1322,10 @@ void __ms_element_unlock_state(const GValue *item, gpointer user_data) 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; + } 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)); gst_pad_remove_probe(sink_pad, g_value_get_int(val)); @@ -1673,9 +1689,9 @@ int __ms_element_set_fmt(media_streamer_node_s *node, const char *pad_name, medi GstElementFactory *factory = gst_element_get_factory(node->gst_element); GstPad *node_pad = gst_element_get_static_pad(node->gst_element, pad_name); - if (GST_PAD_IS_SRC(node_pad)) + if (node_pad && GST_PAD_IS_SRC(node_pad)) can_accept = gst_element_factory_can_src_any_caps(factory, fmt_caps); - else if (GST_PAD_IS_SINK(node_pad)) + else if (node_pad && GST_PAD_IS_SINK(node_pad)) can_accept = gst_element_factory_can_sink_any_caps(factory, fmt_caps); else ms_error(" Node [%s] doesn`t have valid pad [%s]", node->name, pad_name); diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 6443f0d..50c45ff 100755 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -802,7 +802,7 @@ int __ms_node_get_param_list(media_streamer_node_s *node, GList **param_list) int __ms_node_get_param_value(media_streamer_node_s *node, param_s *param, char **string_value) { char *string_val = NULL; - GParamSpec *param_spec; + GParamSpec *param_spec = NULL; GValue value = G_VALUE_INIT; int ret = MEDIA_STREAMER_ERROR_NONE; @@ -811,11 +811,15 @@ int __ms_node_get_param_value(media_streamer_node_s *node, param_s *param, char ret = __ms_rtp_node_get_property(node, param, &value); else { param_spec = g_object_class_find_property(G_OBJECT_GET_CLASS(node->gst_element), param->origin_name); + if (param_spec) { + g_value_init(&value, param_spec->value_type); + g_object_get_property(G_OBJECT(node->gst_element), param->origin_name, &value); - g_value_init(&value, param_spec->value_type); - g_object_get_property(G_OBJECT(node->gst_element), param->origin_name, &value); - - ms_info("Got parameter [%s] for node [%s] with description [%s]", param->param_name, node->name, g_param_spec_get_blurb(param_spec)); + ms_info("Got parameter [%s] for node [%s] with description [%s]", param->param_name, node->name, g_param_spec_get_blurb(param_spec)); + } else { + ms_error("There is no parameter [%s] for node [%s]", param->origin_name, node->name); + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + } } if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_CAMERA_ID)) @@ -894,6 +898,8 @@ int __ms_node_uri_path_check(const char *file_uri) if (EACCES == errno) return MEDIA_STREAMER_ERROR_PERMISSION_DENIED; + + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; } if (fstat(file_open, &stat_results) < 0) { -- 2.7.4 From 0160ec76bf67a30e5695dcf64536a76e015d53b4 Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Tue, 5 Jul 2016 10:36:46 +0900 Subject: [PATCH 04/16] fix svace issue Change-Id: Ifdf71e836967ca6d439160cb2c4bae3e5775a4b9 --- packaging/capi-media-streamer.spec | 2 +- src/media_streamer_gst.c | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) mode change 100755 => 100644 src/media_streamer_gst.c diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 2d80ef8..8430faa 100755 --- 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.4 +Version: 0.1.5 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c old mode 100755 new mode 100644 index 3caba9e..7bfb032 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -1745,6 +1745,12 @@ int __ms_element_pull_packet(GstElement *sink_element, media_packet_h *packet) GstMapInfo map; guint8 *buffer_res = NULL; GstBuffer *buffer = gst_sample_get_buffer(sample); + if (!buffer) { + ms_error("Failed to get buffer from sample"); + media_format_unref(fmt); + gst_sample_unref(sample); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } gst_buffer_map(buffer, &map, GST_MAP_READ); buffer_res = (guint8 *) malloc(map.size * sizeof(guint8)); @@ -1755,8 +1761,6 @@ int __ms_element_pull_packet(GstElement *sink_element, media_packet_h *packet) media_packet_set_pts(*packet, GST_BUFFER_PTS(buffer)); media_packet_set_dts(*packet, GST_BUFFER_DTS(buffer)); media_packet_set_pts(*packet, GST_BUFFER_DURATION(buffer)); - - media_format_unref(fmt); } else { ms_error("Error allocation memory for packet data"); ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; @@ -1764,6 +1768,7 @@ int __ms_element_pull_packet(GstElement *sink_element, media_packet_h *packet) gst_buffer_unmap(buffer, &map); } + media_format_unref(fmt); gst_sample_unref(sample); return ret; } -- 2.7.4 From 714d1d4b8dbd5e0fbf6e78e1cf03838cd7f98ad0 Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Fri, 8 Jul 2016 17:42:06 +0900 Subject: [PATCH 05/16] make right return of the set_params Change-Id: I61494561481d0575012e6fc49382d89a1448ab6b --- packaging/capi-media-streamer.spec | 2 +- src/media_streamer.c | 1 - src/media_streamer_node.c | 14 ++++++++++---- 3 files changed, 11 insertions(+), 6 deletions(-) mode change 100755 => 100644 packaging/capi-media-streamer.spec mode change 100755 => 100644 src/media_streamer_node.c diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec old mode 100755 new mode 100644 index 8430faa..0aeaa64 --- 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.5 +Version: 0.1.6 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/media_streamer.c b/src/media_streamer.c index 7a12e33..8bd592f 100644 --- a/src/media_streamer.c +++ b/src/media_streamer.c @@ -655,7 +655,6 @@ int media_streamer_node_set_params(media_streamer_node_h node, bundle *param_lis ms_retvm_if(param_list == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Parameters list is NULL"); ret = __ms_node_set_params_from_bundle(ms_node, param_list); - ms_retvm_if(ret != MEDIA_STREAMER_ERROR_NONE, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Parameters list is NULL"); return ret; } diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c old mode 100755 new mode 100644 index b45b142..51221f9 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -725,15 +725,21 @@ int __ms_node_set_params_from_bundle(media_streamer_node_s *node, bundle *param_ char *string_val = NULL; for (list_iter = p_list; list_iter != NULL; list_iter = list_iter->next) { param = (param_s *)list_iter->data; - if (bundle_get_str(param_list, param->param_name, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE - && __ms_node_set_param_value(node, param, string_val) == MEDIA_STREAMER_ERROR_NONE) - written_count++; + if (bundle_get_str(param_list, param->param_name, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + ret = __ms_node_set_param_value(node, param, string_val); + if (ret == MEDIA_STREAMER_ERROR_NONE) { + written_count++; + } else { + ms_error("failed to set param"); + break; + } + } } } g_list_free(p_list); ms_info("Set [%d] parameters of [%d]", written_count, bundle_get_count(param_list)); - if (written_count == 0) + if (ret == MEDIA_STREAMER_ERROR_NONE && written_count == 0) ret = MEDIA_STREAMER_ERROR_INVALID_PARAMETER; return ret; -- 2.7.4 From 1fb960bedf11a6a480f7bd51c6ce4c174523c710 Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Fri, 8 Jul 2016 18:52:44 +0900 Subject: [PATCH 06/16] add null check before free Change-Id: I95281ae952837310210e9185df568a92c002cfec --- src/media_streamer_node.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 51221f9..fa8dd59 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -764,7 +764,8 @@ int __ms_node_write_params_into_bundle(media_streamer_node_s *node, bundle *para } } } - g_list_free(p_list); + if (p_list) + g_list_free(p_list); return ret; } -- 2.7.4 From b922a3ee2f55d6bb08a2bc46a720afc402e867d0 Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Tue, 12 Jul 2016 13:49:13 +0900 Subject: [PATCH 07/16] fix svace issue Change-Id: Ie021f598a90c3551958155b197060f92e8a2e64b --- packaging/capi-media-streamer.spec | 2 +- src/media_streamer_gst.c | 43 +++++++++++++++++++------------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 0aeaa64..d0c2ad1 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.6 +Version: 0.1.7 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index 7bfb032..80d5ef6 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -1390,29 +1390,30 @@ int __ms_pipeline_create(media_streamer_s *ms_streamer) int *argc = (int *)malloc(sizeof(int)); char **argv = NULL; - if (argc) { - *argc = 1; - if (ms_streamer->ini.gst_args) - (*argc) += g_strv_length(ms_streamer->ini.gst_args); - - argv = (char **)calloc(*argc, sizeof(char*)); - if (argv) { - argv[0] = g_strdup("MediaStreamer"); - - if (ms_streamer->ini.gst_args) { - int i = 0; - for ( ; ms_streamer->ini.gst_args[i]; ++i) { - argv[i+1] = ms_streamer->ini.gst_args[i]; - ms_debug("Add [%s] gstreamer parameter.", argv[i+1]); - } - } + if (!argc) { + ms_error("Error allocation memory"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } - } else { - MS_SAFE_FREE(argc); - ms_error("Error allocation memory"); - } - } else { + *argc = 1; + if (ms_streamer->ini.gst_args) + (*argc) += g_strv_length(ms_streamer->ini.gst_args); + + argv = (char **)calloc(*argc, sizeof(char*)); + if (!argv) { + MS_SAFE_FREE(argc); ms_error("Error allocation memory"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + argv[0] = g_strdup("MediaStreamer"); + + if (ms_streamer->ini.gst_args) { + int i = 0; + for ( ; ms_streamer->ini.gst_args[i]; ++i) { + argv[i+1] = ms_streamer->ini.gst_args[i]; + ms_debug("Add [%s] gstreamer parameter.", argv[i+1]); + } } gboolean gst_ret = gst_init_check(argc, &argv, &err); -- 2.7.4 From d6df69300cda52408bbba5b0d5e58c5b7dc09310 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Wed, 31 Aug 2016 11:48:54 +0300 Subject: [PATCH 08/16] fix issue with VoIP client pipeline linkage. HTTP streaming file existence check Change-Id: If12508c7bf5d0f711ca84c331a3afbba1d82ad84 Signed-off-by: Volodymyr Brynza --- include/media_streamer_gst.h | 2 +- src/media_streamer_gst.c | 30 +++++++++++++++++++++--------- src/media_streamer_node.c | 8 +++++++- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/include/media_streamer_gst.h b/include/media_streamer_gst.h index 50e809d..26a6cc1 100644 --- a/include/media_streamer_gst.h +++ b/include/media_streamer_gst.h @@ -147,7 +147,7 @@ const gchar *__ms_get_pad_type(GstPad *element_pad); * * @since_tizen 3.0 */ -GstElement *__ms_decodebin_create(media_streamer_s *ms_streamer); +GstElement *__ms_decodebin_create(media_streamer_s *ms_streamer, char * name); /** * @brief Creates next element by klass or by properties and links with the previous one. diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index 80d5ef6..4d2f53c 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -23,6 +23,7 @@ #define H264_PARSER_CONFIG_INTERVAL 5 #define H264_ENCODER_ZEROLATENCY 0x00000004 +#define MEDIASTREAMER_DECODEBIN_TYPE_DECODER "video_decoder" void __ms_generate_dots(GstElement *bin, gchar *name_tag) { @@ -491,6 +492,7 @@ static void __decodebin_nomore_pads_combine(GstPad *src_pad, media_streamer_s *m { GstElement *found_element = gst_pad_get_parent_element(src_pad); const gchar *new_pad_type = __ms_get_pad_type(src_pad); + if (MS_ELEMENT_IS_VIDEO(new_pad_type)) { if (__ms_bin_find_element_by_type(found_element, src_pad, ms_streamer->topology_bin, __ms_node_get_klass_by_its_type(MEDIA_STREAMER_NODE_TYPE_TEXT_OVERLAY))) { found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_TEXT_OVERLAY); @@ -517,6 +519,7 @@ static void __decodebin_nomore_pads_combine(GstPad *src_pad, media_streamer_s *m } else { ms_error("Unsupported pad type [%s]!", new_pad_type); } + __ms_generate_dots(ms_streamer->pipeline, "after_sink_linked"); gst_object_unref(found_element); } @@ -531,14 +534,23 @@ static void __decodebin_nomore_pads_cb(GstElement *decodebin, gpointer user_data gboolean is_server_part = FALSE; media_streamer_node_s *rtp_node = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "rtp_container"); - /* It`s server part of Streaming Scenario*/ if (rtp_node) { - char *param_value = NULL; - media_streamer_node_get_param(rtp_node, MEDIA_STREAMER_PARAM_VIDEO_OUT_PORT, ¶m_value); - if (param_value && (strtol(param_value, NULL, 10) > 0)) - is_server_part = TRUE; + char *decodebin_name = NULL; + g_object_get(G_OBJECT(decodebin), "name", &decodebin_name, NULL); - MS_SAFE_FREE(param_value); + /* FIXME: This case may be not general */ + if (g_strrstr(decodebin_name, MEDIASTREAMER_DECODEBIN_TYPE_DECODER)) { + is_server_part = FALSE; + MS_SAFE_FREE(decodebin_name); + } else { + /* It`s server part of Streaming Scenario*/ + char *param_value = NULL; + media_streamer_node_get_param(rtp_node, MEDIA_STREAMER_PARAM_VIDEO_OUT_PORT, ¶m_value); + if (param_value && (strtol(param_value, NULL, 10) > 0)) + is_server_part = TRUE; + + MS_SAFE_FREE(param_value); + } } GList *iterator = NULL; @@ -551,11 +563,11 @@ static void __decodebin_nomore_pads_cb(GstElement *decodebin, gpointer user_data g_mutex_unlock(&ms_streamer->mutex_lock); } -GstElement *__ms_decodebin_create(media_streamer_s * ms_streamer) +GstElement *__ms_decodebin_create(media_streamer_s * ms_streamer, char * name) { ms_retvm_if(!ms_streamer, NULL, "Handle is NULL"); - GstElement *decodebin = __ms_element_create(DEFAULT_DECODEBIN, NULL); + GstElement *decodebin = __ms_element_create(DEFAULT_DECODEBIN, name); __ms_bin_add_element(ms_streamer->topology_bin, decodebin, TRUE); gst_element_sync_state_with_parent(decodebin); @@ -581,7 +593,7 @@ static gboolean __ms_sink_bin_prepare(media_streamer_s * ms_streamer, GstPad * s if (!decoder_element) { if (ms_streamer->ini.use_decodebin) { - decoder_element = __ms_decodebin_create(ms_streamer); + decoder_element = __ms_decodebin_create(ms_streamer, MEDIASTREAMER_DECODEBIN_TYPE_DECODER); gst_object_ref(found_element); __ms_link_two_elements(found_element, NULL, decoder_element); MS_SAFE_UNREF(decoder_element); diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index fa8dd59..ff86275 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -22,6 +22,7 @@ #include #define SMACK_LABEL_LEN 255 +#define DEFAULT_URI_SCHEME_LENGTH 10 param_s param_table[] = { {MEDIA_STREAMER_PARAM_CAMERA_ID, "camera-id"}, @@ -569,7 +570,7 @@ static void _src_node_prepare(const GValue *item, gpointer user_data) GstElement *found_element = NULL; if (__ms_src_need_typefind(src_pad)) { - found_element = __ms_decodebin_create(ms_streamer); + found_element = __ms_decodebin_create(ms_streamer, NULL); __ms_link_two_elements(src_element, src_pad, found_element); MS_SAFE_UNREF(src_element); } else { @@ -898,6 +899,11 @@ int __ms_node_uri_path_check(const char *file_uri) if (!file_uri || !strlen(file_uri)) return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + /* We can not check wheter the content is available over http or other protocol + * Thus, here we have to check occurence of :// */ + if (g_strrstr_len(file_uri, DEFAULT_URI_SCHEME_LENGTH, "://")) + return MEDIA_STREAMER_ERROR_NONE; + file_open = open(file_uri, O_RDONLY); if (file_open < 0) { char mes_error[256]; -- 2.7.4 From 6507c269815faa69ffb21be404d2ea66b6c5173f Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Tue, 30 Aug 2016 13:57:03 +0300 Subject: [PATCH 09/16] Adaptive streaming client basic implementation Change-Id: Ia5f29a521f4d3838fa36d4107bc518aac5dcd4ce Signed-off-by: Volodymyr Brynza --- include/media_streamer.h | 9 +- include/media_streamer_gst.h | 28 +++++ include/media_streamer_util.h | 10 ++ src/media_streamer_gst.c | 230 ++++++++++++++++++++++++++++++++++++++++++ src/media_streamer_node.c | 135 +++++++++++++++++-------- src/media_streamer_util.c | 41 ++++++++ test/media_streamer_test.c | 180 ++++++++++++++++++++++++++++++++- 7 files changed, 582 insertions(+), 51 deletions(-) diff --git a/include/media_streamer.h b/include/media_streamer.h index dfc3cf6..6275c69 100644 --- a/include/media_streamer.h +++ b/include/media_streamer.h @@ -102,7 +102,8 @@ typedef enum { MEDIA_STREAMER_NODE_SRC_TYPE_VIDEO_CAPTURE, /**< Video capture src type, Camera feature is required */ 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_CUSTOM, /**< Custom src type */ + MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE /**< Adaptive src type */ } media_streamer_node_src_type_e; /** @@ -1063,7 +1064,7 @@ int media_streamer_node_get_pad_format(media_streamer_node_h node, const char *p * @brief Gets name of node pads. * @since_tizen 3.0 * @remark After using the src_pad_name and sink_pad_name, it have to be free. - * src_pad_name or sink_pad_name can be null accoring to the node type. + * src_pad_name or sink_pad_name can be null according to the node type. * In case of src type node, sink_pad_name will be null. * In case of sink type node, src_pad_name will be null. * @param [in] node Media streamer node handle @@ -1139,7 +1140,7 @@ int media_streamer_node_get_params(media_streamer_node_h node, bundle **param_li * The externalstorage privilege(http://tizen.org/privilege/externalstorage) should be added if any video/audio files are written in the external storage devices. * @param [in] node Media streamer node handle * @param [in] param_name Param name of node - * @param [in] param_value Parm value of node + * @param [in] param_value Param value of node * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful @@ -1165,7 +1166,7 @@ int media_streamer_node_set_param(media_streamer_node_h node, * @since_tizen 3.0 * @param [in] node Media streamer node handle * @param [in] param_name Param name of node - * @param [out] param_value Parm value of node + * @param [out] param_value Param value of node * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful diff --git a/include/media_streamer_gst.h b/include/media_streamer_gst.h index 26a6cc1..dbccb31 100644 --- a/include/media_streamer_gst.h +++ b/include/media_streamer_gst.h @@ -75,6 +75,20 @@ GstElement *__ms_bin_find_element_by_klass(GstElement *sink_bin, GstElement *pre GstElement *__ms_element_create(const char *plugin_name, const char *name); /** + * @brief Creates GstBin name for adaptive streaming. + * + * @since_tizen 3.0 + */ +GstElement *__ms_adaptive_element_create(void); + +/** + * @brief Prepares GstBin for adaptive streaming. + * + * @since_tizen 3.0 + */ +int __ms_adaptive_element_prepare(media_streamer_node_s *ms_node, bool auto_plug); + +/** * @brief Creates GstElement from specified node_plug_s structure. * * @since_tizen 3.0 @@ -103,6 +117,13 @@ GstElement *__ms_video_decoder_element_create(node_plug_s *plug_info, media_stre GstElement *__ms_audio_encoder_element_create(node_plug_s *plug_info, media_streamer_node_type_e type); /** + * @brief Creates audio decoder GstElement. + * + * @since_tizen 3.0 + */ +GstElement *__ms_audio_decoder_element_create(node_plug_s *plug_info, media_streamer_node_type_e type); + +/** * @brief Creates rtp container GstElement. * * @since_tizen 3.0 @@ -246,3 +267,10 @@ int __ms_element_push_packet(GstElement *src_element, media_packet_h packet); * @since_tizen 3.0 */ int __ms_element_pull_packet(GstElement *sink_element, media_packet_h *packet); + +/** + * @brief Prepare demuxer elemetn for playing. + * + * @since_tizen 3.0 + */ +int __ms_demux_element_prepare(media_streamer_s *ms_streamer, media_streamer_node_s *demux_node); diff --git a/include/media_streamer_util.h b/include/media_streamer_util.h index 01ecb96..74de8ba 100644 --- a/include/media_streamer_util.h +++ b/include/media_streamer_util.h @@ -183,6 +183,9 @@ typedef struct { #define DEFAULT_AUDIO_RTPPAY "rtpamrpay" #define DEFAULT_AUDIO_RTPDEPAY "rtpamrdepay" +/* adaptive streaming default */ +#define DEFAULT_ADAPTIVE_SOURCE "hlsdemux" + #define MEDIA_STREAMER_DEFAULT_CAMERA_FORMAT "video/x-raw,format=I420,width=352,height=288" #define MEDIA_STREAMER_DEFAULT_AUDIO_RAW_FORMAT "audio/x-raw,channels=1,rate=8000,format=S16LE" #define MEDIA_STREAMER_DEFAULT_VIDEO_FORMAT "video/x-h263,width=352,height=288,framerate = 3/1" @@ -330,6 +333,13 @@ void __ms_signal_destroy(void *data); */ void __ms_param_value_destroy(gpointer data); +/** + * @brief Check URI is valid file + * + * @since_tizen 3.0 + */ +int __ms_node_uri_path_check(const char *file_uri); + #ifdef __cplusplus } #endif diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index 4d2f53c..dd3e0d0 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -454,6 +454,7 @@ static gint __decodebin_autoplug_select_cb(GstElement * bin, GstPad * pad, GstCa return GST_AUTOPLUG_SELECT_SKIP; } } + } return result; @@ -695,6 +696,116 @@ GstElement *__ms_element_create(const char *plugin_name, const char *name) return plugin_elem; } +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); +} + +GstElement *__ms_adaptive_element_create(void) +{ + GstElement *adaptive_bin = gst_bin_new("adaptive_src"); + ms_retvm_if(!adaptive_bin, (GstElement *) NULL, "Error: creating elements for adaptive source"); + + __ms_add_no_target_ghostpad(adaptive_bin, "src", GST_PAD_SRC); + + /* Add adaptive node parameters as GObject data with destroy function */ + MS_SET_INT_STATIC_STRING_PARAM(adaptive_bin, MEDIA_STREAMER_PARAM_URI, "http://localhost"); + + return adaptive_bin; +} + +static GstElement *__ms_manifest_src_create(media_streamer_node_s *ms_node) +{ + char *manifest_src_name = NULL; + gchar *location = NULL; + GstElement *manifest_src = NULL; + + GValue *val = (GValue *)g_object_get_data(G_OBJECT(ms_node->gst_element), MEDIA_STREAMER_PARAM_URI); + const char *uri = g_value_get_string(val); + gchar *protocol = gst_uri_is_valid(uri) ? gst_uri_get_protocol(uri) : NULL; + + if (protocol && g_strrstr(protocol, "http")) { + manifest_src_name = __ms_ini_get_string("node type 1:http", DEFAULT_HTTP_SOURCE); + location = g_strdup(uri); + } else if (protocol && g_strrstr(protocol, "file")) { + manifest_src_name = __ms_ini_get_string("node type 1:file", DEFAULT_FILE_SOURCE); + location = gst_uri_get_location(uri); + } else { + ms_error("Unsupported URI protocol... Check URI is file path"); + if (__ms_node_uri_path_check(uri) == MEDIA_STREAMER_ERROR_NONE) { + manifest_src_name = __ms_ini_get_string("node type 1:file", DEFAULT_FILE_SOURCE); + location = g_strdup(uri); + } else { + g_free(protocol); + ms_error("URI is not valid file path"); + return NULL; + } + } + g_free(protocol); + ms_retvm_if(manifest_src_name == NULL, NULL, + "Error empty manifest source name for adaprive source"); + manifest_src = gst_element_factory_make(manifest_src_name, NULL); + ms_retvm_if(manifest_src == NULL, NULL, + "Error creating manifest source for adaptive source"); + g_object_set(manifest_src, "location", location, NULL); + g_free(location); + + return manifest_src; +} + +int __ms_adaptive_element_prepare(media_streamer_node_s *ms_node, bool auto_plug) +{ + char *plugin_name = NULL; + GstElement *manifest_src = NULL; + GstElement *plugin_elem = NULL; + gboolean res = FALSE; + GstPad *gp = NULL; + + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + if (!auto_plug) { + plugin_name = __ms_ini_get_string("node type 1:adaptive", DEFAULT_ADAPTIVE_SOURCE); + ms_retvm_if(plugin_name == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Error empty plugin name for adaprive source"); + ms_info("Creating [%s] element", plugin_name); + plugin_elem = gst_element_factory_make(plugin_name, NULL); + ms_retvm_if(plugin_elem == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, + "Error creating element [%s] for adaptive source", plugin_name); + + res = gst_bin_add(GST_BIN(ms_node->gst_element), plugin_elem); + ms_retvm_if(res == FALSE, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, + "Error adding adaptive element to bin for adaptive source"); + } + + manifest_src = __ms_manifest_src_create(ms_node); + ms_retvm_if(manifest_src == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, + "Error creating manifest source for adaptive source"); + + res = gst_bin_add(GST_BIN(ms_node->gst_element), manifest_src); + ms_retvm_if(res == FALSE, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, + "Error adding manifest source to bin for adaptive source"); + + if (!auto_plug) { + res = gst_element_link(manifest_src, plugin_elem); + ms_retvm_if(res == FALSE, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, + "Error linking manifest source and element for adaptive source"); + } + + gp = gst_element_get_static_pad(ms_node->gst_element, "src"); + ms_retvm_if(gp == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, + "Error getting source pad for adaptive source"); + + if (!auto_plug) { + g_signal_connect_object(plugin_elem, "pad-added", + 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); + } + + return MEDIA_STREAMER_ERROR_NONE; +} + static gboolean __ms_feature_node_filter(GstPluginFeature *feature, gpointer data) { node_plug_s *plug_info = (node_plug_s*)data; @@ -825,6 +936,8 @@ GstElement *__ms_node_element_create(node_plug_s *plug_info, media_streamer_node * element will be created immediately by format ot name */ if (type == MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER) gst_element = __ms_audio_encoder_element_create(plug_info, type); + else if (type == MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER) + gst_element = __ms_audio_decoder_element_create(plug_info, type); else if (type == MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER) gst_element = __ms_video_encoder_element_create(plug_info, type); else if (type == MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER) @@ -1027,6 +1140,60 @@ GstElement *__ms_audio_encoder_element_create(node_plug_s *plug_info, media_stre return audio_enc_bin; } +GstElement *__ms_audio_decoder_element_create(node_plug_s *plug_info, media_streamer_node_type_e type) +{ + GstCaps *dec_caps = plug_info->sink_caps; + if (!dec_caps) { + dec_caps = gst_caps_from_string(MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT); + ms_debug("No Audio decoding format is set! Deafault will be: [%s]", MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT); + } + + /* Creating Audio Decoder */ + node_info_s *node_klass_type = __ms_node_get_klass_by_its_type(type); + node_plug_s decoder_info = {node_klass_type, plug_info->src_caps, dec_caps, NULL}; + GstElement *decoder_elem = __ms_element_create_from_ini(&decoder_info, MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER); + if (!decoder_elem) + decoder_elem = __ms_element_create_by_registry(&decoder_info, MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER); + + /* Creating Audio Parser */ + node_info_s nodes_info = {MEDIA_STREAMER_PARSER_KLASS, DEFAULT_AUDIO_PARSER}; + node_plug_s parser_info = {&nodes_info, dec_caps, dec_caps, NULL}; + GstElement *decoder_parser = __ms_element_create_from_ini(&parser_info, MEDIA_STREAMER_NODE_TYPE_PARSER); + if (!decoder_parser) + decoder_parser = __ms_element_create_by_registry(&parser_info, MEDIA_STREAMER_NODE_TYPE_PARSER); + + /* Creating bin - Audio Decoder */ + gboolean gst_ret = FALSE; + GstElement *decoder_bin = gst_bin_new("audio_decoder"); + GstElement *decoder_queue = __ms_element_create("queue", NULL); + ms_retvm_if(!decoder_elem || !decoder_queue || !decoder_bin || !decoder_parser, (GstElement *) NULL, "Error: creating elements for audio decoder bin"); + + /* Adding elements to bin Audio Encoder */ + gst_bin_add_many(GST_BIN(decoder_bin), decoder_queue, decoder_elem, decoder_parser, NULL); + gst_ret = gst_element_link_many(decoder_queue, decoder_parser, decoder_elem, NULL); + if (gst_ret != TRUE) { + ms_error("Failed to link elements into decoder_bin"); + MS_SAFE_UNREF(decoder_bin); + return NULL; + } + + GstElement *audio_conv = __ms_element_create("audioconvert", NULL); + GstElement *audio_resample = __ms_element_create("audioresample", NULL); + ms_retvm_if(!audio_conv || !audio_resample, (GstElement *) NULL, "Error: creating elements for audio decoder bin"); + gst_bin_add_many(GST_BIN(decoder_bin), audio_conv, audio_resample, NULL); + gst_ret = gst_element_link_many(decoder_elem, audio_conv, audio_resample, NULL); + if (gst_ret != TRUE) { + ms_error("Failed to link elements into decoder_bin"); + MS_SAFE_UNREF(decoder_bin); + return NULL; + } + + __ms_add_ghostpad(audio_resample, "src", decoder_bin, "src"); + __ms_add_ghostpad(decoder_queue, "sink", decoder_bin, "sink"); + + return decoder_bin; +} + GstElement *__ms_rtp_element_create(void) { GstElement *rtp_container = gst_bin_new("rtp_container"); @@ -1491,6 +1658,11 @@ GstCaps *__ms_create_caps_from_fmt(media_format_h fmt) caps_name = gst_caps_to_string(caps); ms_info("Creating Video Caps from media format [%s]", caps_name); + } else if (!media_format_get_container_mime(fmt, &mime)) { + caps = gst_caps_new_empty_simple(__ms_convert_mime_to_string_format(mime)); + caps_name = gst_caps_to_string(caps); + ms_info("Creating Video Caps from media format [%s]", caps_name); + } else ms_error("Error getting media format information"); @@ -1785,3 +1957,61 @@ int __ms_element_pull_packet(GstElement *sink_element, media_packet_h *packet) gst_sample_unref(sample); return ret; } + +static void __demux_newpad_cb(GstElement * demux, GstPad * new_pad, gpointer user_data) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) user_data; + ms_retm_if(ms_streamer == NULL, "Handle is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + g_object_ref(new_pad); + ms_streamer->pads_types_list = g_list_insert_sorted(ms_streamer->pads_types_list, new_pad, __pad_type_compare); + + g_mutex_unlock(&ms_streamer->mutex_lock); +} + +static void __demux_nomore_pads_combine(GstPad *src_pad, media_streamer_s *ms_streamer) +{ + GstElement *found_element = gst_pad_get_parent_element(src_pad); + const gchar *new_pad_type = __ms_get_pad_type(src_pad); + if (MS_ELEMENT_IS_VIDEO(new_pad_type)) { + found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER); + } else if (MS_ELEMENT_IS_AUDIO(new_pad_type)) { + found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER); + } else if (MS_ELEMENT_IS_TEXT(new_pad_type)) { + found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_TEXT_OVERLAY); + } else { + ms_error("Unsupported pad type [%s]!", new_pad_type); + } + __ms_generate_dots(ms_streamer->pipeline, "after_demux_linked"); + gst_object_unref(found_element); +} + +static void __demux_nomore_pads_cb(GstElement *demux, gpointer user_data) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) user_data; + ms_retm_if(ms_streamer == NULL, "Handle is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + GList *iterator = NULL; + GList *list = ms_streamer->pads_types_list; + for (iterator = list; iterator; iterator = iterator->next) { + GstPad *src_pad = GST_PAD(iterator->data); + __demux_nomore_pads_combine(src_pad, ms_streamer); + } + + g_mutex_unlock(&ms_streamer->mutex_lock); +} + +int __ms_demux_element_prepare(media_streamer_s * ms_streamer, media_streamer_node_s *demux_node) +{ + ms_retvm_if(!ms_streamer, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(!demux_node, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + __ms_signal_create(&ms_streamer->autoplug_sig_list, demux_node->gst_element, "pad-added", G_CALLBACK(__demux_newpad_cb), ms_streamer); + __ms_signal_create(&ms_streamer->autoplug_sig_list, demux_node->gst_element, "no-more-pads", G_CALLBACK(__demux_nomore_pads_cb), ms_streamer); + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index ff86275..0ca0464 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -17,8 +17,6 @@ #include #include #include -#include -#include #include #define SMACK_LABEL_LEN 255 @@ -168,6 +166,62 @@ static int __ms_rtp_node_set_property(media_streamer_node_s *ms_node, param_s *p return ret; } +static gboolean __ms_adaptive_src_node_has_property(media_streamer_node_s *ms_node, const char * param_name) +{ + ms_retvm_if(!ms_node || !ms_node->gst_element, FALSE, "Error: empty node"); + ms_retvm_if(!param_name, FALSE, "Error: invalid property parameter"); + + if (ms_node->type == MEDIA_STREAMER_NODE_TYPE_SRC && + ms_node->subtype == MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE) { + GValue *val = (GValue *)g_object_get_data(G_OBJECT(ms_node->gst_element), param_name); + return val ? TRUE : FALSE; + } + + return FALSE; +} + +static int __ms_adaptive_src_node_get_property(media_streamer_node_s *ms_node, param_s *param, GValue *value) +{ + ms_retvm_if(!ms_node || !ms_node->gst_element, FALSE, "Error: empty node"); + ms_retvm_if(ms_node->type != MEDIA_STREAMER_NODE_TYPE_SRC && + ms_node->subtype != MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Invalid node type"); + ms_retvm_if(!param, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Error: invalid property parameter"); + + int ret = MEDIA_STREAMER_ERROR_NONE; + + GValue *val = (GValue *)g_object_get_data(G_OBJECT(ms_node->gst_element), param->param_name); + if (!strcmp(param->param_name, MEDIA_STREAMER_PARAM_URI)) + g_value_init(value, G_TYPE_STRING); + else + ret = MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + + g_value_copy(val, value); + return ret; +} + +static int __ms_adaptive_src_node_set_property(media_streamer_node_s *ms_node, param_s *param, const char *param_value) +{ + ms_retvm_if(!ms_node || !ms_node->gst_element, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error: empty node"); + ms_retvm_if(ms_node->type != MEDIA_STREAMER_NODE_TYPE_SRC && + ms_node->subtype != MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Invalid node type"); + ms_retvm_if(!param, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Error: invalid property parameter"); + + int ret = MEDIA_STREAMER_ERROR_NONE; + + GValue *val = (GValue *)g_object_get_data(G_OBJECT(ms_node->gst_element), param->param_name); + if (!val) + ret = MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + + if (!strcmp(param->param_name, MEDIA_STREAMER_PARAM_URI)) { + g_value_unset(val); + g_value_init(val, G_TYPE_STRING); + g_value_set_string(val, param_value); + } else + ret = MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + + return ret; +} + int __ms_node_create(media_streamer_node_s *node, media_format_h in_fmt, media_format_h out_fmt) { ms_retvm_if(node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); @@ -235,6 +289,9 @@ static int __ms_node_check_priveleges(media_streamer_node_s *node) case MEDIA_STREAMER_NODE_SRC_TYPE_HTTP: privilege = "http://tizen.org/privilege/internet"; break; + case MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE: + privilege = "http://tizen.org/privilege/internet"; + break; case MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA: privilege = "http://tizen.org/privilege/camera"; break; @@ -367,6 +424,9 @@ int __ms_src_node_create(media_streamer_node_s *node) __ms_signal_create(&node->sig_list, node->gst_element, "need-data", G_CALLBACK(__ms_src_start_feed_cb), node); __ms_signal_create(&node->sig_list, node->gst_element, "enough-data", G_CALLBACK(__ms_src_stop_feed_cb), node); break; + case MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE: + node->gst_element = __ms_adaptive_element_create(); + break; default: ms_error("Error: invalid Src node Type [%d]", node->subtype); break; @@ -604,14 +664,22 @@ 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) { + return g_strrstr((char *)key, "demux") != NULL; +} + int __ms_pipeline_prepare(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; media_streamer_node_s *rtp_node = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "rtp_container"); + media_streamer_node_s *demux = (media_streamer_node_s *)g_hash_table_find(ms_streamer->nodes_table, (GHRFunc)demux_find, NULL); + media_streamer_node_s *adaptive_src = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "adaptive_src"); 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; } else { GstBin *nodes_bin = GST_BIN(ms_streamer->src_bin); if (nodes_bin->numchildren == 0) { @@ -625,6 +693,14 @@ int __ms_pipeline_prepare(media_streamer_s *ms_streamer) } } + if (adaptive_src) { + if (GST_BIN(ms_streamer->topology_bin)->numchildren == 0) { + ret = __ms_adaptive_element_prepare(adaptive_src, true); + } 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); @@ -780,7 +856,8 @@ int __ms_node_get_param(media_streamer_node_s *node, const char *param_name, par for (it_param = 0; param_table[it_param].param_name != NULL; it_param++) { if (!g_strcmp0(param_name, param_table[it_param].param_name)) { param_spec = g_object_class_find_property(G_OBJECT_GET_CLASS(node->gst_element), param_table[it_param].origin_name); - if (param_spec || __ms_rtp_node_has_property(node, param_name)) { + if (param_spec || __ms_rtp_node_has_property(node, param_table[it_param].origin_name) || + __ms_adaptive_src_node_has_property(node, param_table[it_param].origin_name)) { *param = &(param_table[it_param]); ms_info("Got parameter [%s] for node [%s]", (*param)->param_name, node->name); found_param = TRUE; @@ -799,7 +876,8 @@ int __ms_node_get_param_list(media_streamer_node_s *node, GList **param_list) for (it_param = 0; param_table[it_param].param_name != NULL; it_param++) { param_spec = g_object_class_find_property(G_OBJECT_GET_CLASS(node->gst_element), param_table[it_param].origin_name); - if (param_spec || __ms_rtp_node_has_property(node, param_table[it_param].param_name)) { + if (param_spec || __ms_rtp_node_has_property(node, param_table[it_param].origin_name) || + __ms_adaptive_src_node_has_property(node, param_table[it_param].origin_name)) { ms_info("Got parameter [%s] for node [%s]", param_table[it_param].param_name, node->name); *param_list = g_list_append(*param_list, &(param_table[it_param])); } @@ -818,6 +896,9 @@ int __ms_node_get_param_value(media_streamer_node_s *node, param_s *param, char if (node->type == MEDIA_STREAMER_NODE_TYPE_RTP) ret = __ms_rtp_node_get_property(node, param, &value); + else if (node->type == MEDIA_STREAMER_NODE_TYPE_SRC && + node->subtype == MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE) + ret = __ms_adaptive_src_node_get_property(node, param, &value); else { param_spec = g_object_class_find_property(G_OBJECT_GET_CLASS(node->gst_element), param->origin_name); if (param_spec) { @@ -891,46 +972,6 @@ int __ms_node_get_param_value(media_streamer_node_s *node, param_s *param, char return ret; } -int __ms_node_uri_path_check(const char *file_uri) -{ - struct stat stat_results = {0, }; - int file_open = 0; - - if (!file_uri || !strlen(file_uri)) - return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; - - /* We can not check wheter the content is available over http or other protocol - * Thus, here we have to check occurence of :// */ - if (g_strrstr_len(file_uri, DEFAULT_URI_SCHEME_LENGTH, "://")) - return MEDIA_STREAMER_ERROR_NONE; - - file_open = open(file_uri, O_RDONLY); - if (file_open < 0) { - char mes_error[256]; - strerror_r(errno, mes_error, sizeof(mes_error)); - ms_error("Couldn`t open file according to [%s]. Error N [%d]", mes_error, errno); - - if (EACCES == errno) - return MEDIA_STREAMER_ERROR_PERMISSION_DENIED; - - return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; - } - - if (fstat(file_open, &stat_results) < 0) { - ms_error("Couldn`t get status of the file [%s]", file_uri); - } else if (stat_results.st_size == 0) { - ms_error("The size of file is 0"); - close(file_open); - return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; - } else { - ms_debug("Size of file [%lld] bytes", (long long)stat_results.st_size); - } - - close(file_open); - - return MEDIA_STREAMER_ERROR_NONE; -} - 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"); @@ -942,6 +983,12 @@ int __ms_node_set_param_value(media_streamer_node_s *ms_node, param_s *param, co return ret; } + if (ms_node->type == MEDIA_STREAMER_NODE_TYPE_SRC && + ms_node->subtype == MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE) { + ret = __ms_adaptive_src_node_set_property(ms_node, param, param_value); + return ret; + } + if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_CAMERA_ID)) { int camera_id = (int)strtol(param_value, NULL, 10); ms_retvm_if(camera_id == -1, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Invalid %s value", param->param_name); diff --git a/src/media_streamer_util.c b/src/media_streamer_util.c index dcb1d60..d639070 100644 --- a/src/media_streamer_util.c +++ b/src/media_streamer_util.c @@ -19,6 +19,9 @@ #include #include +#include +#include + format_s format_table[] = { /* Audio - ENCODED */ {MEDIA_FORMAT_L16, "audio/x-raw"}, @@ -70,6 +73,9 @@ format_s format_table[] = { {MEDIA_FORMAT_RGBA, "RGBA"}, {MEDIA_FORMAT_ARGB, "ARGB"}, {MEDIA_FORMAT_NATIVE_VIDEO, "NATIVE_VIDEO"}, + /* Container */ + {MEDIA_FORMAT_CONTAINER_MP4, "video/quicktime"}, + {MEDIA_FORMAT_CONTAINER_MPEG2TS, "video/mpegts"}, {MEDIA_FORMAT_MAX, NULL} }; @@ -279,3 +285,38 @@ void __ms_param_value_destroy(gpointer data) } MS_SAFE_GFREE(val); } + +int __ms_node_uri_path_check(const char *file_uri) +{ + struct stat stat_results = {0, }; + int file_open = 0; + + if (!file_uri || !strlen(file_uri)) + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + + file_open = open(file_uri, O_RDONLY); + if (file_open < 0) { + char mes_error[256]; + strerror_r(errno, mes_error, sizeof(mes_error)); + ms_error("Couldn`t open file according to [%s]. Error N [%d]", mes_error, errno); + + if (EACCES == errno) + return MEDIA_STREAMER_ERROR_PERMISSION_DENIED; + + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + } + + if (fstat(file_open, &stat_results) < 0) { + ms_error("Couldn`t get status of the file [%s]", file_uri); + } else if (stat_results.st_size == 0) { + ms_error("The size of file is 0"); + close(file_open); + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + } else { + ms_debug("Size of file [%lld] bytes", (long long)stat_results.st_size); + } + + close(file_open); + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/test/media_streamer_test.c b/test/media_streamer_test.c index bf6aad6..4974e5f 100644 --- a/test/media_streamer_test.c +++ b/test/media_streamer_test.c @@ -28,7 +28,8 @@ typedef enum { MENU_STATE_BROADCAST_MENU, MENU_STATE_VOIP_MENU, MENU_STATE_PLAYING_MENU, - MENU_STATE_PRESET_MENU + MENU_STATE_PRESET_MENU, + MENU_STATE_ADAPTIVE_MENU, } menu_state_e; typedef enum { @@ -40,7 +41,8 @@ typedef enum { SUBMENU_STATE_AUTOPLUG, SUBMENU_STATE_SCENARIO, SUBMENU_STATE_PLAYING_SCENARIO, - SUBMENU_STATE_FORMAT + SUBMENU_STATE_FORMAT, + SUBMENU_STATE_ADAPTIVE_SCENARIO, } submenu_state_e; #define SECOND_VOIP_MASK 0x8 @@ -70,7 +72,10 @@ typedef enum { SCENARIO_MODE_FILE_PLAY_VIDEO_AUDIO, SCENARIO_MODE_FILE_SUBTITLE_VIDEO_AUDIO, SCENARIO_MODE_HTTP_VIDEO_AUDIO, - SCENARIO_MODE_APPSRC_APPSINK + SCENARIO_MODE_APPSRC_APPSINK, + SCENARIO_MODE_ADAPTIVE_SERVER, + SCENARIO_MODE_ADAPTIVE_CLIENT_AUTO, + SCENARIO_MODE_ADAPTIVE_CLIENT_MANUAL, } scenario_mode_e; #define PACKAGE "media_streamer_test" @@ -123,8 +128,11 @@ gboolean g_audio_is_on = FALSE; 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_encoded = NULL; +media_format_h afmt_aenc = NULL; +media_format_h tsfmt = NULL; static void streamer_error_cb(media_streamer_h streamer, media_streamer_error_e error, void *user_data) { @@ -297,6 +305,16 @@ static void create_formats(void) media_format_set_video_avg_bps(vfmt_encoded, VIDEO_AVG_BPS); media_format_set_video_max_bps(vfmt_encoded, VIDEO_MAX_BPS); + /* Define encoded video format for adaptive stream */ + media_format_create(&vfmt_aenc); + if (media_format_set_video_mime(vfmt_aenc, MEDIA_FORMAT_H264_SP) != MEDIA_FORMAT_ERROR_NONE) + g_print("media_format_set_video_mime failed!"); + + media_format_set_video_width(vfmt_aenc, VIDEO_WIDTH); + media_format_set_video_height(vfmt_aenc, VIDEO_HIGHT); + media_format_set_video_avg_bps(vfmt_aenc, VIDEO_AVG_BPS); + media_format_set_video_max_bps(vfmt_aenc, VIDEO_MAX_BPS); + /* Define audio raw format */ media_format_create(&afmt_raw); if (media_format_set_audio_mime(afmt_raw, MEDIA_FORMAT_PCM) != MEDIA_FORMAT_ERROR_NONE) @@ -312,6 +330,20 @@ static void create_formats(void) media_format_set_audio_channel(afmt_encoded, AUDIO_CHANNEL); media_format_set_audio_samplerate(afmt_encoded, AUDIO_SAMPLERATE); + + /* Define audio encoded format for adaptive stream */ + media_format_create(&afmt_aenc); + if (media_format_set_audio_mime(afmt_aenc, MEDIA_FORMAT_AAC) != MEDIA_FORMAT_ERROR_NONE) + g_print("media_format_set_audio_mime failed!"); + + media_format_set_audio_channel(afmt_aenc, AUDIO_CHANNEL); + media_format_set_audio_samplerate(afmt_aenc, AUDIO_SAMPLERATE); + media_format_set_audio_aac_type(afmt_aenc, TRUE); + + /* Define mpegts stream format */ + media_format_create(&tsfmt); + if (media_format_set_container_mime(tsfmt, MEDIA_FORMAT_CONTAINER_MPEG2TS) != MEDIA_FORMAT_ERROR_NONE) + g_print("media_format_set_container_mime failed!"); } static void set_rtp_params(media_streamer_node_h rtp_node, const char *ip, int video_port, int audio_port, gboolean port_reverse) @@ -640,6 +672,71 @@ static media_streamer_node_h _create_rtp(int video_port, int audio_port, gboolea return rtp_bin; } +static void _create_adaptive_playing() +{ + g_print("\n _create_adaptive_playing \n"); + media_streamer_node_h adaptive_src = NULL; + media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE, &adaptive_src); + media_streamer_node_set_param(adaptive_src, MEDIA_STREAMER_PARAM_URI, g_uri); + media_streamer_node_add(current_media_streamer, adaptive_src); + APPEND_NODE(adaptive_src); + + /*********************** videosink *********************************** */ + 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); + APPEND_NODE(video_sink); + + /*********************** audiosink *********************************** */ + media_streamer_node_h audio_sink = NULL; + media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO, &audio_sink); + media_streamer_node_add(current_media_streamer, audio_sink); + APPEND_NODE(audio_sink); +} + +static void _create_adaptive_playing_manual() +{ + g_print("\n _create_adaptive_playing_manual \n"); + media_streamer_node_h adaptive_src = NULL; + media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_ADAPTIVE, &adaptive_src); + media_streamer_node_set_param(adaptive_src, MEDIA_STREAMER_PARAM_URI, g_uri); + media_streamer_node_add(current_media_streamer, adaptive_src); + APPEND_NODE(adaptive_src); + + media_streamer_node_h ts_demux = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_DEMUXER, tsfmt, NULL, &ts_demux); + media_streamer_node_add(current_media_streamer, ts_demux); + APPEND_NODE(ts_demux); + + media_streamer_node_h video_dec = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER, vfmt_aenc, vfmt_raw, &video_dec); + media_streamer_node_add(current_media_streamer, video_dec); + 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_add(current_media_streamer, audio_dec); + APPEND_NODE(audio_dec); + + /*********************** videosink *********************************** */ + 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); + APPEND_NODE(video_sink); + + /*********************** audiosink *********************************** */ + media_streamer_node_h audio_sink = NULL; + media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO, &audio_sink); + media_streamer_node_add(current_media_streamer, audio_sink); + APPEND_NODE(audio_sink); + + /********************** link nodes *********************************** */ + media_streamer_node_link(adaptive_src, "src", ts_demux, "sink"); + media_streamer_node_link(video_dec, "src", video_sink, "sink"); + media_streamer_node_link(audio_dec, "src", audio_sink, "sink"); +} + + /* Application source callback */ static void buffer_status_cb(media_streamer_node_h node, media_streamer_custom_buffer_status_e status, void *user_data) { @@ -842,6 +939,23 @@ static void display_playing_scenario_select_menu(void) g_print("====================================================\n"); } +static void display_adaptive_scenario_select_menu(void) +{ + g_print("\n"); + g_print("====================================================\n"); + g_print(" media streamer test: Adaptive menu v0.3\n"); + g_print("----------------------------------------------------\n"); + g_print("\n"); + g_print("Please select Adaptive Scenario mode\n"); + g_print("By default will be used [%d] mode\n", g_scenario_mode); + g_print("1. [Server] Create Video http file segment \n"); + g_print("2. [Client] Adaptive playing auto-plug mode\n"); + g_print("3. [Client] Adaptive playing manual plug mode\n"); + g_print("b. back \n"); + g_print("----------------------------------------------------\n"); + g_print("====================================================\n"); +} + static void display_preset_menu(void) { g_print("\n"); @@ -901,6 +1015,7 @@ static void display_main_menu(void) g_print("1. Broadcast \n"); g_print("2. VOIP \n"); g_print("3. Local Playing \n"); + g_print("4. Adaptive \n"); g_print("q. quit \n"); g_print("----------------------------------------------------\n"); g_print("====================================================\n"); @@ -925,6 +1040,9 @@ static void display_menu(void) case MENU_STATE_PRESET_MENU: display_preset_menu(); break; + case MENU_STATE_ADAPTIVE_MENU: + display_preset_menu(); + break; default: g_print("*** Unknown status.\n"); break; @@ -952,6 +1070,9 @@ static void display_menu(void) case SUBMENU_STATE_PLAYING_SCENARIO: display_playing_scenario_select_menu(); break; + case SUBMENU_STATE_ADAPTIVE_SCENARIO: + display_adaptive_scenario_select_menu(); + break; default: g_print("*** Unknown Submenu state.\n"); break; @@ -1037,6 +1158,22 @@ void run_playing_preset(void) g_print("Invalid playing menu preset was selected!"); } +void run_adaptive_preset(void) +{ + create_formats(); + + g_print("%s:%d, %d %d %d", __FUNCTION__, __LINE__, g_menu_state, g_sub_menu_state, g_scenario_mode); + + if (g_scenario_mode == SCENARIO_MODE_ADAPTIVE_SERVER) + g_print("Adaptive server scenario"); + else if (g_scenario_mode == SCENARIO_MODE_ADAPTIVE_CLIENT_AUTO) + _create_adaptive_playing(); /* temp */ + else if (g_scenario_mode == SCENARIO_MODE_ADAPTIVE_CLIENT_MANUAL) + _create_adaptive_playing_manual(); /* temp */ + else + g_print("Invalid adaptive menu preset was selected!"); +} + void _interpret_main_menu(char *cmd) { int len = strlen(cmd); @@ -1048,6 +1185,8 @@ void _interpret_main_menu(char *cmd) g_menu_state = MENU_STATE_VOIP_MENU; else if (!strncmp(cmd, "3", len)) g_menu_state = MENU_STATE_PLAYING_MENU; + else if (!strncmp(cmd, "4", len)) + g_menu_state = MENU_STATE_ADAPTIVE_MENU; else if (!strncmp(cmd, "q", len)) quit(); } else { @@ -1112,6 +1251,28 @@ void _interpret_voip_menu(char *cmd) } } +void _interpret_adaptive_scenario_menu(char *cmd) +{ + int len = strlen(cmd); + + if (len == 1) { + if (!strncmp(cmd, "1", len)) { + g_scenario_mode = SCENARIO_MODE_ADAPTIVE_SERVER; + g_sub_menu_state = SUBMENU_STATE_GETTING_VIDEOFILE_URI; + return; + } else if (!strncmp(cmd, "2", len)) { + g_scenario_mode = SCENARIO_MODE_ADAPTIVE_CLIENT_AUTO; + g_sub_menu_state = SUBMENU_STATE_GETTING_VIDEOFILE_URI; + return; + } else if (!strncmp(cmd, "3", len)) { + g_scenario_mode = SCENARIO_MODE_ADAPTIVE_CLIENT_MANUAL; + g_sub_menu_state = SUBMENU_STATE_GETTING_VIDEOFILE_URI; + return; + } + } + g_sub_menu_state = SUBMENU_STATE_UNKNOWN; +} + void _interpret_playing_scenario_menu(char *cmd) { int len = strlen(cmd); @@ -1262,6 +1423,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); 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; @@ -1274,6 +1436,10 @@ void _interpret_getting_uri_menu(char *cmd) create_formats(); _create_file_streaming(); _create_rtp(VIDEO_PORT, AUDIO_PORT, FALSE); + } else if (g_scenario_mode == SCENARIO_MODE_ADAPTIVE_SERVER || + g_scenario_mode == SCENARIO_MODE_ADAPTIVE_CLIENT_AUTO || + g_scenario_mode == SCENARIO_MODE_ADAPTIVE_CLIENT_MANUAL) { + run_adaptive_preset(); } else { run_preset(); } @@ -1320,6 +1486,8 @@ void _interpret_preset_menu(char *cmd) /* call the run_preset function after autoplug mode was selected; */ if (g_menu_state == MENU_STATE_PLAYING_MENU) g_sub_menu_state = SUBMENU_STATE_PLAYING_SCENARIO; + else if (g_menu_state == MENU_STATE_ADAPTIVE_MENU) + g_sub_menu_state = SUBMENU_STATE_ADAPTIVE_SCENARIO; else g_sub_menu_state = SUBMENU_STATE_AUTOPLUG; } else if (!strncmp(cmd, "3", len)) { @@ -1372,6 +1540,9 @@ static void interpret_cmd(char *cmd) case MENU_STATE_PRESET_MENU: _interpret_preset_menu(cmd); break; + case MENU_STATE_ADAPTIVE_MENU: + _interpret_preset_menu(cmd); + break; default: g_print("Invalid command\n"); return; @@ -1400,6 +1571,9 @@ static void interpret_cmd(char *cmd) case SUBMENU_STATE_PLAYING_SCENARIO: _interpret_playing_scenario_menu(cmd); break; + case SUBMENU_STATE_ADAPTIVE_SCENARIO: + _interpret_adaptive_scenario_menu(cmd); + break; default: g_print("*** Unknown Submenu state.\n"); break; -- 2.7.4 From 930229bd3467297e597ad3b268b3aa71d24d311d Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Tue, 30 Aug 2016 19:12:26 +0900 Subject: [PATCH 10/16] add new sink type for adaptive Change-Id: I8e4fd35371cbd6f99f4244546e7fee8d88a12fd4 --- include/media_streamer.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/media_streamer.h b/include/media_streamer.h index 6275c69..f25715b 100644 --- a/include/media_streamer.h +++ b/include/media_streamer.h @@ -120,7 +120,8 @@ typedef enum { 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_CUSTOM, /**< Custom sink type */ + MEDIA_STREAMER_NODE_SINK_TYPE_ADAPTIVE /**< Adaptive sink type */ } media_streamer_node_sink_type_e; /** -- 2.7.4 From cd0617622ae23b0e410ca710127b30a26728d471 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Fri, 9 Sep 2016 15:25:00 +0300 Subject: [PATCH 11/16] Implement initial adaptive server Change-Id: I6f00edb8baf51f3c22b4c40dcc2906d9256a7146 Signed-off-by: Volodymyr Brynza --- include/media_streamer_gst.h | 7 +++ include/media_streamer_util.h | 1 + src/media_streamer_gst.c | 108 +++++++++++++++++++++++++++++++++++++++--- src/media_streamer_node.c | 14 +++++- test/media_streamer_test.c | 96 ++++++++++++++++++++++++++++++++++--- 5 files changed, 210 insertions(+), 16 deletions(-) diff --git a/include/media_streamer_gst.h b/include/media_streamer_gst.h index dbccb31..d407829 100644 --- a/include/media_streamer_gst.h +++ b/include/media_streamer_gst.h @@ -274,3 +274,10 @@ int __ms_element_pull_packet(GstElement *sink_element, media_packet_h *packet); * @since_tizen 3.0 */ int __ms_demux_element_prepare(media_streamer_s *ms_streamer, media_streamer_node_s *demux_node); + +/** + * @brief Finds type of media + * + * @since_tizen 3.0 + */ +int __ms_find_type(media_streamer_s *ms_streamer, GstElement *src_element); diff --git a/include/media_streamer_util.h b/include/media_streamer_util.h index 74de8ba..16347dc 100644 --- a/include/media_streamer_util.h +++ b/include/media_streamer_util.h @@ -185,6 +185,7 @@ typedef struct { /* adaptive streaming default */ #define DEFAULT_ADAPTIVE_SOURCE "hlsdemux" +#define DEFAULT_ADAPTIVE_SINK "hlssink" #define MEDIA_STREAMER_DEFAULT_CAMERA_FORMAT "video/x-raw,format=I420,width=352,height=288" #define MEDIA_STREAMER_DEFAULT_AUDIO_RAW_FORMAT "audio/x-raw,channels=1,rate=8000,format=S16LE" diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index dd3e0d0..2fa751d 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -25,6 +25,14 @@ #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_type_e; + +static int __ms_adaptive_sink_prepare(media_streamer_s * ms_streamer); + void __ms_generate_dots(GstElement *bin, gchar *name_tag) { gchar *dot_name; @@ -489,7 +497,7 @@ static void __decodebin_newpad_cb(GstElement * decodebin, GstPad * new_pad, gpoi g_mutex_unlock(&ms_streamer->mutex_lock); } -static void __decodebin_nomore_pads_combine(GstPad *src_pad, media_streamer_s *ms_streamer, gboolean is_server_part) +static void __decodebin_nomore_pads_combine(GstPad *src_pad, media_streamer_s *ms_streamer, media_streamer_sink_bin_type_e sink_bin_type) { GstElement *found_element = gst_pad_get_parent_element(src_pad); const gchar *new_pad_type = __ms_get_pad_type(src_pad); @@ -499,19 +507,27 @@ static void __decodebin_nomore_pads_combine(GstPad *src_pad, media_streamer_s *m found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_TEXT_OVERLAY); src_pad = NULL; } - if (is_server_part) { + if (sink_bin_type == MEDIA_STREAMER_SINK_BIN_RTP_SERVER) { found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER); found_element = __ms_combine_next_element(found_element, NULL, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_PAY); found_element = __ms_combine_next_element(found_element, NULL, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_RTP); + } else if (sink_bin_type == MEDIA_STREAMER_SINK_BIN_ADAPTIVE) { + found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER); + found_element = __ms_combine_next_element(found_element, NULL, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_MUXER); + found_element = __ms_combine_next_element(found_element, NULL, ms_streamer->sink_bin, MEDIA_STREAMER_NODE_TYPE_SINK); } else { found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_CONVERTER); found_element = __ms_combine_next_element(found_element, NULL, ms_streamer->sink_bin, MEDIA_STREAMER_NODE_TYPE_SINK); } } else if (MS_ELEMENT_IS_AUDIO(new_pad_type)) { - if (is_server_part) { + if (sink_bin_type == MEDIA_STREAMER_SINK_BIN_RTP_SERVER) { found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER); found_element = __ms_combine_next_element(found_element, NULL, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_AUDIO_PAY); found_element = __ms_combine_next_element(found_element, NULL, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_RTP); + } else if (sink_bin_type == MEDIA_STREAMER_SINK_BIN_ADAPTIVE) { + found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER); + found_element = __ms_combine_next_element(found_element, NULL, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_MUXER); + found_element = __ms_combine_next_element(found_element, NULL, ms_streamer->sink_bin, MEDIA_STREAMER_NODE_TYPE_SINK); } else { found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->sink_bin, MEDIA_STREAMER_NODE_TYPE_SINK); } @@ -532,8 +548,9 @@ static void __decodebin_nomore_pads_cb(GstElement *decodebin, gpointer user_data g_mutex_lock(&ms_streamer->mutex_lock); - gboolean is_server_part = FALSE; + media_streamer_sink_bin_type_e sink_bin_type = MEDIA_STREAMER_SINK_BIN_NORMAL; media_streamer_node_s *rtp_node = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "rtp_container"); + media_streamer_node_s *adaptive_sink = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "adaptive_sink"); if (rtp_node) { char *decodebin_name = NULL; @@ -541,24 +558,27 @@ static void __decodebin_nomore_pads_cb(GstElement *decodebin, gpointer user_data /* FIXME: This case may be not general */ if (g_strrstr(decodebin_name, MEDIASTREAMER_DECODEBIN_TYPE_DECODER)) { - is_server_part = FALSE; + sink_bin_type = MEDIA_STREAMER_SINK_BIN_NORMAL; MS_SAFE_FREE(decodebin_name); } else { /* It`s server part of Streaming Scenario*/ char *param_value = NULL; media_streamer_node_get_param(rtp_node, MEDIA_STREAMER_PARAM_VIDEO_OUT_PORT, ¶m_value); if (param_value && (strtol(param_value, NULL, 10) > 0)) - is_server_part = TRUE; + sink_bin_type = MEDIA_STREAMER_SINK_BIN_RTP_SERVER; MS_SAFE_FREE(param_value); } + } else if (adaptive_sink) { + __ms_adaptive_sink_prepare(ms_streamer); + sink_bin_type = MEDIA_STREAMER_SINK_BIN_ADAPTIVE; } GList *iterator = NULL; GList *list = ms_streamer->pads_types_list; for (iterator = list; iterator; iterator = iterator->next) { GstPad *src_pad = GST_PAD(iterator->data); - __decodebin_nomore_pads_combine(src_pad, ms_streamer, is_server_part); + __decodebin_nomore_pads_combine(src_pad, ms_streamer, sink_bin_type); } g_mutex_unlock(&ms_streamer->mutex_lock); @@ -702,6 +722,38 @@ static void __hlsdemux_pad_added_cb(GstElement *demux, GstPad *pad, gpointer dat gst_ghost_pad_set_target (GST_GHOST_PAD(gp), pad); } +static int __ms_adaptive_sink_prepare(media_streamer_s * ms_streamer) +{ + node_info_s nodes_info[] = { + {"Codec/Encoder/Video", "video_encoder"}, /* MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER */ + {"Codec/Encoder/Audio", "audio_encoder"}, /* MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER */ + {"Codec/Muxer", "mpegtsmux"}, /* MEDIA_STREAMER_NODE_TYPE_MUXER */ + }; + + GstCaps *video_enc_src_caps = gst_caps_new_empty_simple("video/x-h264"); + 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); + + GstCaps *audio_enc_src_caps = gst_caps_new_simple("audio/mpeg", "mpegversion", G_TYPE_INT, 4, NULL); + GstCaps *audio_enc_sink_caps = gst_caps_new_empty_simple("audio/x-raw"); + node_plug_s audio_enc_plug_info = {&(nodes_info[1]), audio_enc_src_caps, audio_enc_sink_caps, NULL}; + GstElement *audio_enc = __ms_node_element_create(&audio_enc_plug_info, MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER); + + GstCaps *muxer_src_caps = gst_caps_new_empty_simple("video/mpegts"); + node_plug_s mux_plug_info = {&(nodes_info[2]), muxer_src_caps, NULL, NULL}; + GstElement *muxer = __ms_node_element_create(&mux_plug_info, MEDIA_STREAMER_NODE_TYPE_MUXER); + + __ms_bin_add_element(ms_streamer->topology_bin, muxer, FALSE); + gst_element_sync_state_with_parent(muxer); + __ms_bin_add_element(ms_streamer->topology_bin, video_enc, FALSE); + gst_element_sync_state_with_parent(video_enc); + __ms_bin_add_element(ms_streamer->topology_bin, audio_enc, FALSE); + gst_element_sync_state_with_parent(audio_enc); + + return MEDIA_STREAMER_ERROR_NONE; +} + GstElement *__ms_adaptive_element_create(void) { GstElement *adaptive_bin = gst_bin_new("adaptive_src"); @@ -1118,6 +1170,10 @@ 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")) { + g_object_set(audio_encoder, "compliance", -2, NULL); + } + /* Creating bin - Audio Encoder */ GstElement *audio_enc_bin = gst_bin_new("audio_encoder"); ms_retvm_if(!audio_convert || !audio_postenc_convert || !audio_filter || !audio_encoder || !audio_enc_bin, (GstElement *) NULL, "Error: creating elements for encoder bin"); @@ -2015,3 +2071,41 @@ int __ms_demux_element_prepare(media_streamer_s * ms_streamer, media_streamer_no return MEDIA_STREAMER_ERROR_NONE; } + +static void __ms_typefound_cb(GstElement *typefind, guint probability, GstCaps *caps, gpointer data) +{ + GstElement *decodebin = NULL; + media_streamer_s *ms_streamer = (media_streamer_s *) data; + media_streamer_node_s *adaptive_sink = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "adaptive_sink"); + gchar *type; + GstPad *src_pad = gst_element_get_static_pad(typefind, "src"); + + 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 { + decodebin = __ms_decodebin_create(ms_streamer, NULL); + __ms_link_two_elements(typefind, src_pad, decodebin); + } + + MS_SAFE_UNREF(src_pad); + g_free (type); +} + +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"); + __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); + + __ms_link_two_elements(src_element, src_pad, typefind); + + MS_SAFE_UNREF(src_pad); + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 0ca0464..e62408e 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -524,6 +524,17 @@ int __ms_sink_node_create(media_streamer_node_s *node) __ms_signal_create(&node->sig_list, node->gst_element, "eos", G_CALLBACK(sink_eos), node); } break; + case MEDIA_STREAMER_NODE_SINK_TYPE_ADAPTIVE: + 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); + break; default: ms_error("Error: invalid Sink node Type [%d]", node->subtype); break; @@ -630,8 +641,7 @@ static void _src_node_prepare(const GValue *item, gpointer user_data) GstElement *found_element = NULL; if (__ms_src_need_typefind(src_pad)) { - found_element = __ms_decodebin_create(ms_streamer, NULL); - __ms_link_two_elements(src_element, src_pad, found_element); + __ms_find_type(ms_streamer,src_element); MS_SAFE_UNREF(src_element); } else { /* Check the source element`s pad type */ diff --git a/test/media_streamer_test.c b/test/media_streamer_test.c index 4974e5f..6a25dbd 100644 --- a/test/media_streamer_test.c +++ b/test/media_streamer_test.c @@ -74,6 +74,7 @@ typedef enum { SCENARIO_MODE_HTTP_VIDEO_AUDIO, SCENARIO_MODE_APPSRC_APPSINK, SCENARIO_MODE_ADAPTIVE_SERVER, + SCENARIO_MODE_ADAPTIVE_SERVER_MANUAL, SCENARIO_MODE_ADAPTIVE_CLIENT_AUTO, SCENARIO_MODE_ADAPTIVE_CLIENT_MANUAL, } scenario_mode_e; @@ -133,6 +134,7 @@ media_format_h afmt_raw = NULL; media_format_h afmt_encoded = NULL; media_format_h afmt_aenc = NULL; media_format_h tsfmt = NULL; +media_format_h qtfmt = NULL; static void streamer_error_cb(media_streamer_h streamer, media_streamer_error_e error, void *user_data) { @@ -344,6 +346,10 @@ static void create_formats(void) media_format_create(&tsfmt); if (media_format_set_container_mime(tsfmt, MEDIA_FORMAT_CONTAINER_MPEG2TS) != MEDIA_FORMAT_ERROR_NONE) g_print("media_format_set_container_mime failed!"); + /* Define MP4 stream format */ + media_format_create(&qtfmt); + if (media_format_set_container_mime(qtfmt, MEDIA_FORMAT_CONTAINER_MP4) != MEDIA_FORMAT_ERROR_NONE) + g_print("media_format_set_container_mime failed!"); } static void set_rtp_params(media_streamer_node_h rtp_node, const char *ip, int video_port, int audio_port, gboolean port_reverse) @@ -672,6 +678,74 @@ static media_streamer_node_h _create_rtp(int video_port, int audio_port, gboolea return rtp_bin; } +static void _create_adaptive_server() +{ + g_print("\n _create_adaptive_server \n"); + media_streamer_node_h file_src = NULL; + media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_FILE, &file_src); + media_streamer_node_set_param(file_src, MEDIA_STREAMER_PARAM_URI, g_uri); + media_streamer_node_add(current_media_streamer, file_src); + APPEND_NODE(file_src); + + /*********************** videosink *********************************** */ + media_streamer_node_h adaptive_sink = NULL; + media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_ADAPTIVE, &adaptive_sink); + media_streamer_node_add(current_media_streamer, adaptive_sink); + APPEND_NODE(adaptive_sink); +} + +static void _create_adaptive_server_manual() +{ + g_print("\n _create_adaptive_server manual \n"); + media_streamer_node_h file_src = NULL; + media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_FILE, &file_src); + media_streamer_node_set_param(file_src, MEDIA_STREAMER_PARAM_URI, g_uri); + media_streamer_node_add(current_media_streamer, file_src); + APPEND_NODE(file_src); + + media_streamer_node_h qt_demux = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_DEMUXER, qtfmt, NULL, &qt_demux); + media_streamer_node_add(current_media_streamer, qt_demux); + APPEND_NODE(qt_demux); + + media_streamer_node_h video_dec = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER, vfmt_aenc, vfmt_raw, &video_dec); + media_streamer_node_add(current_media_streamer, video_dec); + 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_add(current_media_streamer, audio_dec); + APPEND_NODE(audio_dec); + + media_streamer_node_h video_enc = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER, vfmt_raw, vfmt_aenc, &video_enc); + media_streamer_node_add(current_media_streamer, video_enc); + 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_add(current_media_streamer, audio_enc); + APPEND_NODE(audio_enc); + + media_streamer_node_h ts_mux = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_MUXER, NULL, tsfmt, &ts_mux); + media_streamer_node_add(current_media_streamer, ts_mux); + APPEND_NODE(ts_mux); + + media_streamer_node_h adaptive_sink = NULL; + media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_ADAPTIVE, &adaptive_sink); + media_streamer_node_add(current_media_streamer, adaptive_sink); + APPEND_NODE(adaptive_sink); + + media_streamer_node_link(file_src, "src", qt_demux, "sink"); + media_streamer_node_link(video_dec, "src", video_enc, "sink"); + media_streamer_node_link(audio_dec, "src", audio_enc, "sink"); + media_streamer_node_link(video_enc, "src", ts_mux, "sink_%d"); + media_streamer_node_link(audio_enc, "src", ts_mux, "sink_%d"); + media_streamer_node_link(ts_mux, "src", adaptive_sink, "sink"); +} + static void _create_adaptive_playing() { g_print("\n _create_adaptive_playing \n"); @@ -948,9 +1022,10 @@ static void display_adaptive_scenario_select_menu(void) g_print("\n"); g_print("Please select Adaptive Scenario mode\n"); g_print("By default will be used [%d] mode\n", g_scenario_mode); - g_print("1. [Server] Create Video http file segment \n"); - g_print("2. [Client] Adaptive playing auto-plug mode\n"); - g_print("3. [Client] Adaptive playing manual plug mode\n"); + g_print("1. [Server] Create Adaptive content generation auto mode \n"); + g_print("2. [Server] Create Adaptive content generation manual mode \n"); + g_print("3. [Client] Adaptive playing auto-plug mode\n"); + g_print("4. [Client] Adaptive playing manual plug mode\n"); g_print("b. back \n"); g_print("----------------------------------------------------\n"); g_print("====================================================\n"); @@ -1165,11 +1240,13 @@ void run_adaptive_preset(void) g_print("%s:%d, %d %d %d", __FUNCTION__, __LINE__, g_menu_state, g_sub_menu_state, g_scenario_mode); if (g_scenario_mode == SCENARIO_MODE_ADAPTIVE_SERVER) - g_print("Adaptive server scenario"); + _create_adaptive_server(); + else if (g_scenario_mode == SCENARIO_MODE_ADAPTIVE_SERVER_MANUAL) + _create_adaptive_server_manual(); else if (g_scenario_mode == SCENARIO_MODE_ADAPTIVE_CLIENT_AUTO) - _create_adaptive_playing(); /* temp */ + _create_adaptive_playing(); else if (g_scenario_mode == SCENARIO_MODE_ADAPTIVE_CLIENT_MANUAL) - _create_adaptive_playing_manual(); /* temp */ + _create_adaptive_playing_manual(); else g_print("Invalid adaptive menu preset was selected!"); } @@ -1261,10 +1338,14 @@ void _interpret_adaptive_scenario_menu(char *cmd) g_sub_menu_state = SUBMENU_STATE_GETTING_VIDEOFILE_URI; return; } else if (!strncmp(cmd, "2", len)) { - g_scenario_mode = SCENARIO_MODE_ADAPTIVE_CLIENT_AUTO; + g_scenario_mode = SCENARIO_MODE_ADAPTIVE_SERVER_MANUAL; g_sub_menu_state = SUBMENU_STATE_GETTING_VIDEOFILE_URI; return; } else if (!strncmp(cmd, "3", len)) { + g_scenario_mode = SCENARIO_MODE_ADAPTIVE_CLIENT_AUTO; + g_sub_menu_state = SUBMENU_STATE_GETTING_VIDEOFILE_URI; + return; + } else if (!strncmp(cmd, "4", len)) { g_scenario_mode = SCENARIO_MODE_ADAPTIVE_CLIENT_MANUAL; g_sub_menu_state = SUBMENU_STATE_GETTING_VIDEOFILE_URI; return; @@ -1437,6 +1518,7 @@ void _interpret_getting_uri_menu(char *cmd) _create_file_streaming(); _create_rtp(VIDEO_PORT, AUDIO_PORT, FALSE); } else if (g_scenario_mode == SCENARIO_MODE_ADAPTIVE_SERVER || + g_scenario_mode == SCENARIO_MODE_ADAPTIVE_SERVER_MANUAL || g_scenario_mode == SCENARIO_MODE_ADAPTIVE_CLIENT_AUTO || g_scenario_mode == SCENARIO_MODE_ADAPTIVE_CLIENT_MANUAL) { run_adaptive_preset(); -- 2.7.4 From e3319e5baee88cf1054386083a44889d1ce8e740 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Tue, 6 Sep 2016 11:30:57 +0300 Subject: [PATCH 12/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 13/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 14/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 15/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 16/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