From 0c5a1dbe5dfa6c5f82b1127dc87b34b44c791ada Mon Sep 17 00:00:00 2001 From: "eunhae1.choi" Date: Tue, 9 Jun 2015 23:09:38 +0900 Subject: [PATCH 2/5] add mediastreamer initial code Change-Id: Ic121e5611599539451f0e7f8896a845e84e58b81 --- AUTHORS | 4 + CMakeLists.txt | 104 +++ LICENSE.APLv2 | 204 ++++++ NOTICE | 3 + capi-media-streamer.pc.in | 11 + doc/mediastreamer_doc.h | 41 ++ include/media_streamer.h | 926 ++++++++++++++++++++++++++ include/media_streamer_gst.h | 121 ++++ include/media_streamer_node.h | 79 +++ include/media_streamer_priv.h | 145 ++++ include/media_streamer_util.h | 230 +++++++ packaging/capi-media-streamer.manifest | 8 + packaging/capi-media-streamer.spec | 77 +++ src/media_streamer.c | 517 ++++++++++++++ src/media_streamer_gst.c | 1146 ++++++++++++++++++++++++++++++++ src/media_streamer_node.c | 453 +++++++++++++ src/media_streamer_priv.c | 203 ++++++ src/media_streamer_util.c | 217 ++++++ test/CMakeLists.txt | 24 + test/media_streamer_test.c | 940 ++++++++++++++++++++++++++ 20 files changed, 5453 insertions(+) create mode 100755 AUTHORS create mode 100755 CMakeLists.txt create mode 100755 LICENSE.APLv2 create mode 100755 NOTICE create mode 100755 capi-media-streamer.pc.in create mode 100755 doc/mediastreamer_doc.h create mode 100755 include/media_streamer.h create mode 100755 include/media_streamer_gst.h create mode 100755 include/media_streamer_node.h create mode 100755 include/media_streamer_priv.h create mode 100755 include/media_streamer_util.h create mode 100755 packaging/capi-media-streamer.manifest create mode 100755 packaging/capi-media-streamer.spec create mode 100755 src/media_streamer.c create mode 100755 src/media_streamer_gst.c create mode 100755 src/media_streamer_node.c create mode 100755 src/media_streamer_priv.c create mode 100755 src/media_streamer_util.c create mode 100755 test/CMakeLists.txt create mode 100755 test/media_streamer_test.c diff --git a/AUTHORS b/AUTHORS new file mode 100755 index 0000000..a0cc6e6 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,4 @@ +Eunhae Choi +Oleg Kopysov +Andrey Shelest +Vyacheslav Valkovoy diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100755 index 0000000..df8d4a5 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,104 @@ + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_name "capi-media-streamer") + +PROJECT(${fw_name}) + +SET(CMAKE_INSTALL_PREFIX /usr) +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" ) +SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0" ) + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_name} REQUIRED ${dependents}) +FOREACH(flag ${${fw_name}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "-I./include -I./include/headers ${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") + +IF("${ARCH}" STREQUAL "arm") + ADD_DEFINITIONS("-DTARGET") +ENDIF("${ARCH}" STREQUAL "arm") + +ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") +ADD_DEFINITIONS("-DTIZEN_DEBUG") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib") + +AUX_SOURCE_DIRECTORY (src MAIN_SRC) + +LIST (APPEND SOURCES + ${MAIN_SRC} + ) + +ADD_LIBRARY(${fw_name} SHARED ${SOURCES}) + +TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS}) + +SET_TARGET_PROPERTIES(${fw_name} + PROPERTIES + VERSION ${FULLVER} + SOVERSION ${MAJORVER} + CLEAN_DIRECT_OUTPUT 1 +) + +INSTALL(TARGETS ${fw_name} DESTINATION lib) +INSTALL( + DIRECTORY ${INC_DIR}/ DESTINATION include/media + FILES_MATCHING + PATTERN "media_streamer_*.h" EXCLUDE + PATTERN "${INC_DIR}/*.h" + ) + + +SET(PC_NAME ${fw_name}) +SET(PC_REQUIRED ${pc_dependents}) +SET(PC_LDFLAGS -l${fw_name}) +SET(PC_CFLAGS -I\${includedir}/media) + +CONFIGURE_FILE( + ${fw_name}.pc.in + ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc + @ONLY +) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION lib/pkgconfig) + +ADD_SUBDIRECTORY(test) + +IF(UNIX) + +ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution) +ADD_CUSTOM_COMMAND( + DEPENDS clean + COMMENT "distribution clean" + COMMAND find + ARGS . + -not -name config.cmake -and \( + -name tester.c -or + -name Testing -or + -name CMakeFiles -or + -name cmake.depends -or + -name cmake.check_depends -or + -name CMakeCache.txt -or + -name cmake.check_cache -or + -name *.cmake -or + -name Makefile -or + -name core -or + -name core.* -or + -name gmon.out -or + -name install_manifest.txt -or + -name *.pc -or + -name *~ \) + | grep -v TC | xargs rm -rf + TARGET distclean + VERBATIM +) + +ENDIF(UNIX) + diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100755 index 0000000..a06208b --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,204 @@ +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/NOTICE b/NOTICE new file mode 100755 index 0000000..ccdad52 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE file for Apache License terms and conditions. diff --git a/capi-media-streamer.pc.in b/capi-media-streamer.pc.in new file mode 100755 index 0000000..0da82e4 --- /dev/null +++ b/capi-media-streamer.pc.in @@ -0,0 +1,11 @@ +prefix = @prefix@ +exec_prefix=@exec_prefix@ +libdir = @libdir@ +includedir = @includedir@ + +Name : mediastreamer +Description : Multimedia Framework MediaStreamer Library +Requires : mm-common +Version : @VERSION@ +Libs : -L${libdir} -lmmfstreamer +Cflags : -I${includedir}/mmf diff --git a/doc/mediastreamer_doc.h b/doc/mediastreamer_doc.h new file mode 100755 index 0000000..c050b94 --- /dev/null +++ b/doc/mediastreamer_doc.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TIZEN_MEDIASTREAMER_DOC_H__ +#define __TIZEN_MEDIASTREAMER_DOC_H__ + +/** + * @file mediastreamer_doc.h + * @brief This file contains high level documentation of the CAPI MEDIA STREAMER API. + */ + +/** + * @ingroup CAPI_MEDIA_FRAMEWORK + * @defgroup CAPI_MEDIA_MEDIASTREAMER_MODULE Media Streamer + * @brief The @ref CAPI_MEDIA_MEDIASTREAMER_MODULE APIs provides functions for building custom pipeline + * + * @section CAPI_MEDIA_MEDIASTREAMER_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_MEDIASTREAMER_MODULE_OVERVIEW Overview + * + * MEDIASTREAMER allows : + * Create streamer handle and elements to build custom pipeline. + * Application can create, add and link elements manually. + * + */ + +#endif /* __TIZEN_MEDIASTREAMER_DOC_H__ */ diff --git a/include/media_streamer.h b/include/media_streamer.h new file mode 100755 index 0000000..5fd99f8 --- /dev/null +++ b/include/media_streamer.h @@ -0,0 +1,926 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TIZEN_MEDIASTREAMER_H__ +#define __TIZEN_MEDIASTREAMER_H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#ifndef TIZEN_ERROR_MEDIA_STREAMER +#define TIZEN_ERROR_MEDIA_STREAMER -0x03000000 +#endif + +/** +* @file media_streamer.h +* @brief This file contains the capi media streamer API. +*/ + +/** +* @addtogroup CAPI_MEDIASTREAMER_MODULE +* @{ +*/ + +/** + * @brief Media Streamer handle type. + * + * @since_tizen 3.0 + */ +typedef void *media_streamer_h; + +/** + * @brief Media Streamer node handle type. + * + * @since_tizen 3.0 + */ +typedef void *media_streamer_node_h; + +/** + * @brief Media streamer time type. + * + * @since_tizen 3.0 + */ +typedef long long media_streamer_time_value; + +/** + * @brief Enumeration for media streamer node type. + * + * @since_tizen 3.0 + */ +typedef enum +{ + MEDIA_STREAMER_NODE_TYPE_NONE, /**< Not defined type */ + MEDIA_STREAMER_NODE_TYPE_SRC, /**< Src node type */ + MEDIA_STREAMER_NODE_TYPE_SINK, /**< Sink node type */ + MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER, /**< Video encoder node type */ + MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER, /**< Video decoder node type */ + MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER, /**< Audio encoder node type */ + MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER, /**< Audio decoder node type */ + MEDIA_STREAMER_NODE_TYPE_VIDEO_CONVERTER, /**< Video converter node type */ + MEDIA_STREAMER_NODE_TYPE_AUDIO_CONVERTER, /**< Audio converter node type */ + MEDIA_STREAMER_NODE_TYPE_AUDIO_RESAMPLE, /**< Audio resample node type */ + MEDIA_STREAMER_NODE_TYPE_VIDEO_PAY, /**< Rtp video payloader */ + MEDIA_STREAMER_NODE_TYPE_AUDIO_PAY, /**< Rtp audio payloader */ + MEDIA_STREAMER_NODE_TYPE_VIDEO_DEPAY, /**< Rtp video depayloader */ + MEDIA_STREAMER_NODE_TYPE_AUDIO_DEPAY, /**< Rtp audio depayloader */ + MEDIA_STREAMER_NODE_TYPE_PARSER, /**< Parser node type */ + MEDIA_STREAMER_NODE_TYPE_FILTER, /**< Filter node type, to limit formats of data */ + MEDIA_STREAMER_NODE_TYPE_TEE, /**< Tee node type, splits data to multiple path */ + MEDIA_STREAMER_NODE_TYPE_QUEUE, /**< Queue node type */ + MEDIA_STREAMER_NODE_TYPE_MQUEUE, /**< Multiple data queue node type */ + MEDIA_STREAMER_NODE_TYPE_MUXER, /**< Muxer node type */ + MEDIA_STREAMER_NODE_TYPE_DEMUXER, /**< Demuxer node type */ + MEDIA_STREAMER_NODE_TYPE_RTP, /**< Rtp component to send and receive data */ + MEDIA_STREAMER_NODE_TYPE_INPUT_SELECTOR, /**< N-to-1 input stream selector */ + MEDIA_STREAMER_NODE_TYPE_OUTPUT_SELECTOR, /**< 1-to-N output stream selector */ + MEDIA_STREAMER_NODE_TYPE_INTERLEAVE, /**< Folds many mono channel into one interleaved audio stream */ + MEDIA_STREAMER_NODE_TYPE_DEINTERLEAVE /**< Splits multi channel audio into many mono audio */ +} media_streamer_node_type_e; + +/** + * @brief Enumeration for media streamer source node type. + * + * @since_tizen 3.0 + */ +typedef enum +{ + MEDIA_STREAMER_SRC_TYPE_NONE, /**< Not defined src type */ + MEDIA_STREAMER_SRC_TYPE_FILE, /**< Local file src type */ + MEDIA_STREAMER_SRC_TYPE_HTTP, /**< Http src type */ + MEDIA_STREAMER_SRC_TYPE_RTSP, /**< Rtsp src type */ + MEDIA_STREAMER_SRC_TYPE_CAMERA, /**< Camera src type */ + MEDIA_STREAMER_SRC_TYPE_AUDIO_CAPTURE, /**< Audio capture src type */ + MEDIA_STREAMER_SRC_TYPE_VIDEO_CAPTURE, /**< Video capture src type */ + MEDIA_STREAMER_SRC_TYPE_AUDIO_TEST, /**< Audio test src type */ + MEDIA_STREAMER_SRC_TYPE_VIDEO_TEST, /**< Video test src type */ + MEDIA_STREAMER_SRC_TYPE_CUSTOM /**< Custom src type */ +} media_streamer_src_type_e; + +/** + * @brief Enumeration for media streamer sink node type. + * + * @since_tizen 3.0 + */ +typedef enum +{ + MEDIA_STREAMER_SINK_TYPE_NONE, /**< Not defined sink type */ + MEDIA_STREAMER_SINK_TYPE_FILE, /**< Local file sink type */ + MEDIA_STREAMER_SINK_TYPE_RTSP, /**< Rtsp sink type */ + MEDIA_STREAMER_SINK_TYPE_HTTP, /**< Http sink type */ + MEDIA_STREAMER_SINK_TYPE_AUDIO, /**< Audio sink type */ + MEDIA_STREAMER_SINK_TYPE_SCREEN, /**< Screen sink type */ + MEDIA_STREAMER_SINK_TYPE_FAKE, /**< Fake sink type */ + MEDIA_STREAMER_SINK_TYPE_CUSTOM /**< Custom sink type */ +} media_streamer_sink_type_e; + +/** + * @brief Enumeration for media streamer state. + * + * @since_tizen 3.0 + */ +typedef enum +{ + MEDIA_STREAMER_STATE_NONE, /**< Streamer is not created */ + MEDIA_STREAMER_STATE_IDLE, /**< Streamer is created but not prepared */ + MEDIA_STREAMER_STATE_READY, /**< Streamer is ready to play */ + MEDIA_STREAMER_STATE_PLAYING, /**< Streamer is playing */ + MEDIA_STREAMER_STATE_PAUSED, /**< Streamer is paused */ + MEDIA_STREAMER_STATE_SEEKING /**< Seek is under operation */ +} media_streamer_state_e; + +/** + * @brief Enumeration for media streamer error. + * + * @since_tizen 3.0 + */ +typedef enum +{ + MEDIA_STREAMER_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ + 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_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 */ + MEDIA_STREAMER_ERROR_RESOURCE_CONFLICT = TIZEN_ERROR_MEDIA_STREAMER|0x03, /**< Resource conflict */ +} media_streamer_error_e; + +/** + * @brief Enumeration of media streamer buffer status of custom src + * + * @since_tizen 3.0 + */ +typedef enum +{ + MEDIA_STREAMER_CUSTOM_BUFFER_UNDERRUN, /**< buffer underrun of custom src */ + MEDIA_STREAMER_CUSTOM_BUFFER_OVERFLOW, /**< buffer overflow of custom src */ +} media_streamer_custom_buffer_status_e; + +/** + * @brief Called when error occurs in media streamer. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @param [in] error The error that occurred in media steamer + * @param [in] user_data The user data passed from the code where + * media_streamer_set_error_cb() was invoked + * This data will be accessible from @a media_streamer_error_cb + * @pre Create media streamer handle by calling media_streamer_create() function + * @see media_streamer_set_error_cb() + * @see media_streamer_unset_error_cb() + */ +typedef void (*media_streamer_error_cb)(media_streamer_h streamer, + media_streamer_error_e error, + void *user_data); + +/** + * @brief Called when media streamer state was changed. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @param [in] previous_state The previous state of the media steamer + * @param [in] current_state The current state of media streamer + * @param [in] user_data The user data passed from the code where + * media_streamer_set_state_changed_cb() was invoked + * This data will be accessible from @a media_streamer_state_changed_cb + * @pre Create media streamer handle by calling media_streamer_create() function + * @see media_streamer_set_state_change_cb() + * @see media_streamer_unset_state_change_cb() + */ +typedef void (*media_streamer_state_changed_cb)(media_streamer_h streamer, + media_streamer_state_e previous_state, + media_streamer_state_e current_state, + void *user_data); + +/** + * @brief Called when the custom source needs more data or has enough data. + * @details This callback will be invoked when the buffer level drops below the threshold of max size + * or no free space in custom source buffer. + * @since_tizen 3.0 + * @remarks Callback can be applied only for MEDIA_STREAMER_SRC_TYPE_CUSTOM source type + * @param [in] node Media streamer source node handle + * @param [in] user_data The user data passed from the callback registration function + * @see media_streamer_src_set_buffer_status_cb() + * @see media_streamer_node_get_param_list() + * @see media_streamer_node_set_params() + */ +typedef void (*media_streamer_custom_buffer_status_cb) (media_streamer_node_h node, + media_streamer_custom_buffer_status_e status, + void *user_data); + +/** + * @brief Called when new data is available from custom sink. + * @details This callback can be applied only to MEDIA_STREAMER_SINK_TYPE_CUSTOM sink type + * @since_tizen 3.0 + * @param [in] node Media streamer sink node handle + * @param [in] user_data The user data passed from the code where + * media_streamer_sink_set_data_ready_cb() was invoked + * This data will be accessible from @a media_streamer_sink_data_ready_cb + * @pre media_streamer_sink_set_data_ready_cb() + * @see MEDIA_STREAMER_SINK_TYPE_CUSTOM + * @see media_streamer_sink_set_data_ready_cb() + * @see media_streamer_sink_unset_data_ready_cb() + */ +typedef void (*media_streamer_sink_data_ready_cb)(media_streamer_node_h node, + void *user_data); + +/** + * @brief Called when the end-of-stream has been reached. + * @details This callback can be applied only to MEDIA_STREAMER_SINK_TYPE_CUSTOM sink type + * @since_tizen 3.0 + * @param [in] node Media streamer sink node handle + * @param [in] user_data The user data passed from the code where + * media_streamer_sink_set_eos_cb() was invoked + * This data will be accessible from @a media_streamer_sink_eos_cb + * @pre media_streamer_sink_set_eos_cb() + * @see MEDIA_STREAMER_SINK_TYPE_CUSTOM + * @see media_streamer_sink_set_eos_cb() + * @see media_streamer_sink_unset_eos_cb() + */ +typedef void (*media_streamer_sink_eos_cb)(media_streamer_node_h node, + void *user_data); + +/** + * @brief Register a error callback function to be invoked when an error occurs. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @param [in] callback Callback function pointer + * @param [in] user_data The user data passed from the code where + * media_streamer_set_error_cb() was invoked + * This data will be accessible from @a media_streamer_error_cb + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a media streamer handle by calling media_streamer_create() function + * @post media_streamer_error_cb() will be invoked. + * @see media_streamer_unset_error_cb() + * @see media_streamer_error_cb() + */ +int media_streamer_set_error_cb(media_streamer_h streamer, + media_streamer_error_cb callback, + void *user_data); + +/** + * @brief Unregisters the error callback function. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @see media_streamer_error_cb() + */ +int media_streamer_unset_error_cb(media_streamer_h streamer); + +/** + * @brief Register a callback that will be triggered after media streamer state was changed. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @param [in] callback Callback function pointer + * @param [in] user_data The user data passed from the code + * where media_streamer_set_state_change_cb() was invoked + * This data will be accessible from @a media_streamer_state_changed_cb + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a media streamer handle by calling media_streamer_create() function + * @post media_streamer_state_changed_cb() will be invoked. + * @see media_streamer_unset_state_change_cb() + * @see media_streamer_state_change_cb() + */ +int media_streamer_set_state_change_cb(media_streamer_h streamer, + media_streamer_state_changed_cb callback, + void *user_data); + +/** + * @brief Unregisters the state changed callback function. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @see media_streamer_set_state_change_cb() + */ +int media_streamer_unset_state_change_cb(media_streamer_h streamer); + +/** + * @brief Registers a callback function to be invoked when buffer underrun or overflow is occurred. + * @details This function can be called only for MEDIA_STREAMER_SRC_TYPE_CUSTOM source type + * @since_tizen 3.0 + * @remarks This API is used for media stream playback only. + * @param [in] source Media streamer source node handle + * @param [in] callback The buffer status callback function to register + * @param [in] user_data The user data passed from the code where + * media_streamer_src_set_buffer_status_cb() was invoked + * This data will be accessible from @a media_streamer_custom_buffer_status_cb() + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a media streamer source node handle by calling media_streamer_src_create() function + * @pre Add created media streamer source node to media streamer by calling media_streamer_node_add() function + * @post media_streamer_custom_buffer_status_cb() will be invoked. + * @see media_streamer_src_unset_buffer_status_cb() + * @see media_streamer_custom_buffer_status_cb() + */ +int media_streamer_src_set_buffer_status_cb(media_streamer_node_h source, + media_streamer_custom_buffer_status_cb callback, + void *user_data); + +/** + * @brief Unregisters the src buffer status callback function. + * @since_tizen 3.0 + * @param [in] source Media streamer source node handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @see media_streamer_src_set_buffer_status_cb() + */ +int media_streamer_src_unset_buffer_status_cb(media_streamer_node_h source); + +/** + * @brief Register 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_SINK_TYPE_CUSTOM sink type + * @since_tizen 3.0 + * @param [in] sink Media streamer sink 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 + * This data will be accessible from @a media_streamer_sink_data_ready_cb + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a media streamer sink handle by calling media_streamer_sink_create() function + * @pre Add created media streamer sink node to media streamer by calling media_streamer_node_add() function + * @post media_streamer_sink_data_ready_cb() will be invoked. + * @see media_streamer_sink_unset_data_ready_cb() + * @see media_streamer_sink_data_ready_cb() + */ +int media_streamer_sink_set_data_ready_cb(media_streamer_node_h sink, + media_streamer_sink_data_ready_cb callback, + void *user_data); + +/** + * @brief Unregisters the sink data ready callback function. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @see media_streamer_sink_set_data_ready_cb() + */ +int media_streamer_sink_unset_data_ready_cb(media_streamer_h streamer); + +/** + * @brief Registers a callback function to be called when custom sink detect the end-of-stream. + * @since_tizen 3.0 + * @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_eos_cb() was invoked. + * This data will be accessible from @a media_streamer_sink_eos_cb + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a media streamer sink handle by calling media_streamer_sink_create() function + * @pre Add created media streamer sink node to media streamer by calling media_streamer_node_add() function + * @post media_streamer_sink_eos_cb() will be invoked. + * @see media_streamer_sink_unset_eos_cb() + * @see media_streamer_sink_eos_cb() + */ +int media_streamer_sink_set_eos_cb(media_streamer_node_h sink, + media_streamer_sink_eos_cb callback, + void *user_data); + +/** + * @brief Unregisters the sink end-of-stream callback function. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @see media_streamer_sink_set_eos_cb() + */ +int media_streamer_sink_unset_eos_cb(media_streamer_h streamer); + +/** + * @brief Creates an instance of media streamer and + * passes the handle to the caller. + * @since_tizen 3.0 + * @remarks You must release @a streamer using media_streamer_destroy() + * @param [out] streamer Media streamer handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @post The media streamer state will be #MEDIA_STREAMER_STATE_IDLE. + * @see media_streamer_destroy() + */ +int media_streamer_create(media_streamer_h *streamer); + +/** + * @brief Sets media streamer state to MEDIA_STREAMER_STATE_READY. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre The media streamer state must be set to #MEDIA_STREAMER_STATE_IDLE + * 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_src_create(), media_streamer_sink_create() and media_streamer_node_link(). + * @post The media streamer state will be #MEDIA_STREANER_STATE_READY. + * @see media_streamer_unprepare() + * @see media_streamer_create() + */ +int media_streamer_prepare(media_streamer_h streamer); + +/** + * @brief Sets media streamer state to MEDIA_STREAMER_STATE_IDLE. + * @details The most recently used media is reset and no longer associated with the media streamer. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre The media streamer state should be higher than #MEDIA_STREAMER_STATE_IDLE. + * @post The media streamer state will be #MEDIA_STREAMER_STATE_IDLE. + * @see media_streamer_prepare() + */ +int media_streamer_unprepare(media_streamer_h streamer); + +/** + * @brief Sets media streamer state to MEDIA_STREAMER_STATE_PLAYING. + * @details start running the current streamer, or resumes it if paused. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre The media streamer state must be set to #MEDIA_STREAMER_STATE_READY by calling media_streamer_prepare() or + * set to #MEDIA_STREAMER_STATE_PAUSED by calling media_streamer_pause(). + * @post The media streamer state will be #MEDIA_STREAMER_STATE_PLAYING. + * @see media_streamer_create() + * @see media_streamer_pause() + * @see media_streamer_stop() + */ +int media_streamer_play(media_streamer_h streamer); + +/** + * @brief Pause the media streamer. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre The media streamer state must be set to #MEDIA_STREAMER_STATE_PLAYING. + * @post The media streamer state will be #MEDIA_STREAMER_STATE_READY. + * @see media_streamer_create() + * @see media_streamer_play() + */ +int media_streamer_pause(media_streamer_h streamer); + +/** + * @brief Stops the media streamer. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre The media streamer state must be set to #MEDIA_STREAMER_STATE_PLAYING by calling media_streamer_start() or + * set to #MEDIA_STREAMER_STATE_PAUSED by calling media_streamer_pause(). + * @post The media streamer state will be #MEDIA_STREAMER_STATE_READY. + * @see media_streamer_create() + * @see media_streamer_start() + * @see media_streamer_pause() + */ +int media_streamer_stop(media_streamer_h streamer); + +/** + * @brief Destroys media streamer. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a media streamer handle by calling media_streamer_create() function + * @post The media streamer state will be #MEDIA_STREAMER_STATE_NONE. + * @see media_streamer_create() + */ +int media_streamer_destroy(media_streamer_h streamer); + +/** + * @brief Gets media streamer state. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @param [out] state Media streamer state + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a media streamer handle by calling media_streamer_create() function + * @see #media_streamer_state_e + */ +int media_streamer_get_state(media_streamer_h streamer, + media_streamer_state_e *state); + +/** + * @brief Creates media streamer source node. + * @since_tizen 3.0 + * @privlevel public + * @privilege http://tizen.org/privilege/mediastorage + * http://tizen.org/privilege/externalstorage + * http://tizen.org/privilege/internet + * http://tizen.org/privilege/camera + * http://tizen.org/privilege/recorder + * @remarks The mediastorage privilege(http://tizen.org/privilege/mediastorage) should be added if any video/audio files are used to play located in the internal storage. + * @remarks The externalstorage privilege(http://tizen.org/privilege/externalstorage) should be added if any video/audio files are used to play located in the external storage. + * @remarks The internet privilege(http://tizen.org/privilege/internet) should be added if any URIs are used to play from network. + * @remarks The camera privilege(http://tizen.org/privilege/camera) should be added if the src node handle the camera device. + * @remarks The recorder privilege(http://tizen.org/privilege/recorder) should be added if the src node handle the recorder device. + * @remarks You can release @a source node using media_streamer_node_destroy() function + * @param [in] type Media streamer source node type + * @param [out] src Media streamer source node handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @retval #MEDIA_STREAMER_ERROR_PERMISSION_DENIED Permission denied + * @retval #MEDIA_STREAMER_ERROR_FEATURE_NOT_SUPPORTED_ON_DEVICE Not support on device + * @see #media_streamer_src_type_e + * @see media_streamer_node_destroy() + */ +int media_streamer_src_create(media_streamer_src_type_e type, + media_streamer_node_h *src); + +/** + * @brief Pushes packet into custom source node. + * @details This function can be called only for MEDIA_STREAMER_SRC_TYPE_CUSTOM. + * @since_tizen 3.0 + * @param [in] src Media streamer source node handle + * @param [in] packet Media packet handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @retval #MEDIA_STREAMER_ERROR_PERMISSION_DENIED Permission denied + * @pre Create a source node handle by calling media_streamer_src_create() function + * @pre The media streamer state must be set to #MEDIA_STREAMER_STATE_IDLE at least. + * @see #media_packet_h + */ +int media_streamer_push_packet(media_streamer_node_h src, + media_packet_h packet); + +/** + * @brief Creates media streamer sink node. + * @details This function can be called only for MEDIA_STREAMER_SINK_TYPE_CUSTOM + * @since_tizen 3.0 + * @privlevel public + * @privilege http://tizen.org/privilege/mediastorage + * http://tizen.org/privilege/externalstorage + * http://tizen.org/privilege/internet + * @remarks The mediastorage privilege(http://tizen.org/privilege/mediastorage) should be added if any video/audio files are written in the internal storage devices. + * @remarks The externalstorage privilege(http://tizen.org/privilege/externalstorage) should be added if any video/audio files are written in the external storage devices. + * @remarks The internet privilege(http://tizen.org/privilege/internet) should be added if any URIs are used to transmit the output data. + * @remarks You can release @a sink node using media_streamer_node_destroy() + * @param [in] type Type of sink node to be created + * @param [out] sink Media streamer sink node handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @retval #MEDIA_STREAMER_ERROR_PERMISSION_DENIED Permission denied + * @retval #MEDIA_STREAMER_ERROR_FEATURE_NOT_SUPPORTED_ON_DEVICE Not support on device + * @see #media_streamer_sink_type_e + * @see media_streamer_node_destroy() + */ +int media_streamer_sink_create(media_streamer_sink_type_e type, + media_streamer_node_h *sink); + +/** + * @brief Pulls packet from custom sink node. + * @details This function can be called only for MEDIA_STREAMER_SINK_TYPE_CUSTOM + * @since_tizen 3.0 + * @param [in] sink Media streamer sink node handle + * @param [out] packet Media packet handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a sink node handle by calling media_streamer_sink_create() function + * @pre Set media_streamer_data_ready_cb by calling media_streamer_set_data_ready_cb() function. + * @see #media_packet_h + * @see media_streamer_sink_create() + */ +int media_streamer_pull_packet(media_streamer_node_h sink, + media_packet_h *packet); + +/** + * @brief Creates media streamer node except src and sink. + * @details Creates node specific @a type with specific format of input + * and output data. + * @since_tizen 3.0 + * @remarks You can release @a node using media_streamer_node_destroy() function + * @param [in] type Created node type + * @param [in] in_fmt Media format handle for input data + * @param [in] out_fmt Media format handle for output data + * @param [out] node Media streamer node handle to be created + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @see #media_streamer_node_type_e + * @see #media_format_h + * @see media_streamer_node_destroy() + */ +int media_streamer_node_create(media_streamer_node_type_e type, + media_format_h in_fmt, + media_format_h out_fmt, + media_streamer_node_h *node); + +/** + * @brief Adds node to media streamer. + * @since_tizen 3.0 + * @param [in] streamer Media streamer handle + * @param [in] node Media streamer node handle to be added + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create media streamer handle by calling media_streamer_create() function + * @pre Create node handle by calling media_streamer_node_create() function + * @see media_streamer_create() + * @see media_streamer_node_create() + * @see media_streamer_src_create() + * @see media_streamer_sink_create() + */ +int media_streamer_node_add(media_streamer_h streamer, + media_streamer_node_h node); + +/** + * @brief Destroys media streamer node. + * @since_tizen 3.0 + * @param [in] node Media streamer node handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create node handle by calling media_streamer_node_create() function + * @pre If the node was added to media streamer, it have to be removed by calling media_streamer_node_remove() function + * @see media_streamer_node_create() + * @see media_streamer_src_create() + * @see media_streamer_sink_create() + * @see media_streamer_node_remove() + */ +int media_streamer_node_destroy(media_streamer_node_h node); + +/** + * @brief Remove media streamer node from streamer. + * @since_tizen 3.0 + * @remarks If the node is linked, it will be unlinked before removing. + * @param [in] streamer Media streamer handle + * @param [in] node Media streamer node handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Add node to streamer by calling media_streamer_node_add() function + * @see media_streamer_node_add() + */ +int media_streamer_node_remove(media_streamer_h streamer, + media_streamer_node_h node); + +/** + * @brief Sets media format for media streamer node. + * @since_tizen 3.0 + * @param [in] node Media streamer node handle + * @param [in] fmt Media format handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create node handle by calling media_streamer_node_create() function + * @see #media_format_h + */ +int media_streamer_node_set_format(media_streamer_node_h node, + media_format_h fmt); + +/** + * @brief Gets media format for media streamer node. + * @since_tizen 3.0 + * @param [in] node Media streamer node handle + * @param [out] fmt Media format handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a source node handle by calling media_streamer_node_create() function + * @see #media_format_h + */ +int media_streamer_node_get_format(media_streamer_node_h node, + media_format_h *fmt); + +/** + * @brief Links two media streamer nodes. + * @since_tizen 3.0 + * @param [in] src_node Media streamer node handle + * @param [in] src_pad The name of the source pad of the source node + * @param [in] dest_node The destination media streamer node handle + * @param [in] sink_pad The name of the sink pad of the destination node + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a source node and a destination node handles + * by calling media_streamer_node_create() function + * and add the nodes into streamer by calling media_streamer_node_add() function. + * @see media_streamer_node_create() + * @see media_streamer_node_add() + */ +int media_streamer_node_link(media_streamer_node_h src_node, + const char *src_pad, + media_streamer_node_h dest_node, + const char *sink_pad); + +/** + * @brief Gets formats of node pads. + * @since_tizen 3.0 + * @remark After using the src_fmt and sink_fmt, it have to be free + * @param [in] node Media streamer node handle + * @param [out] src_fmt Array of source pad formats + * @param [out] sink_fmt Array of sink pad formats + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a node handle by calling media_streamer_node_create() function + * @see media_streamer_node_create() + * @see media_streamer_src_create() + * @see media_streamer_sink_create() + */ +int media_streamer_node_get_pad_format(media_streamer_node_h node, + char **src_fmt, + char **sink_fmt); + +/** + * @brief Sets parameters of node. + * @details Many parameters can be set at one time all together by using bundle. + * @since_tizen 3.0 + * @param [in] node Media streamer node handle + * @param [in] param_list Key value array of media streamer node parameters + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a node handle by calling media_streamer_node_create() function. + * @pre Get param list to set by calling media_streamer_node_get_param_list() function. + * @see media_streamer_node_create() + * @see media_streamer_src_create() + * @see media_streamer_sink_create() + * @see media_streamer_node_get_param_list() + * @see media_streamer_node_set_single_param() + */ +int media_streamer_node_set_params(media_streamer_node_h node, + bundle *param_list); + +/** + * @brief Sets single parameter of node. + * @details Sets parameter one by one without creating param bundle. + * @since_tizen 3.0 + * @param [in] node Media streamer node handle + * @param [in] param_name Param name of node + * @param [in] param_value Parm value of node + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a node handle by calling media_streamer_node_create() function. + * @pre Get param list to set by calling media_streamer_node_get_param_list() function. + * @see media_streamer_node_create() + * @see media_streamer_src_create() + * @see media_streamer_sink_create() + * @see media_streamer_node_get_param_list() + * @see media_streamer_node_set_params() + */ +int media_streamer_node_set_single_param(media_streamer_node_h node, + const char *param_name, const char *param_value); + +/** + * @brief Gets node parameter list. + * @since_tizen 3.0 + * @remark After using param_list, it have to be free by calling bundle_free() in bundle.h + * @param [in] node Media streamer node handle + * @param [out] param_list Key value array of media streamer node parameters + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a node handle by calling media_streamer_node_create() function + * @post Set params which are needed to set by calling media_streamer_node_set_params() function. + * @see media_streamer_node_create() + * @see media_streamer_src_create() + * @see media_streamer_sink_create() + * @see media_streamer_node_set_params() + */ +int media_streamer_node_get_param_list(media_streamer_node_h node, + bundle **param_list); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIASTREAMER_H__ */ diff --git a/include/media_streamer_gst.h b/include/media_streamer_gst.h new file mode 100755 index 0000000..939fd4f --- /dev/null +++ b/include/media_streamer_gst.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#define DOT_FILE_NAME "streamer" + +#define MEDIA_STREAMER_PIPELINE_NAME "media-streamer-pipeline" +#define MEDIA_STREAMER_SRC_BIN_NAME "streamer_src" +#define MEDIA_STREAMER_VIDEO_SINK_BIN_NAME "streamer_video_sink" +#define MEDIA_STREAMER_AUDIO_SINK_BIN_NAME "streamer_audio_sink" +#define MEDIA_STREAMER_TOPOLOGY_BIN_NAME "streamer_topology" + +/** + * @brief Generates dot files for GStreamer pipeline. + * + * @since_tizen 3.0 + */ +void __ms_generate_dots(GstElement *bin, gchar *name_tag); + +/** + * @brief Returns the string representation of GST_STATE. + * + * @since_tizen 3.0 + */ +const char *_ms_state_to_string(GstState state); + +/** + * @brief Creates GstElement by plugin name. + * + * @since_tizen 3.0 + */ +GstElement *__ms_element_create(const char *plugin_name, const char *name); + +/** + * @brief Creates camera GstElement by camera plugin name. + * + * @since_tizen 3.0 + */ +GstElement *__ms_camera_element_create(const char *microphone_plugin_name); + +/** + * @brief Creates encoder GstElement by mime type. + * + * @since_tizen 3.0 + */ +GstElement *__ms_video_encoder_element_create(dictionary *dict, media_format_mimetype_e mime); + +/** + * @brief Creates decoder GstElement by mime type. + * + * @since_tizen 3.0 + */ +GstElement *__ms_video_decoder_element_create(dictionary *dict, media_format_mimetype_e mime); + +/** + * @brief Creates audio encoder GstElement. + * + * @since_tizen 3.0 + */ +GstElement *__ms_audio_encoder_element_create(void); + +/** + * @brief Creates rtp container GstElement. + * + * @since_tizen 3.0 + */ +GstElement *__ms_rtp_element_create(media_streamer_node_s *ms_node); + +/** + * @brief Parse param for RTP node type. + * + * @since_tizen 3.0 + */ +int __ms_rtp_set_param( + media_streamer_node_s *node, + const gchar *param_key, + const gchar *param_value); + +/** + * @brief Creates pipeline, bus and src/sink/topology bins. + * + * @since_tizen 3.0 + */ +int __ms_pipeline_create(media_streamer_s *ms_streamer); + +/** + * @brief Adds node to bin + * + * @since_tizen 3.0 + */ +int __ms_add_node_into_bin(media_streamer_s *ms_streamer,media_streamer_node_s *ms_node); + +/** + * @brief Sets GstElement into state. + * + * @since_tizen 3.0 + */ +int __ms_element_set_state(GstElement *gst_element, GstState gst_state); + +/** + * @brief Sets mediaformat into GstElement. + * + * @since_tizen 3.0 + */ +int __ms_element_set_fmt(media_streamer_node_s *node, media_format_h fmt); diff --git a/include/media_streamer_node.h b/include/media_streamer_node.h new file mode 100755 index 0000000..8843ccf --- /dev/null +++ b/include/media_streamer_node.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +/** + * @brief Creates media streamer node using input and output format. + * + * @since_tizen 3.0 + */ +int __ms_node_create(media_streamer_node_s *node, + media_format_h in_fmt, + media_format_h out_fmt); + +/** + * @brief Creates media streamer source node. + * + * @since_tizen 3.0 + */ +int __ms_src_node_create(media_streamer_node_s *node); + +/** + * @brief Creates media streamer sink node. + * + * @since_tizen 3.0 + */ +int __ms_sink_node_create(media_streamer_node_s *node); + +/** + * @brief Destroys media streamer node. + * + * @since_tizen 3.0 + */ +void __ms_node_destroy(void *data); + +/** + * @brief Inserts media streamer node into nodes table. + * + * @since_tizen 3.0 + */ +void __ms_node_insert_into_table(GHashTable *nodes_table, + media_streamer_node_s *ms_node); + +/** + * @brief Remove media streamer node from nodes table. + * + * @since_tizen 3.0 + */ +int __ms_node_remove_from_table(GHashTable *nodes_table, + media_streamer_node_s *ms_node); + +/** + * @brief Reads node parameters from user's bundle object. + * + * @since_tizen 3.0 + */ +int __ms_node_read_params_from_bundle (media_streamer_node_s *node, + bundle *param_list); + +/** + * @brief Writes GstElement properties into user's bundle object. + * + * @since_tizen 3.0 + */ +int __ms_node_write_params_into_bundle (media_streamer_node_s *node, + bundle *param_list); diff --git a/include/media_streamer_priv.h b/include/media_streamer_priv.h new file mode 100755 index 0000000..10070cc --- /dev/null +++ b/include/media_streamer_priv.h @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TIZEN_MEDIASTREAMER_PRIVATE_H__ +#define __TIZEN_MEDIASTREAMER_PRIVATE_H__ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include + +#include +#include + +/** + * @brief Media Streamer callbacks structure. + * + * @since_tizen 3.0 + */ +typedef struct +{ + void *callback; + void *user_data; +} media_streamer_callback_s; + +/** + * @brief Media Streamer source callbacks structure. + * + * @since_tizen 3.0 + */ +typedef struct +{ + media_streamer_callback_s enough_data_cb; + media_streamer_callback_s need_data_cb; +} media_streamer_src_callbacks_s; + +/** + * @brief Media Streamer sink callbacks structure. + * + * @since_tizen 3.0 + */ +typedef struct +{ + media_streamer_callback_s data_ready_cb; + media_streamer_callback_s eos_cb; +} media_streamer_sink_callbacks_s; + +/** + * @brief Media Streamer type handle. + * + * @since_tizen 3.0 + */ +typedef struct +{ + media_streamer_ini_t ini; + GstElement *pipeline; + + GstElement *src_bin; + GstElement *sink_video_bin; + GstElement *sink_audio_bin; + GstElement *topology_bin; + + GHashTable *nodes_table; + GMutex mutex_lock; + + GstBus *bus; + guint bus_watcher; + + media_streamer_state_e state; + + media_streamer_callback_s error_cb; + media_streamer_callback_s state_changed_cb; +} media_streamer_s; + +/** + * @brief Media Streamer node type handle. + * + * @since_tizen 3.0 + */ +typedef int (*media_streamer_node_set_param)( + struct media_streamer_node_s *node, + const gchar *param_key, + const gchar *param_value); + +/** + * @brief Media Streamer node type handle. + * + * @since_tizen 3.0 + */ +typedef struct +{ + GstElement *gst_element; + char *name; + media_streamer_s *parent_streamer; + media_streamer_node_type_e type; + int subtype; + media_streamer_node_set_param set_param; + void *callbacks_structure; +} media_streamer_node_s; + +/* Private functions definition */ + +/** + * @brief Destroys media streamer structure. + * + * @since_tizen 3.0 + */ +void __ms_streamer_destroy(media_streamer_s *ms_streamer); + +/** + * @brief Creates media streamer structure. + * + * @since_tizen 3.0 + */ +int __ms_create(media_streamer_s *ms_streamer); + +/** + * @brief Changes state of media streamer. + * + * @since_tizen 3.0 + */ +int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e state); + +#ifdef __cplusplus +} + +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIASTREAMER_PRIVATE_H__ */ diff --git a/include/media_streamer_util.h b/include/media_streamer_util.h new file mode 100755 index 0000000..dbd052c --- /dev/null +++ b/include/media_streamer_util.h @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MEDIA_STREAMER_UTIL_H__ +#define __MEDIA_STREAMER_UTIL_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* DLog Utils*/ +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "CAPI_MEDIASTREAMER" + +#define FONT_COLOR_RESET "\033[0m" +#define FONT_COLOR_RED "\033[31m" +#define FONT_COLOR_GREEN "\033[32m" +#define FONT_COLOR_YELLOW "\033[33m" +#define FONT_COLOR_BLUE "\033[34m" +#define FONT_COLOR_PURPLE "\033[35m" +#define FONT_COLOR_CYAN "\033[36m" +#define FONT_COLOR_GRAY "\033[37m" + +#define ms_debug(fmt, arg...) do { \ + LOGD(FONT_COLOR_RESET""fmt"", ##arg); \ +} while(0) + +#define ms_info(fmt, arg...) do { \ + LOGI(FONT_COLOR_GREEN""fmt"", ##arg); \ +} while(0) + +#define ms_error(fmt, arg...) do { \ + LOGE(FONT_COLOR_RED""fmt"", ##arg); \ +} while(0) + +#define ms_debug_fenter() do { \ + LOGD(FONT_COLOR_YELLOW""); \ +} while(0) + +#define ms_debug_fleave() do { \ + LOGD(FONT_COLOR_PURPLE""); \ +} while(0) + +#define ms_retm_if(expr, fmt, arg...) do { \ + if(expr) { \ + LOGE(FONT_COLOR_RED""fmt"", ##arg); \ + return; \ +} \ +} while(0) + +#define ms_retvm_if(expr, val, fmt, arg...) do { \ + if(expr) { \ + LOGE(FONT_COLOR_RED""fmt"", ##arg); \ + return(val); \ +} \ +} while(0) + + +#define MS_SAFE_FREE(src) {if(src) {free(src); src = NULL;}} +#define MS_SAFE_GFREE(src) {if(src) {g_free(src); src = NULL;}} +#define MS_SAFE_UNREF(src) {if(src) {gst_object_unref(GST_OBJECT(src)); src = NULL;}} +#define MS_TABLE_SAFE_UNREF(src) {if(src) {g_hash_table_unref(src); src = NULL;}} + +/* Ini Utils */ +#define MEDIA_STREAMER_INI_DEFAULT_PATH "/usr/etc/media_streamer.ini" +#define MEDIA_STREAMER_INI_MAX_STRLEN 100 + +/** + * @brief Media Streamer ini settings structure. + * + * @since_tizen 3.0 + */ +typedef struct __media_streamer_ini +{ + /* general */ + gboolean generate_dot; + +} media_streamer_ini_t; + +/*Test elements*/ +#define DEFAULT_VIDEO_TEST_SOURCE "videotestsrc" +#define DEFAULT_AUDIO_TEST_SOURCE "audiotestsrc" +#define DEFAULT_FAKE_SINK "fakesink" +#define DEFAULT_QUEUE "queue" + +/* setting default values if each value is not specified in .ini file */ +/* general */ +#define DEFAULT_GENERATE_DOT FALSE +#define DEFAULT_AUDIO_SOURCE "alsasrc" +#define DEFAULT_CAMERA_SOURCE "camerasrc" +#define DEFAULT_VIDEO_SOURCE "ximagesrc" +#define DEFAULT_AUDIO_SINK "pulsesink" +#define DEFAULT_VIDEO_SINK "autovideosink" + +/* udp streaming */ +#define DEFAULT_UDP_SOURCE "udpsrc" +#define DEFAULT_UDP_SINK "udpsink" +#define DEFAULT_RTP_BIN "rtpbin" + +/* video format defaults */ +#define DEFAULT_VIDEO_ENCODER "omxh264enc" +#define DEFAULT_VIDEO_DECODER "omxh264dec" +#define DEFAULT_VIDEO_PARSER "h264parse" +#define DEFAULT_VIDEO_RTPPAY "rtph264pay" +#define DEFAULT_VIDEO_RTPDEPAY "rtph264depay" + +/* audio format defaults */ +#define DEFAULT_AUDIO_ENCODER "omxh264enc" +#define DEFAULT_AUDIO_DECODER "omxh264dec" +#define DEFAULT_AUDIO_PARSER "h264parse" +#define DEFAULT_AUDIO_RTPPAY "rtph264pay" +#define DEFAULT_AUDIO_RTPDEPAY "rtph264depay" + +#define MEDIA_STREAMER_DEFAULT_CAMERA_FORMAT "video/x-raw,width=320,height=240" +#define MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT "audio/x-raw,channels=1,rate=44100,format=S16BE" +#define MEDIA_STREAMER_DEFAULT_ENCODER_FORMAT "video/x-h264,stream-format=byte-stream,profile=high" + +#define MEDIA_STREAMER_DEFAULT_DOT_DIR "/tmp" +#define MEDIA_STREAMER_DEFAULT_INI \ +"\ +[general] \n\ +; generating dot file representing pipeline state \n\ +generate dot = no \n\ +dot dir = /tmp \n\ +\n\ +\n\ +[sources] \n\ +\n\ +audio_source = pulsesrc \n\ +camera_source = camerasrc \n\ +video_source = ximagesrc \n\ +udp_source = udpsrc \n\ +\n\ +\n\ +[sinks] \n\ +\n\ +audio_sink = pulsesink \n\ +video_sink = autovideosink \n\ +udp_sink = udpsink \n\ +\n\ +\n\ +[h263] \n\ +\n\ +encoder = avenc_h263 \n\ +decoder = avdec_h263 \n\ +rtppay = rtph263pay \n\ +rtpdepay = rtph263depay \n\ +parser = h263parse \n\ +\n\ +\n\ +[h264] \n\ +\n\ +encoder = omxh264enc \n\ +decoder = avdec_h264 \n\ +rtppay = rtph264pay \n\ +rtpdepay = rtph264depay \n\ +parser = h264parse \n\ +\n\ +\n\ +[audio-raw] \n\ +\n\ +encoder = \n\ +decoder = \n\ +rtppay = rtpL16pay \n\ +rtpdepay = rtpL16depay \n\ +\n\ +" + +/** + * @brief Load media streamer settings from ini file. + * + * @since_tizen 3.0 + */ +int __ms_load_ini_settings(media_streamer_ini_t *ini); + +/** + * @brief Load settings from ini file into dictionary object. + * + * @since_tizen 3.0 + */ +gboolean __ms_load_ini_dictionary(dictionary **dict); + +/** + * @brief Destroys ini dictionary object and frees all resources. + * + * @since_tizen 3.0 + */ +gboolean __ms_destroy_ini_dictionary(dictionary *dict); + +/** + * @brief Read and copy string reading from ini file. + * + * @since_tizen 3.0 + */ +gchar *__ms_ini_get_string(dictionary *dict, const char *ini_path, + char *default_str); + +/** + * @brief Converts Media Format mime type into string. + * + * @since_tizen 3.0 + */ +const gchar *__ms_convert_mime_to_string(media_format_mimetype_e mime); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packaging/capi-media-streamer.manifest b/packaging/capi-media-streamer.manifest new file mode 100755 index 0000000..56b1c62 --- /dev/null +++ b/packaging/capi-media-streamer.manifest @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec new file mode 100755 index 0000000..cf1d34b --- /dev/null +++ b/packaging/capi-media-streamer.spec @@ -0,0 +1,77 @@ +Name: capi-media-streamer +Summary: A Media Streamer library in Tizen Native API +Version: 0.1.1 +Release: 0 +Group: Multimedia/API +License: Apache-2.0 +URL: http://source.tizen.org +Source0: %{name}-%{version}.tar.gz +Source1001: capi-media-streamer.manifest +BuildRequires: cmake +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(mm-common) +BuildRequires: pkgconfig(capi-base-common) +BuildRequires: pkgconfig(capi-media-tool) +BuildRequires: pkgconfig(libtbm) +BuildRequires: pkgconfig(gstreamer-1.0) +BuildRequires: pkgconfig(gstreamer-plugins-base-1.0) +BuildRequires: pkgconfig(gstreamer-video-1.0) +BuildRequires: pkgconfig(gstreamer-app-1.0) +BuildRequires: pkgconfig(iniparser) +BuildRequires: pkgconfig(bundle) + +%description +A MediaStreamer library in Tizen Native API. + +%package devel +Summary: Multimedia Streamer Library in Tizen Native API (Development) +Group: TO_BE/FILLED_IN +Requires: %{name} = %{version}-%{release} + +%description devel +MediaStreamer Library in Tizen Native API (DEV). + +%prep +%setup -q +cp %{SOURCE1001} . + +%build +%if 0%{?sec_build_binary_debug_enable} +export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE" +export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE" +export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE" +%endif +MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` +cmake . -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER} + + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}/usr/share/license +mkdir -p %{buildroot}/usr/bin +cp LICENSE.APLv2 %{buildroot}/usr/share/license/%{name} +cp test/media_streamer_test %{buildroot}/usr/bin + +%make_install + +%post +/sbin/ldconfig + +%postun -p /sbin/ldconfig + + +%files +%manifest capi-media-streamer.manifest +%{_libdir}/libcapi-media-streamer.so.* +%{_datadir}/license/%{name} +/usr/bin/* + +%files devel +%{_includedir}/media/*.h +%{_libdir}/pkgconfig/*.pc +%{_libdir}/libcapi-media-streamer.so + + diff --git a/src/media_streamer.c b/src/media_streamer.c new file mode 100755 index 0000000..ccfedcc --- /dev/null +++ b/src/media_streamer.c @@ -0,0 +1,517 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include + +/* +* Public Implementation +*/ + +int media_streamer_src_create(media_streamer_src_type_e type, + media_streamer_node_h *src) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + media_streamer_node_s *ms_src = (media_streamer_node_s*)src; + ms_retvm_if(ms_src == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + ms_src = (media_streamer_node_s *)calloc(1, sizeof(media_streamer_node_s)); + ms_retvm_if(ms_src == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error allocation memory"); + + ms_src->type = MEDIA_STREAMER_NODE_TYPE_SRC; + ms_src->subtype = (media_streamer_src_type_e)type; + ret = __ms_src_node_create(ms_src); + if(ret != MEDIA_STREAMER_ERROR_NONE) + { + MS_SAFE_FREE(ms_src); + ms_error( "Error creating Src node [%d]",ret); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + ms_info("Source node [%s] created", ms_src->name); + *src = (media_streamer_node_h)ms_src; + + return ret; +} + +int media_streamer_sink_create(media_streamer_sink_type_e type, + media_streamer_node_h *sink) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + media_streamer_node_s *ms_sink = (media_streamer_node_s*)sink; + ms_retvm_if(ms_sink == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + ms_sink = (media_streamer_node_s *)calloc(1, sizeof(media_streamer_node_s)); + ms_retvm_if(ms_sink == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error allocation memory"); + + ms_sink->type = MEDIA_STREAMER_NODE_TYPE_SINK; + ms_sink->subtype = (media_streamer_sink_type_e)type; + ret = __ms_sink_node_create(ms_sink); + if(ret != MEDIA_STREAMER_ERROR_NONE) + { + MS_SAFE_FREE(ms_sink); + ms_error( "Error creating Sink node [%d]",ret); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + ms_info("Sink node [%s] created", ms_sink->name); + *sink = (media_streamer_node_h)ms_sink; + + return ret; +} + +int media_streamer_node_create(media_streamer_node_type_e type, + media_format_h in_fmt, + media_format_h out_fmt, + media_streamer_node_h *node) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + media_streamer_node_s *ms_node = (media_streamer_node_s*)node; + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + ms_node = (media_streamer_node_s *)calloc(1, sizeof(media_streamer_node_s)); + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error allocation memory"); + + ms_node->type = type; + ms_node->subtype = 0; + + ret = __ms_node_create(ms_node, in_fmt, out_fmt); + if(ret != MEDIA_STREAMER_ERROR_NONE) + { + MS_SAFE_FREE(ms_node); + ms_error( "Error creating Node [%d]",ret); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + ms_info("Node [%s] created", ms_node->name); + *node = (media_streamer_node_h)ms_node; + + return ret; +} + +int media_streamer_node_destroy(media_streamer_node_h node) +{ + media_streamer_node_s *ms_node = (media_streamer_node_s*)node; + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + if (ms_node->parent_streamer == NULL) + { + // This node was not added into any media streamer + __ms_node_destroy(ms_node); + } + else + { + int ret = __ms_node_remove_from_table(ms_node->parent_streamer->nodes_table, ms_node); + ms_retvm_if(ret != MEDIA_STREAMER_ERROR_NONE, MEDIA_STREAMER_ERROR_INVALID_OPERATION, + "Current key was not removed from nodes_table"); + } + + ms_info("Node destroyed successfully"); + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_node_add(media_streamer_h streamer, + media_streamer_node_h node) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + ms_retvm_if(streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + media_streamer_node_s* ms_node = (media_streamer_node_s*)node; + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + __ms_node_insert_into_table(ms_streamer->nodes_table,ms_node); + ms_node->parent_streamer = ms_streamer; + + __ms_add_node_into_bin(ms_streamer, ms_node); + + g_mutex_unlock(&ms_streamer->mutex_lock); + + return ret; +} + +int media_streamer_prepare(media_streamer_h streamer) +{ + media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(ms_streamer->pipeline == NULL, MEDIA_STREAMER_ERROR_INVALID_STATE, "Pipeline doesn`t exist"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + if(ms_streamer->state > MEDIA_STREAMER_STATE_IDLE) + { + ms_error("Error: Media streamer already prepared [%d]!", + MEDIA_STREAMER_ERROR_INVALID_OPERATION); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_READY) != MEDIA_STREAMER_ERROR_NONE) + { + ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + __ms_generate_dots(ms_streamer->pipeline, "prepare"); + + g_mutex_unlock(&ms_streamer->mutex_lock); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_unprepare(media_streamer_h streamer) +{ + media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(ms_streamer->pipeline == NULL, MEDIA_STREAMER_ERROR_INVALID_STATE, "Pipeline doesn`t exist"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_IDLE) != MEDIA_STREAMER_ERROR_NONE) + { + ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + g_mutex_unlock(&ms_streamer->mutex_lock); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_play(media_streamer_h streamer) +{ + media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + if(ms_streamer->state < MEDIA_STREAMER_STATE_READY) + { + ms_error("Error: Media streamer must be prepared first [%d]!", + MEDIA_STREAMER_ERROR_INVALID_OPERATION); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_PLAYING) != MEDIA_STREAMER_ERROR_NONE) + { + ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + g_mutex_unlock(&ms_streamer->mutex_lock); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_create(media_streamer_h *streamer) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + media_streamer_s *ms_streamer = NULL; + ms_retvm_if(streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + ms_streamer = (media_streamer_s *)calloc(1, sizeof(media_streamer_s)); + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error allocation memory"); + + /* create streamer lock */ + g_mutex_init(&ms_streamer->mutex_lock); + + ms_streamer->state = MEDIA_STREAMER_STATE_NONE; + + ret = __ms_create(ms_streamer); + if(ret!=MEDIA_STREAMER_ERROR_NONE) + { + ms_error("Error creating Media Streamer"); + __ms_streamer_destroy(ms_streamer); + + g_mutex_clear(&ms_streamer->mutex_lock); + + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_IDLE) != MEDIA_STREAMER_ERROR_NONE) + { + ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + *streamer = ms_streamer; + ms_info("Media Streamer created successfully"); + return ret; +} + +int media_streamer_destroy(media_streamer_h streamer) +{ + media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + __ms_streamer_destroy(ms_streamer); + + g_mutex_unlock(&ms_streamer->mutex_lock); + g_mutex_clear(&ms_streamer->mutex_lock); + + ms_info("Media Streamer destroyed successfully"); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_set_error_cb(media_streamer_h streamer, + media_streamer_error_cb callback, + void *data) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_unset_error_cb(media_streamer_h streamer) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_set_state_change_cb(media_streamer_h streamer, + media_streamer_state_changed_cb callback, + void *data) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_unset_state_change_cb(media_streamer_h streamer) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_src_set_buffer_status_cb(media_streamer_node_h source, + media_streamer_custom_buffer_status_cb callback, + void *user_data) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_src_unset_buffer_status_cb(media_streamer_node_h source) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_sink_set_data_ready_cb(media_streamer_node_h sink, + media_streamer_sink_data_ready_cb callback, + void *data) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_sink_unset_data_ready_cb(media_streamer_node_h source) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_sink_set_eos_cb(media_streamer_node_h sink, + media_streamer_sink_eos_cb callback, + void *data) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_sink_unset_eos_cb(media_streamer_node_h source) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_pause(media_streamer_h streamer) +{ + media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_PAUSED) != MEDIA_STREAMER_ERROR_NONE) + { + ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + g_mutex_unlock(&ms_streamer->mutex_lock); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_stop(media_streamer_h streamer) +{ + media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + if(ms_streamer->state < MEDIA_STREAMER_STATE_READY) + { + ms_error("Error: Media streamer must be prepared first [%d]!", + MEDIA_STREAMER_ERROR_INVALID_OPERATION); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_READY) != MEDIA_STREAMER_ERROR_NONE) + { + ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + g_mutex_unlock(&ms_streamer->mutex_lock); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_get_state(media_streamer_h streamer, + media_streamer_state_e *state) +{ + media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + *state = ms_streamer->state; + + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_seek(media_streamer_h streamer, + media_streamer_time_value time) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_push_packet(media_streamer_node_h src, + media_packet_h packet) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_pull_packet(media_streamer_node_h sink, + media_packet_h *packet) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_node_set_format(media_streamer_node_h node, + media_format_h fmt) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + media_streamer_node_s *ms_node = (media_streamer_node_s*)node; + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Format is NULL"); + + ret = __ms_element_set_fmt(node, fmt); + return ret; +} + +int media_streamer_node_get_format(media_streamer_node_h node, + media_format_h *fmt) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + media_streamer_node_s *ms_node = (media_streamer_node_s*)node; + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Format is NULL"); + + + return ret; +} + +int media_streamer_node_link(media_streamer_node_h src_node, + const char *src_pad, + media_streamer_node_h dest_node, + const char *sink_pad) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + media_streamer_node_s *ms_src_node = (media_streamer_node_s*)src_node; + ms_retvm_if(ms_src_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + media_streamer_node_s *ms_dest_node = (media_streamer_node_s*)dest_node; + ms_retvm_if(ms_dest_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + gchar *src_element_name = gst_element_get_name(ms_src_node->gst_element); + gchar *sink_element_name = gst_element_get_name(ms_dest_node->gst_element); + + ms_retvm_if(src_pad == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Pad is NULL"); + ms_retvm_if(sink_pad == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Pad is NULL"); + + gboolean link_ret; + + link_ret = gst_element_link_pads (ms_src_node->gst_element, src_pad, ms_dest_node->gst_element, sink_pad); + if(!link_ret) + { + ms_error("Can not link [%s]->%s pad to [%s]->%s pad, ret code [%d] ", src_pad, sink_pad, src_element_name, sink_element_name, link_ret); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + MS_SAFE_GFREE(src_element_name); + MS_SAFE_GFREE(sink_element_name); + return ret; +} + +int media_streamer_node_get_pad_format(media_streamer_node_h node, + char **in_fmt, + char **out_fmt) +{ + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_node_set_params(media_streamer_node_h node, + bundle *param_list) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + media_streamer_node_s *ms_node = (media_streamer_node_s*)node; + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(ms_node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(param_list == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Parameters list is NULL"); + + ret = __ms_node_read_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; +} + +int media_streamer_node_get_param_list(media_streamer_node_h node, + bundle **param_list) +{ + media_streamer_node_s *ms_node =(media_streamer_node_s*)node; + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(param_list == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Param list pionter is NULL"); + + bundle *ms_params = NULL; + ms_params = bundle_create(); + ms_retvm_if(ms_params == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Error creating new params object"); + + if (__ms_node_write_params_into_bundle(ms_node, ms_params) != MEDIA_STREAMER_ERROR_NONE) + { + ms_info("Node [%s] do not have any params.", ms_node->name); + bundle_free(ms_params); + *param_list = NULL; + + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + *param_list = ms_params; + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c new file mode 100755 index 0000000..e452e03 --- /dev/null +++ b/src/media_streamer_gst.c @@ -0,0 +1,1146 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#define MS_ELEMENT_IS_SINK(el) g_str_has_suffix(el, "sink") +#define MS_ELEMENT_IS_SOURCE(el) g_str_has_suffix(el, "source") +#define MS_ELEMENT_IS_AUDIO(el) g_str_has_prefix(el, "audio") +#define MS_ELEMENT_IS_VIDEO(el) g_str_has_prefix(el, "video") + +void __ms_generate_dots(GstElement *bin, gchar *name_tag) +{ + gchar *dot_name; + ms_retm_if(bin == NULL, "Handle is NULL"); + + if (!name_tag) + { + dot_name = g_strdup(DOT_FILE_NAME); + } + else + { + dot_name = g_strconcat (DOT_FILE_NAME, ".", name_tag, NULL); + } + + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(bin), GST_DEBUG_GRAPH_SHOW_ALL, dot_name); + + MS_SAFE_GFREE (dot_name); +} + +const char *_ms_state_to_string(GstState state) +{ + static const char pending[] = "PENDING\0"; + static const char null_s[] = "NULL\0"; + static const char ready[] = "READY\0"; + static const char paused[] = "PAUSED\0"; + static const char playing[] = "PLAYING\0"; + switch(state) + { + case GST_STATE_VOID_PENDING: + return pending; + break; + case GST_STATE_NULL: + return null_s; + break; + case GST_STATE_READY: + return ready; + break; + case GST_STATE_PAUSED: + return paused; + break; + case GST_STATE_PLAYING: + return playing; + break; + default: + return "\0"; + break; + }; + return 0; +} + +static int __ms_add_ghostpad(GstElement *gst_element, + const char *pad_name, + GstElement *gst_bin, + const char *ghost_pad_name) +{ + ms_retvm_if(!ghost_pad_name || !gst_bin, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + int ret = MEDIA_STREAMER_ERROR_NONE; + + GstPad *ghost_pad = NULL; + gchar *bin_name = gst_element_get_name(gst_bin); + + if(!gst_element || !pad_name) + { + ghost_pad = gst_ghost_pad_new_no_target(ghost_pad_name, GST_PAD_SRC); + gst_element_add_pad(GST_ELEMENT(gst_bin), ghost_pad); + ms_info("Added %s empty ghostpad into [%s]", bin_name); + ret = MEDIA_STREAMER_ERROR_NONE; + } + else + { + gchar *element_name = gst_element_get_name(gst_element); + GstPad *element_pad = gst_element_get_static_pad(gst_element, pad_name); + if(!element_pad) + { + //maybe it is request pad + element_pad = gst_element_get_request_pad(gst_element, pad_name); + } + if(element_pad != NULL) + { + ghost_pad = gst_ghost_pad_new(ghost_pad_name, element_pad); + gst_pad_set_active(ghost_pad, TRUE); + + gst_element_add_pad(GST_ELEMENT(gst_bin), ghost_pad); + ms_info("Added %s ghostpad from [%s] into [%s]", pad_name, element_name, bin_name); + MS_SAFE_UNREF(element_pad); + MS_SAFE_GFREE(element_name); + + ret = MEDIA_STREAMER_ERROR_NONE; + } + else + { + ms_error("Error: element [%s] does not have valid [%s] pad for adding into [%s] bin", + element_name, pad_name, bin_name); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } + + MS_SAFE_GFREE(bin_name); + + return ret; +} + +static GObject *__ms_get_property_owner(GstElement *element, const gchar *key, GValue *value) +{ + GParamSpec *param; + GObject *obj = NULL; + + if (GST_IS_CHILD_PROXY(element)) + { + int i; + int childs_count = gst_child_proxy_get_children_count(GST_CHILD_PROXY(element)); + + param = NULL; + for(i = 0; (i < childs_count) && (param == NULL); ++i) + { + obj = gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(element),i); + param = g_object_class_find_property(G_OBJECT_GET_CLASS(obj), key); + } + ms_retvm_if(param == NULL || obj == NULL, NULL, "Error: Bin object does not have property [%s].", key); + } + else + { + obj = G_OBJECT(element); + param = g_object_class_find_property + (G_OBJECT_GET_CLASS(obj), key); + } + + g_value_init(value, param->value_type); + + if (param->flags & G_PARAM_WRITABLE) + { + g_object_get_property(G_OBJECT(obj), key, value); + } + else + { + // Skip properties which user can not change. + ms_error("Error: node param [%s] is not writable!", key); + return NULL; + } + ms_info("%-20s: %s\n", g_param_spec_get_name(param), g_param_spec_get_blurb(param)); + + return obj; +} + +static void __ms_element_set_property(GstElement *element, const gchar *key, const gchar *param_value) +{ + gchar *element_name = gst_element_get_name(element); + GValue value = G_VALUE_INIT; + GObject *obj = __ms_get_property_owner(element, key, &value); + + if(obj == NULL) + { + ms_debug("Element [%s] does not have property [%s].", element_name, key); + MS_SAFE_GFREE(element_name); + return; + } + + switch(G_VALUE_TYPE(&value)) + { + case G_TYPE_STRING: + g_value_set_string(&value, param_value); + ms_info("Set string value: [%s]", g_value_get_string(&value)); + break; + + case G_TYPE_BOOLEAN: + { + gboolean bool_val = !g_strcmp0(param_value, "true") ? TRUE : FALSE; + g_value_set_boolean(&value, bool_val); + ms_info("Set boolean value: [%d]", g_value_get_boolean(&value)); + break; + } + + case G_TYPE_ULONG: + { + unsigned long pulong = atol(param_value); + g_value_set_ulong(&value, pulong); + ms_info("Set ulong value: [%lu]", g_value_get_ulong(&value)); + break; + } + + case G_TYPE_LONG: + { + long plong = atol(param_value); + g_value_set_long(&value, plong); + ms_info("Set long value: [%ld]", g_value_get_long(&value)); + break; + } + + case G_TYPE_UINT: + { + unsigned int puint = atoi(param_value); + g_value_set_uint(&value, puint); + ms_info("Set uint value: [%u]", g_value_get_uint(&value)); + break; + } + + case G_TYPE_INT: + { + int pint = atoi(param_value); + g_value_set_int(&value, pint); + ms_info("Set int value: [%d]", g_value_get_int(&value)); + break; + } + + case G_TYPE_UINT64: + { + unsigned long long puint64 = strtoull(param_value, NULL, 10); + g_value_set_uint64(&value, puint64); + ms_info("Set long value: [%llu]", g_value_get_uint64(&value)); + break; + } + + case G_TYPE_INT64: + { + long long pint64 = strtoll(param_value, NULL, 10); + g_value_set_int64(&value, pint64); + ms_info("Set long value: [%ll]", g_value_get_int64(&value)); + break; + } + case G_TYPE_FLOAT: + { + float pfloat = strtof(param_value, NULL); + g_value_set_float(&value, pfloat); + ms_info("Set long value: [%15.7g]", g_value_get_float(&value)); + break; + } + case G_TYPE_DOUBLE: + { + double pdouble = strtod(param_value, NULL); + g_value_set_double(&value, pdouble); + ms_info("Set long value: [%15.7g]", g_value_get_float(&value)); + break; + } + default: + if(G_VALUE_TYPE(&value) == GST_TYPE_CAPS) + { + GstCaps *caps = gst_caps_from_string(param_value); + + if (!caps) + { + ms_error("Can not create caps from param value."); + } + else + { + ms_info("Create Caps from params and set to the object."); + g_object_set(obj, key, caps, NULL); + gst_caps_unref(caps); + } + return; + } + else + { + ms_info("Got unknown type with param->value_type [%d]", G_VALUE_TYPE(&value)); + return; + } + break; + } + g_object_set_property(obj, key, &value); + MS_SAFE_GFREE(element_name); +} + +#if 0 +static void __ms_link_elements_on_pad_added_cb(GstPad *new_pad, GstElement *sink_element) +{ + GstPadLinkReturn ret; + GstPad *sink_pad; + gchar *new_pad_name = NULL; + gchar *sink_element_name = NULL; + gchar *peer_pad_name = NULL; + GstPad *peer_pad = NULL; + + sink_pad = gst_element_get_static_pad(sink_element, "sink"); + ms_retm_if(sink_pad == NULL, "Sinkpad is NULL"); + + sink_element_name = gst_element_get_name(sink_element); + new_pad_name = gst_pad_get_name(new_pad); + + if(!gst_pad_is_linked(sink_pad)) + { + ms_info("Pads [rtpbin].[%s] and [%s].[sink] are not linked\n", new_pad_name, sink_element_name); + + ret = gst_pad_link(new_pad, sink_pad); + if(GST_PAD_LINK_FAILED (ret)) + { + ms_error("Failed to link [rtpbin].[%s] and [%s].[sink]\n", new_pad_name, sink_element_name); + } + else + { + ms_info("Succeeded to link [rtpbin].[%s]->[%s].[sink]\n", new_pad_name, sink_element_name); + } + } + else + { + peer_pad = gst_pad_get_peer(sink_pad); + peer_pad_name = gst_pad_get_name(peer_pad); + + ms_debug("Pads [rtpbin].[%s]->[%s].[sink] are previously linked\n", peer_pad_name, sink_element_name); + + ret = gst_pad_unlink(peer_pad, sink_pad); + if(!ret) + { + ms_error("Filed to unlink pads [rtpbin].[%s] <-and-> [%s].[sink] \n", peer_pad_name, sink_element_name); + } + else + { + ms_info("Pads [rtpbin].[%s] <-and-> [%s].[sink] are unlinked successfully\n", peer_pad_name, sink_element_name); + } + + ret = gst_pad_link(new_pad, sink_pad); + if(GST_PAD_LINK_FAILED(ret)) + { + ms_error("Failed to link [rtpbin].[%s] and [%s].[sink]\n", new_pad_name, sink_element_name); + } + else + { + ms_info("Succeeded to link [rtpbin].[%s]->[%s].[sink]\n", new_pad_name, sink_element_name); + } + } + + MS_SAFE_GFREE(sink_element_name); + MS_SAFE_GFREE(new_pad_name); + MS_SAFE_GFREE(peer_pad_name); +} + +static void __ms_got_rtpstream_on_pad_added_cb(media_streamer_node_s *ms_node, GstPad *new_pad, const gchar *compared_type) +{ + GstPad *src_pad; + GstCaps *src_pad_caps = NULL; + GstStructure *src_pad_struct = NULL; + + gchar *sink_element_name = NULL; + GstElement *sink_element; + + GValue elem=G_VALUE_INIT; + const gchar *depay_klass_name = "Codec/Depayloader/Network/RTP"; + GstIterator *bin_iterator; + + gchar *new_pad_name = gst_pad_get_name(new_pad); + gchar *source_pad_name = g_strdup_printf("%s_source", compared_type); + + bin_iterator = gst_bin_iterate_elements(GST_BIN(ms_node->parent_streamer->topology_bin)); + while(GST_ITERATOR_OK == gst_iterator_next(bin_iterator, &elem)) + { + + sink_element = (GstElement *)g_value_get_object(&elem); + sink_element_name = gst_element_get_name(sink_element); + + const gchar *klass_name = gst_element_factory_get_klass(gst_element_get_factory(sink_element)); + + if( g_strrstr(klass_name, depay_klass_name)) + { + src_pad = gst_element_get_static_pad (sink_element, "src"); + ms_retm_if(src_pad == NULL, "Src pad is NULL"); + + src_pad_caps = gst_pad_query_caps(src_pad,NULL); + src_pad_struct = gst_caps_get_structure(src_pad_caps, 0); + const gchar *src_pad_type = gst_structure_get_name(src_pad_struct); + + if (g_strrstr(src_pad_type, compared_type)) + { + ms_debug("Element to connect [%s] has type [%s] \n", sink_element_name, src_pad_type); + GstPad *video_source_pad = gst_element_get_static_pad(ms_node->gst_element, source_pad_name); + + gst_ghost_pad_set_target(GST_GHOST_PAD(video_source_pad), new_pad); + gst_pad_set_active(video_source_pad, TRUE); + __ms_generate_dots(ms_node->parent_streamer->pipeline); + } + + gst_caps_unref(src_pad_caps); + + MS_SAFE_UNREF(src_pad); + } + g_value_reset(&elem); + } + g_value_unset(&elem); + gst_iterator_free(bin_iterator); + MS_SAFE_GFREE(sink_element_name); + MS_SAFE_GFREE(source_pad_name); + MS_SAFE_FREE(new_pad_name); +} +#endif + +static void __ms_rtpbin_pad_added_cb(GstElement *src, GstPad *new_pad, gpointer user_data) +{ + GstCaps *src_pad_caps = NULL; + GstStructure *src_pad_struct = NULL; + GstPad *target_pad = NULL; + + gchar *new_pad_name = NULL; + gchar *src_element_name = NULL; + + media_streamer_node_s *ms_node = (media_streamer_node_s *)user_data; + ms_retm_if(ms_node == NULL, "Handle is NULL"); + + new_pad_name = gst_pad_get_name(new_pad); + src_element_name = gst_element_get_name(src); + ms_debug("Pad [%s] added on [%s]\n", new_pad_name, src_element_name); + + target_pad = gst_ghost_pad_get_target(GST_GHOST_PAD(new_pad)); + src_pad_caps = gst_pad_query_caps(target_pad,NULL); + src_pad_struct = gst_caps_get_structure(src_pad_caps, 0); + + const gchar *src_pad_type = gst_structure_get_string(src_pad_struct, "media"); + ms_debug("type is [%s]", src_pad_type); + + if(ms_node->parent_streamer == NULL) + { + ms_error("Node doesn`t have parent streamer:\n"); + } + else + { + gchar *source_pad_name = NULL; + GstElement *sink_bin = NULL; + if(g_strrstr(src_pad_type, "video")) + { + source_pad_name = g_strdup_printf("%s_source", "video"); + sink_bin = ms_node->parent_streamer->sink_video_bin; + } + else if(g_strrstr(src_pad_type, "audio")) + { + source_pad_name = g_strdup_printf("%s_source", "audio"); + sink_bin = ms_node->parent_streamer->sink_audio_bin; + } + + if(source_pad_name != NULL) + { + if(gst_object_get_parent(GST_OBJECT(sink_bin)) == NULL) + { + gst_bin_add(GST_BIN(ms_node->parent_streamer->pipeline), sink_bin); + } + gst_element_sync_state_with_parent(sink_bin); + + + 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); + gst_pad_set_active(source_pad, TRUE); + + GstPad *sink_pad = gst_bin_find_unlinked_pad(GST_BIN(sink_bin), GST_PAD_SINK); + if(sink_pad != NULL) + { + __ms_add_ghostpad(gst_pad_get_parent(sink_pad), "sink", sink_bin, "sink"); + if (gst_element_link_pads(ms_node->gst_element, source_pad_name, sink_bin, "sink")) + { + __ms_element_set_state(ms_node->gst_element, GST_STATE_PLAYING); + __ms_generate_dots(ms_node->parent_streamer->pipeline, "playing"); + } + else + { + ms_error("Failed to link [rtp_containeer].[%s] and [sink_bin].[sink]\n", source_pad_name); + } + MS_SAFE_UNREF(sink_pad); + } + MS_SAFE_UNREF(source_pad); + MS_SAFE_GFREE(source_pad_name); + } + } + + gst_caps_unref(src_pad_caps); + MS_SAFE_UNREF(target_pad); + MS_SAFE_GFREE(new_pad_name); + MS_SAFE_GFREE(src_element_name); +} + +int __ms_element_set_state(GstElement *gst_element, GstState gst_state) +{ + ms_retvm_if(gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + GstStateChangeReturn ret_state; + gchar *element_name = gst_element_get_name(gst_element); + + ret_state = gst_element_set_state(gst_element, gst_state); + if(ret_state == GST_STATE_CHANGE_FAILURE) + { + ms_error("Failed to set element [%s] into %s state", element_name, _ms_state_to_string(gst_state)); + MS_SAFE_GFREE(element_name); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + MS_SAFE_GFREE(element_name); + return MEDIA_STREAMER_ERROR_NONE; +} + +GstElement *__ms_element_create(const char *plugin_name, const char *name) +{ + ms_retvm_if(plugin_name == NULL, (GstElement*)NULL, "Error empty plugin name"); + ms_info("Creating [%s] element", plugin_name); + return gst_element_factory_make(plugin_name, name); +} + +GstElement *__ms_camera_element_create(const char *camera_plugin_name) +{ + ms_retvm_if(camera_plugin_name == NULL, (GstElement*)NULL, "Error empty camera plugin name"); + + gboolean gst_ret = FALSE; + GstElement *camera_bin = gst_bin_new("camera_src"); + GstElement *camera_elem = __ms_element_create(camera_plugin_name, NULL); + GstElement *filter = __ms_element_create("capsfilter", NULL); + GstElement *scale = __ms_element_create("videoscale", NULL); + GstElement *videoconvert = __ms_element_create("videoconvert", NULL); + ms_retvm_if(!filter || !camera_elem || !camera_bin || !scale || !videoconvert , (GstElement*)NULL, + "Error: creating elements for camera bin"); + + GstCaps *videoCaps = gst_caps_from_string(MEDIA_STREAMER_DEFAULT_CAMERA_FORMAT); + g_object_set (G_OBJECT (filter), "caps", videoCaps, NULL); + gst_caps_unref(videoCaps); + + gst_bin_add_many(GST_BIN(camera_bin), camera_elem, filter, scale, videoconvert, NULL); + gst_ret = gst_element_link_many(camera_elem, filter, scale, videoconvert, NULL); + if (gst_ret != TRUE) + { + ms_error("Failed to link elements into camerabin"); + MS_SAFE_UNREF(camera_bin); + } + + __ms_add_ghostpad(videoconvert, "src", camera_bin, "src"); + + return camera_bin; +} + +GstElement *__ms_video_encoder_element_create(dictionary *dict , media_format_mimetype_e mime) +{ + char *plugin_name = NULL; + char *format_prefix = NULL; + + format_prefix = g_strdup_printf("%s:encoder", __ms_convert_mime_to_string(mime)); + plugin_name = __ms_ini_get_string(dict, format_prefix, DEFAULT_VIDEO_DECODER); + GstElement *encoder_elem = __ms_element_create(plugin_name,NULL); + MS_SAFE_FREE(format_prefix); + MS_SAFE_FREE(plugin_name); + + format_prefix = g_strdup_printf("%s:parser", __ms_convert_mime_to_string(mime)); + plugin_name = __ms_ini_get_string(dict, format_prefix, DEFAULT_VIDEO_PARSER); + GstElement *encoder_parser = __ms_element_create(plugin_name,NULL); + MS_SAFE_FREE(format_prefix); + MS_SAFE_FREE(plugin_name); + + gboolean gst_ret = FALSE; + GstElement *encoder_bin = gst_bin_new("video_encoder"); + GstElement *filter = __ms_element_create("capsfilter", NULL); + ms_retvm_if(!filter || !encoder_elem || !encoder_bin || !encoder_parser, (GstElement*)NULL, + "Error: creating elements for video encoder bin"); + + format_prefix = g_strdup_printf("video/x-%s,stream-format=byte-stream,profile=high", + __ms_convert_mime_to_string(mime)); + GstCaps *videoCaps = gst_caps_from_string(format_prefix); + g_object_set(G_OBJECT(filter), "caps", videoCaps, NULL); + MS_SAFE_FREE(format_prefix); + + gst_caps_unref(videoCaps); + + gst_bin_add_many(GST_BIN(encoder_bin), encoder_elem, filter, encoder_parser, NULL); + gst_ret = gst_element_link_many(encoder_elem, filter, encoder_parser, NULL); + if (gst_ret != TRUE) + { + ms_error("Failed to link elements into encoder_bin"); + MS_SAFE_UNREF(encoder_bin); + } + + __ms_add_ghostpad(encoder_parser, "src", encoder_bin, "src"); + __ms_add_ghostpad(encoder_elem, "sink", encoder_bin, "sink"); + + return encoder_bin; +} + +GstElement *__ms_video_decoder_element_create(dictionary *dict , media_format_mimetype_e mime) +{ + char *plugin_name = NULL; + char *format_prefix = NULL; + gboolean is_omx = FALSE; + GstElement *last_elem = NULL; + + format_prefix = g_strdup_printf("%s:decoder", __ms_convert_mime_to_string(mime)); + plugin_name = __ms_ini_get_string(dict, format_prefix, DEFAULT_VIDEO_DECODER); + GstElement *decoder_elem = __ms_element_create(plugin_name,NULL); + MS_SAFE_FREE(format_prefix); + MS_SAFE_FREE(plugin_name); + + format_prefix = g_strdup_printf("%s:parser", __ms_convert_mime_to_string(mime)); + plugin_name = __ms_ini_get_string(dict, format_prefix, DEFAULT_VIDEO_PARSER); + GstElement *decoder_parser = __ms_element_create(plugin_name,NULL); + + if(mime == MEDIA_FORMAT_H264_SP) + { + g_object_set(G_OBJECT(decoder_parser), "config-interval", 5, NULL); + } + + is_omx = g_strrstr(format_prefix, "omx"); + MS_SAFE_FREE(format_prefix); + MS_SAFE_FREE(plugin_name); + + gboolean gst_ret = FALSE; + GstElement *decoder_bin = gst_bin_new("video_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 video decoder bin"); + + 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; + } + last_elem = decoder_elem; + + if(!is_omx) + { + GstElement *video_conv = __ms_element_create("videoconvert",NULL); + GstElement *video_scale = __ms_element_create("videoscale",NULL); + ms_retvm_if(!video_conv || !video_scale, (GstElement*)NULL, + "Error: creating elements for video decoder bin"); + gst_bin_add_many(GST_BIN(decoder_bin), video_conv, video_scale, NULL); + gst_ret = gst_element_link_many(decoder_elem, video_conv, video_scale, NULL); + if (gst_ret != TRUE) + { + ms_error("Failed to link elements into decoder_bin"); + MS_SAFE_UNREF(decoder_bin); + return NULL; + } + last_elem = video_scale; + } + + __ms_add_ghostpad(last_elem, "src", decoder_bin, "src"); + __ms_add_ghostpad(decoder_queue, "sink", decoder_bin, "sink"); + + return decoder_bin; +} + +GstElement *__ms_audio_encoder_element_create(void) +{ + gboolean gst_ret = FALSE; + GstElement *audio_convert = __ms_element_create("audioconvert",NULL); + GstElement *audio_filter = __ms_element_create("capsfilter",NULL); + GstElement *audio_enc_bin = gst_bin_new("audio_encoder"); + ms_retvm_if(!audio_convert || !audio_filter || !audio_enc_bin, (GstElement*)NULL, + "Error: creating elements for encoder bin"); + + GstCaps *audioCaps = gst_caps_from_string(MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT); + g_object_set(G_OBJECT(audio_filter), "caps", audioCaps, NULL); + gst_caps_unref(audioCaps); + + gst_bin_add_many(GST_BIN(audio_enc_bin), audio_convert, audio_filter, NULL); + gst_ret = gst_element_link_many(audio_filter, audio_convert, NULL); + if (gst_ret != TRUE) + { + ms_error("Failed to link elements into decoder_bin"); + MS_SAFE_UNREF(audio_enc_bin); + } + + __ms_add_ghostpad(audio_convert, "src", audio_enc_bin, "src"); + __ms_add_ghostpad(audio_filter, "sink", audio_enc_bin, "sink"); + + return audio_enc_bin; +} + +GstElement *__ms_rtp_element_create(media_streamer_node_s *ms_node) +{ + ms_retvm_if(ms_node == NULL, (GstElement*)NULL, "Error empty rtp node Handle"); + + GstElement *rtp_container = gst_bin_new("rtp_container"); + GstElement *rtp_elem = __ms_element_create("rtpbin", "rtpbin"); + ms_retvm_if(!rtp_container || !rtp_elem, (GstElement*)NULL, + "Error: creating elements for rtp container"); + + gst_bin_add(GST_BIN(rtp_container), rtp_elem); + g_signal_connect (rtp_elem, "pad-added", G_CALLBACK (__ms_rtpbin_pad_added_cb), ms_node); + + return rtp_container; +} + +static gboolean __ms_get_rtp_elements(media_streamer_node_s *ms_node, + GstElement **rtp_elem, GstElement **rtcp_elem, const gchar *elem_name) +{ + gboolean ret = FALSE; + gchar *rtp_elem_name = NULL; + gchar *rtcp_elem_name = NULL; + gchar *plugin_name = NULL; + + GstElement *rtpbin = gst_bin_get_by_name(GST_BIN(ms_node->gst_element), "rtpbin"); + + ms_retvm_if(!elem_name, FALSE, "Empty rtp element name."); + + if(MS_ELEMENT_IS_SOURCE(elem_name)) + { + plugin_name = g_strdup("udpsrc"); + } + else if(MS_ELEMENT_IS_SINK(elem_name)) + { + plugin_name = g_strdup("udpsink"); + } + else + { + ms_error("Error: invalid parameter name [%s]", elem_name); + return FALSE; + } + + rtp_elem_name = g_strdup_printf("%s_rtp", elem_name); + rtcp_elem_name = g_strdup_printf("%s_rtcp", elem_name); + + // Find video udp rtp/rtcp element if it present. + *rtp_elem = gst_bin_get_by_name(GST_BIN(ms_node->gst_element), rtp_elem_name); + *rtcp_elem = gst_bin_get_by_name(GST_BIN(ms_node->gst_element), rtcp_elem_name); + + // Create new udp element if it did not found. + if((NULL == *rtp_elem) && (NULL == *rtcp_elem)) + { + *rtp_elem = __ms_element_create(plugin_name, rtp_elem_name); + *rtcp_elem = __ms_element_create(plugin_name, rtcp_elem_name); + } + else + { + //rtp/rtcp elements already into rtp bin. + MS_SAFE_GFREE(rtp_elem_name); + MS_SAFE_GFREE(rtcp_elem_name); + MS_SAFE_GFREE(plugin_name); + return TRUE; + } + + gst_bin_add_many(GST_BIN(ms_node->gst_element), + *rtp_elem, *rtcp_elem, NULL); + + if(MS_ELEMENT_IS_SINK(elem_name)) + { + g_object_set(GST_OBJECT(*rtcp_elem), "sync", FALSE, NULL); + g_object_set(GST_OBJECT(*rtcp_elem), "async", FALSE, NULL); + + if(MS_ELEMENT_IS_VIDEO(elem_name)) + { + __ms_add_ghostpad(rtpbin, "send_rtp_sink_0", ms_node->gst_element, "video_sink"); + ret = gst_element_link_pads(rtpbin, "send_rtp_src_0", *rtp_elem, "sink") && + gst_element_link_pads(rtpbin, "send_rtcp_src_0",*rtcp_elem, "sink"); + } + else + { + __ms_add_ghostpad(rtpbin, "send_rtp_sink_1", ms_node->gst_element, "audio_sink"); + ret = gst_element_link_pads(rtpbin, "send_rtp_src_1", *rtp_elem, "sink") && + gst_element_link_pads(rtpbin, "send_rtcp_src_1",*rtcp_elem, "sink"); + } + } + else + { + if(MS_ELEMENT_IS_VIDEO(elem_name)) + { + ret = gst_element_link_pads(*rtp_elem, "src", rtpbin, "recv_rtp_sink_0") && + gst_element_link_pads (*rtcp_elem, "src", rtpbin, "recv_rtcp_sink_0"); + __ms_add_ghostpad(NULL, NULL, ms_node->gst_element, "video_source"); + } + else + { + ret = gst_element_link_pads(*rtp_elem, "src", rtpbin, "recv_rtp_sink_1") && + gst_element_link_pads (*rtcp_elem, "src", rtpbin, "recv_rtcp_sink_1"); + __ms_add_ghostpad(NULL, NULL, ms_node->gst_element, "audio_source"); + } + } + + if(!ret) + { + ms_error("Can not link [rtpbin] pad to [%s] pad, ret code [%d] ", rtp_elem, ret); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + __ms_generate_dots(ms_node->gst_element, "rtp"); + MS_SAFE_GFREE(rtp_elem_name); + MS_SAFE_GFREE(rtcp_elem_name); + MS_SAFE_GFREE(plugin_name); + + return ret; +} + +int __ms_rtp_set_param( + media_streamer_node_s *ms_node, + const gchar *param_key, + const gchar *param_value) +{ + ms_retvm_if(!ms_node && !ms_node->gst_element, MEDIA_STREAMER_ERROR_NONE, "Error: empty node"); + + gchar **tokens = NULL; + gchar *elem_name = NULL; + guint i = 0; + GstElement *rtp_elem = NULL; + GstElement *rtcp_elem = NULL; + + tokens = g_strsplit(param_key,",",3); + ms_retvm_if(tokens == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Invalid rtp parameter line."); + elem_name = tokens[0]; + + if(FALSE == __ms_get_rtp_elements(ms_node, &rtp_elem, &rtcp_elem, elem_name)) + { + ms_error("Error: invalid parameter [%s]", param_key); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + for(i = 1; (tokens && tokens[i]); i++) + { + ms_retvm_if(!rtp_elem || !rtcp_elem, + MEDIA_STREAMER_ERROR_INVALID_OPERATION, + "Error: [%s] did not found or created into streamer", tokens[i]); + + if(!g_strcmp0(tokens[i], "port")) + { + __ms_element_set_property(rtp_elem, tokens[i], param_value); + gchar *next_port = g_strdup(param_value); + next_port[strlen(next_port)-1] += 1; + __ms_element_set_property(rtcp_elem, tokens[i], next_port); + MS_SAFE_GFREE(next_port); + } + else if(!g_strcmp0(tokens[i], "host") && MS_ELEMENT_IS_SINK(elem_name)) + { + __ms_element_set_property(rtp_elem, tokens[i], param_value); + __ms_element_set_property(rtcp_elem, tokens[i], param_value); + } + else if(!g_strcmp0(tokens[i], "format") && MS_ELEMENT_IS_SOURCE(elem_name)) + { + __ms_element_set_property(rtp_elem, "caps", param_value); + } + + } + g_strfreev(tokens); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_add_node_into_bin(media_streamer_s *ms_streamer,media_streamer_node_s *ms_node) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Handle is NULL"); + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Handle is NULL"); + + ms_info("Try to add [%s] node into streamer, node type/subtype [%d/%d]", + ms_node->name, ms_node->type, ms_node->subtype); + + gchar *bin_name = NULL; + gboolean gst_ret = FALSE; + + switch(ms_node->type) + { + case MEDIA_STREAMER_NODE_TYPE_SRC: + gst_ret = gst_bin_add(GST_BIN(ms_streamer->src_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_SRC_BIN_NAME); + break; + case MEDIA_STREAMER_NODE_TYPE_SINK: + switch(ms_node->subtype) + { + case MEDIA_STREAMER_SINK_TYPE_SCREEN: + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); + break; + case MEDIA_STREAMER_SINK_TYPE_AUDIO: + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_AUDIO_SINK_BIN_NAME); + break; + default: + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); + break; + } + break; + case MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER: + gst_ret = gst_bin_add(GST_BIN(ms_streamer->topology_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_TOPOLOGY_BIN_NAME); + break; + case MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER: + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); + break; + case MEDIA_STREAMER_NODE_TYPE_VIDEO_DEPAY: + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); + break; + case MEDIA_STREAMER_NODE_TYPE_AUDIO_DEPAY: + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_AUDIO_SINK_BIN_NAME); + break; + case MEDIA_STREAMER_NODE_TYPE_AUDIO_RESAMPLE: + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_AUDIO_SINK_BIN_NAME); + break; + case MEDIA_STREAMER_NODE_TYPE_AUDIO_CONVERTER: + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_AUDIO_SINK_BIN_NAME); + break; + default: + // Another elements will be add into topology bin + gst_ret = gst_bin_add(GST_BIN(ms_streamer->topology_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_TOPOLOGY_BIN_NAME); + break; + } + + if(!gst_ret) + { + ms_error("Failed to add Element [%s] into [%s] bin.", ms_node->name, bin_name); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + else + { + ms_info("Success added Element [%s] into [%s] bin.", ms_node->name, bin_name); + ret = MEDIA_STREAMER_ERROR_NONE; + } + + MS_SAFE_GFREE(bin_name); + + return ret; +} + + +static gboolean __ms_bus_cb(GstBus *bus, GstMessage *message, gpointer userdata) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + media_streamer_s *ms_streamer = (media_streamer_s*)userdata; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(ms_streamer->pipeline == NULL, MEDIA_STREAMER_ERROR_INVALID_STATE, "Pipeline doesn`t exist"); + + /* Parse message */ + if (message != NULL) + { + switch (GST_MESSAGE_TYPE(message)) + { + case GST_MESSAGE_ERROR: + { + GError *err; + gchar *debug; + gst_message_parse_error (message, &err, &debug); + + ms_error("[Source: %s] Error: %s", GST_OBJECT_NAME(GST_OBJECT_CAST(GST_ELEMENT(GST_MESSAGE_SRC (message)))), err->message); + + MS_SAFE_FREE(err); + MS_SAFE_FREE(debug); + break; + } + + case GST_MESSAGE_STATE_CHANGED: + { + if (GST_MESSAGE_SRC (message) == GST_OBJECT (ms_streamer->pipeline)) + { + GstState state_old, state_new, state_pending; + gchar *state_transition_name; + + gst_message_parse_state_changed (message, &state_old, &state_new, &state_pending); + ms_info ("GST_MESSAGE_STATE_CHANGED: [%s] %s -> %s\n", + gst_object_get_name(GST_MESSAGE_SRC(message)), + _ms_state_to_string(state_old), + _ms_state_to_string(state_new)); + + state_transition_name = g_strdup_printf ("%s_%s", + gst_element_state_get_name (state_old), + gst_element_state_get_name (state_new)); + + __ms_generate_dots(ms_streamer->pipeline, state_transition_name); + + MS_SAFE_GFREE (state_transition_name); + + if (state_old == GST_STATE_NULL && state_new == GST_STATE_READY) + { + ms_info("[Success] GST_STATE_NULL => GST_STATE_READY"); + + /* Pause Media_Streamer */ + ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PAUSED); + if(ret != MEDIA_STREAMER_ERROR_NONE) + { + ms_error("ERROR - Pause pipeline"); + return FALSE; + } + } + + if (state_old == GST_STATE_READY && state_new == GST_STATE_PAUSED) + { + ms_info("[Success] GST_STATE_READY => GST_STATE_PAUSED"); + + ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PLAYING); + if(ret != MEDIA_STREAMER_ERROR_NONE) + { + ms_error("ERROR - Play Pipeline"); + return FALSE; + } + } + } + break; + } + + case GST_MESSAGE_EOS: + { + ms_info("GST_MESSAGE_EOS end-of-stream"); + ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PAUSED); + if(ret != MEDIA_STREAMER_ERROR_NONE) + { + ms_error("ERROR - Pause Pipeline"); + return FALSE; + } + break; + } + default: + break; + } + } + return TRUE; +} + +int __ms_pipeline_create(media_streamer_s *ms_streamer) +{ + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + gst_init(NULL, NULL); + + ms_streamer->pipeline = gst_pipeline_new(MEDIA_STREAMER_PIPELINE_NAME); + ms_retvm_if(ms_streamer->pipeline == NULL, + MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error creating pipeline"); + + ms_streamer->bus = gst_pipeline_get_bus(GST_PIPELINE(ms_streamer->pipeline)); + ms_retvm_if(ms_streamer->bus == NULL, + MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error getting the bus of the pipeline"); + + ms_streamer->bus_watcher = gst_bus_add_watch (ms_streamer->bus, (GstBusFunc)__ms_bus_cb, ms_streamer); + + ms_streamer->src_bin = gst_bin_new(MEDIA_STREAMER_SRC_BIN_NAME); + ms_retvm_if(ms_streamer->src_bin == NULL, + MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error creating Src bin"); + +// g_signal_connect(ms_streamer->src_bin, "element-added", G_CALLBACK(__src_bin_element_added_cb), ms_streamer); + + ms_streamer->sink_video_bin = gst_bin_new(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); + ms_retvm_if(ms_streamer->sink_video_bin == NULL, + MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error creating Sink bin"); +// g_signal_connect(ms_streamer->sink_bin, "element-added", G_CALLBACK(__sink_bin_element_added_cb), ms_streamer); + + ms_streamer->sink_audio_bin = gst_bin_new(MEDIA_STREAMER_AUDIO_SINK_BIN_NAME); + ms_retvm_if(ms_streamer->sink_audio_bin == NULL, + MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error creating Audio Sink bin"); + + ms_streamer->topology_bin = gst_bin_new(MEDIA_STREAMER_TOPOLOGY_BIN_NAME); + ms_retvm_if(ms_streamer->topology_bin == NULL, + MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error creating Topology bin"); +// g_signal_connect(ms_streamer->topology_bin, "element-added", G_CALLBACK(__bin_element_added_cb), ms_streamer); + + gst_bin_add_many(GST_BIN(ms_streamer->pipeline), ms_streamer->src_bin, + ms_streamer->topology_bin, NULL); + + return MEDIA_STREAMER_ERROR_NONE; +} + +static GstCaps *__ms_create_caps_from_fmt(media_format_h fmt) +{ + GstCaps *caps = NULL; + media_format_mimetype_e mime; + gchar *format_name = NULL; + int width; + int height; + int avg_bps; + int max_bps; + int channel; + int samplerate; + int bit; + + if (media_format_get_video_info(fmt, &mime, &width, &height, &avg_bps, &max_bps) == MEDIA_PACKET_ERROR_NONE) + { + + ms_info("Creating video Caps from media format [width=%d, height=%d, bps=%d, mime=%d]", + width, height, avg_bps, mime); + + if (mime & MEDIA_FORMAT_RAW) + { + format_name = g_strdup(__ms_convert_mime_to_string(mime)); + caps = gst_caps_new_simple("video/x-raw", +// "framerate", GST_TYPE_FRACTION, max_bps, avg_bps, + "format", G_TYPE_STRING, format_name, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, NULL); + } + else + { + //mime & MEDIA_FORMAT_ENCODED + format_name = g_strdup_printf("video/x-%s", __ms_convert_mime_to_string(mime)); + caps = gst_caps_new_simple(format_name, + "framerate", GST_TYPE_FRACTION, max_bps, avg_bps, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, NULL); + } + + } + else if (media_format_get_audio_info(fmt, &mime, &channel, &samplerate, &bit, &avg_bps) == MEDIA_PACKET_ERROR_NONE) + { + ms_info("Creating audio Caps from media format [channel=%d, samplerate=%d, bit=%d, avg_bps=%d, mime=%d]", + channel, samplerate, bit, avg_bps, mime); + + if (mime & MEDIA_FORMAT_RAW) + { + format_name = g_strdup(__ms_convert_mime_to_string(mime)); + caps = gst_caps_new_simple("audio/x-raw", + "channels", G_TYPE_INT, channel, + "format", G_TYPE_STRING, format_name, + "rate", G_TYPE_INT, samplerate, NULL); + } + else + { + ms_error("Encoded audio formats does not supported yet."); + } + } + else + { + ms_error("Failed getting media info from fmt."); + } + MS_SAFE_GFREE(format_name); + + return caps; +} + +int __ms_element_set_fmt(media_streamer_node_s *node, media_format_h fmt) +{ + GstCaps *caps = NULL; + GObject *obj = NULL; + GValue value = G_VALUE_INIT; + caps = __ms_create_caps_from_fmt(fmt); + ms_retvm_if(caps == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Fail creating caps from fmt."); + + obj = __ms_get_property_owner(node->gst_element, "caps", &value); + gst_value_set_caps(&value, caps); + g_object_set_property(obj, "caps", &value); + gst_caps_unref(caps); + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c new file mode 100755 index 0000000..5fb4413 --- /dev/null +++ b/src/media_streamer_node.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +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"); + + dictionary *dict = NULL; + char *plugin_name = NULL; + media_format_mimetype_e mime; + + if (MEDIA_FORMAT_ERROR_NONE != media_format_get_video_info(out_fmt, &mime, NULL, NULL, NULL, NULL)) + { + media_format_get_audio_info(out_fmt, &mime, NULL, NULL, NULL, NULL); + } + char* format_prefix = NULL; + + __ms_load_ini_dictionary(&dict); + + switch(node->type) + { + case MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER: + format_prefix = g_strdup_printf("%s:encoder", __ms_convert_mime_to_string(mime)); + plugin_name = __ms_ini_get_string(dict, + format_prefix, DEFAULT_VIDEO_ENCODER); + node->gst_element = __ms_video_encoder_element_create(dict, mime); + break; + case MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER: + format_prefix = g_strdup_printf("%s:decoder", __ms_convert_mime_to_string(mime)); + plugin_name = __ms_ini_get_string(dict, + format_prefix, DEFAULT_VIDEO_DECODER); + node->gst_element = __ms_video_decoder_element_create(dict, mime); + break; + case MEDIA_STREAMER_NODE_TYPE_PARSER: + format_prefix = g_strdup_printf("%s:parser", __ms_convert_mime_to_string(mime)); + plugin_name = __ms_ini_get_string(dict, + format_prefix, DEFAULT_VIDEO_PARSER); + node->gst_element = __ms_element_create(plugin_name, NULL); + break; + case MEDIA_STREAMER_NODE_TYPE_FILTER: + node->gst_element = __ms_element_create("capsfilter", NULL); + break; + case MEDIA_STREAMER_NODE_TYPE_VIDEO_PAY: + format_prefix = g_strdup_printf("%s:rtppay", __ms_convert_mime_to_string(mime)); + plugin_name = __ms_ini_get_string(dict, + format_prefix, DEFAULT_VIDEO_RTPPAY); + node->gst_element = __ms_element_create(plugin_name, NULL); + break; + case MEDIA_STREAMER_NODE_TYPE_AUDIO_PAY: + plugin_name = __ms_ini_get_string(dict, + "audio-raw:rtppay", DEFAULT_AUDIO_RTPPAY); + node->gst_element = __ms_element_create(plugin_name, NULL); + break; + case MEDIA_STREAMER_NODE_TYPE_VIDEO_DEPAY: + format_prefix = g_strdup_printf("%s:rtpdepay", __ms_convert_mime_to_string(mime)); + plugin_name = __ms_ini_get_string(dict, + format_prefix, DEFAULT_VIDEO_RTPDEPAY); + node->gst_element = __ms_element_create(plugin_name, NULL); + break; + case MEDIA_STREAMER_NODE_TYPE_AUDIO_DEPAY: + plugin_name = __ms_ini_get_string(dict, + "audio-raw:rtpdepay", DEFAULT_AUDIO_RTPPAY); + node->gst_element = __ms_element_create(plugin_name, NULL); + break; + case MEDIA_STREAMER_NODE_TYPE_RTP: + node->gst_element = __ms_rtp_element_create(node); + node->set_param = (media_streamer_node_set_param)__ms_rtp_set_param; + break; + case MEDIA_STREAMER_NODE_TYPE_QUEUE: + node->gst_element = __ms_element_create(DEFAULT_QUEUE, NULL); + break; + case MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER: + node->gst_element = __ms_audio_encoder_element_create(); + break; + case MEDIA_STREAMER_NODE_TYPE_VIDEO_CONVERTER: + node->gst_element = __ms_element_create("videoconvert", NULL); + break; + case MEDIA_STREAMER_NODE_TYPE_AUDIO_CONVERTER: + node->gst_element = __ms_element_create("audioconvert", NULL); + break; + case MEDIA_STREAMER_NODE_TYPE_AUDIO_RESAMPLE: + node->gst_element = __ms_element_create("audioresample", NULL); + break; + default: + ms_error( "Error: invalid node Type [%d]",node->type); + break; + } + + ms_retvm_if(node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating GstElement"); + + node->name = gst_element_get_name(node->gst_element); + + MS_SAFE_FREE(plugin_name); + MS_SAFE_FREE(format_prefix); + __ms_destroy_ini_dictionary(dict); + + return MEDIA_STREAMER_ERROR_NONE; +} + + +int __ms_src_node_create(media_streamer_node_s *node) +{ + ms_retvm_if(node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + dictionary *dict = NULL; + char *plugin_name = NULL; + + __ms_load_ini_dictionary(&dict); + + switch(node->subtype) + { + case MEDIA_STREAMER_SRC_TYPE_FILE: + ms_error("Error: not implemented yet"); + break; + case MEDIA_STREAMER_SRC_TYPE_RTSP: + node->gst_element = __ms_element_create(DEFAULT_UDP_SOURCE, NULL); + break; + case MEDIA_STREAMER_SRC_TYPE_HTTP: + ms_error("Error: not implemented yet"); + break; + case MEDIA_STREAMER_SRC_TYPE_CAMERA: + plugin_name = __ms_ini_get_string(dict, + "sources:camera_source",DEFAULT_CAMERA_SOURCE); + node->gst_element = __ms_camera_element_create(plugin_name); + + break; + case MEDIA_STREAMER_SRC_TYPE_AUDIO_CAPTURE: + plugin_name = __ms_ini_get_string(dict, + "sources:audio_source",DEFAULT_AUDIO_SOURCE); + node->gst_element = __ms_element_create(plugin_name, NULL); + break; + case MEDIA_STREAMER_SRC_TYPE_VIDEO_CAPTURE: + plugin_name = __ms_ini_get_string(dict, + "sources:video_source",DEFAULT_VIDEO_SOURCE); + node->gst_element = __ms_element_create(plugin_name, NULL); + break; + case MEDIA_STREAMER_SRC_TYPE_VIDEO_TEST: + node->gst_element = __ms_element_create(DEFAULT_VIDEO_TEST_SOURCE, NULL); + g_object_set (G_OBJECT (node->gst_element), "is-live", true, NULL); + break; + case MEDIA_STREAMER_SRC_TYPE_AUDIO_TEST: + node->gst_element = __ms_element_create(DEFAULT_AUDIO_TEST_SOURCE, NULL); + break; + case MEDIA_STREAMER_SRC_TYPE_CUSTOM: + ms_error("Error: not implemented yet"); + break; + default: + ms_error( "Error: invalid Src node Type [%d]",node->subtype); + break; + } + + ms_retvm_if(node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating GstElement"); + node->name = gst_element_get_name(node->gst_element); + + MS_SAFE_FREE(plugin_name); + __ms_destroy_ini_dictionary(dict); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_sink_node_create(media_streamer_node_s *node) +{ + ms_retvm_if(node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + dictionary *dict = NULL; + char *plugin_name = NULL; + + __ms_load_ini_dictionary(&dict); + + switch(node->subtype) + { + case MEDIA_STREAMER_SINK_TYPE_FILE: + ms_error("Error: not implemented yet"); + break; + case MEDIA_STREAMER_SINK_TYPE_RTSP: + node->gst_element = __ms_element_create(DEFAULT_UDP_SINK, NULL); + break; + case MEDIA_STREAMER_SINK_TYPE_HTTP: + ms_error("Error: not implemented yet"); + break; + case MEDIA_STREAMER_SINK_TYPE_AUDIO: + plugin_name = __ms_ini_get_string(dict, + "sinks:audio_sink",DEFAULT_AUDIO_SINK); + node->gst_element = __ms_element_create(plugin_name, NULL); + break; + case MEDIA_STREAMER_SINK_TYPE_SCREEN: + plugin_name = __ms_ini_get_string(dict, + "sinks:video_sink",DEFAULT_VIDEO_SINK); + node->gst_element = __ms_element_create(plugin_name, NULL); + break; + case MEDIA_STREAMER_SINK_TYPE_FAKE: + node->gst_element = __ms_element_create(DEFAULT_FAKE_SINK, NULL); + break; + case MEDIA_STREAMER_SINK_TYPE_CUSTOM: + + break; + default: + ms_error( "Error: invalid Sink node Type [%d]",node->subtype); + break; + } + + ms_retvm_if(node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating GstElement"); + node->name = gst_element_get_name(node->gst_element); + + MS_SAFE_FREE(plugin_name); + __ms_destroy_ini_dictionary(dict); + + return MEDIA_STREAMER_ERROR_NONE; +} + +void __ms_node_destroy(void *data) +{ + char *node_name = NULL; + media_streamer_node_s *node = (media_streamer_node_s*)data; + ms_retm_if(node == NULL, "Empty value while deleting element from table"); + + node_name = g_strdup(node->name); + MS_SAFE_UNREF(node->gst_element); + MS_SAFE_FREE(node->name); + + ms_info("Node [%s] destroyed", node_name); + MS_SAFE_FREE(node_name); +} + +void __ms_node_insert_into_table(GHashTable *nodes_table, + media_streamer_node_s *ms_node) +{ + if(g_hash_table_contains(nodes_table,ms_node->name)) + { + ms_debug( "Current Node [%s] already added", ms_node->name); + return; + } + g_hash_table_insert(nodes_table,(gpointer)ms_node->name,(gpointer)ms_node); + ms_info("Node [%s] added into streamer, node type/subtype [%d/%d]", + ms_node->name, ms_node->type, ms_node->subtype); +} + +int __ms_node_remove_from_table(GHashTable *nodes_table, + media_streamer_node_s *ms_node) +{ + ms_retvm_if(nodes_table == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Handle is NULL"); + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Handle is NULL"); + + gboolean g_ret = g_hash_table_remove(nodes_table, ms_node->name); + ms_retvm_if(g_ret != TRUE, MEDIA_STREAMER_ERROR_INVALID_OPERATION, + "Error while removing element from table"); + + return MEDIA_STREAMER_ERROR_NONE; +} + +static void __params_foreach_cb(const char *key, + const int type, + const bundle_keyval_t *kv, + void *user_data) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + media_streamer_node_s *ms_node = (media_streamer_node_s*)user_data; + ms_retm_if(ms_node == NULL, "Handle is NULL"); + + void *basic_val = NULL; + size_t basic_size = 0; + + ms_info("Try to add parameter [%s] with type [%d] to the node [%s].", key, type, ms_node->name); + + if(!bundle_keyval_type_is_array((bundle_keyval_t *)kv)) + { + bundle_keyval_get_basic_val((bundle_keyval_t *)kv, &basic_val, &basic_size); + ms_info("Read param value[%s] with size [%d].", (gchar*)basic_val, basic_size); + + if(ms_node->set_param != NULL) + { + ret = ms_node->set_param(ms_node, (gchar*)key, (gchar*)basic_val); + } + else + { + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + } + else + { + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + ms_retm_if(ret != MEDIA_STREAMER_ERROR_NONE, + "Error while adding param [%s,%s] to the node [%s]", + key, type, ms_node->name); +} + +int __ms_node_read_params_from_bundle (media_streamer_node_s *node, + bundle *param_list) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + bundle_foreach(param_list, __params_foreach_cb, (void*)node); + return ret; +} + +int __ms_node_write_params_into_bundle (media_streamer_node_s *node, + bundle *param_list) +{ + GParamSpec **property_specs; + guint num_properties, i; + char *string_val = NULL; + + property_specs = g_object_class_list_properties + (G_OBJECT_GET_CLASS(node->gst_element), &num_properties); + + if (num_properties <= 0) + { + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + ms_info("Getting parameter of the Node [%s]", node->name ); + + for (i = 0; i < num_properties; i++) + { + GValue value = { 0, }; + GParamSpec *param = property_specs[i]; + + g_value_init(&value, param->value_type); + if (param->flags & G_PARAM_READWRITE) + { + g_object_get_property(G_OBJECT(node->gst_element), param->name, &value); + } + else + { + // Skip properties which user can not change. + continue; + } + + ms_info("%-20s: %s\n", g_param_spec_get_name(param), g_param_spec_get_blurb(param)); + + switch(G_VALUE_TYPE(&value)) + { + case G_TYPE_STRING: + bundle_add_str(param_list, g_param_spec_get_name(param), g_value_get_string(&value)); + ms_info("Got string value: [%s]", g_value_get_string(&value)); + break; + + case G_TYPE_BOOLEAN: + string_val = g_strdup_printf("%s", g_value_get_boolean(&value) ? "true" : "false"); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got boolean value: [%s]", string_val); + break; + + case G_TYPE_ULONG: + { + GParamSpecULong *pulong = G_PARAM_SPEC_ULONG(param); + string_val = g_strdup_printf("%lu", g_value_get_ulong(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got ulong value: [%s], range: %lu - %lu (default %s)", + string_val, pulong->minimum, pulong->maximum); + break; + } + + case G_TYPE_LONG: + { + GParamSpecLong *plong = G_PARAM_SPEC_LONG(param); + string_val = g_strdup_printf("%ld", g_value_get_long(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got long value: [%s], range: %ld - %ld (default %s)", + string_val, plong->minimum, plong->maximum); + break; + } + + case G_TYPE_UINT: + { + GParamSpecUInt *puint = G_PARAM_SPEC_UINT(param); + string_val = g_strdup_printf("%u", g_value_get_uint(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got uint value: [%s], range: %u - %u", + string_val, puint->minimum, puint->maximum); + break; + } + + case G_TYPE_INT: + { + GParamSpecInt *pint = G_PARAM_SPEC_INT(param); + string_val = g_strdup_printf("%d", g_value_get_int(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got int value: [%s], range: %d - %d", + string_val, pint->minimum, pint->maximum); + break; + } + + case G_TYPE_UINT64: + { + GParamSpecUInt64 *puint64 = G_PARAM_SPEC_UINT64(param); + string_val = g_strdup_printf("%" G_GUINT64_FORMAT, g_value_get_uint64(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got uint64 value: [%s], range: %" G_GUINT64_FORMAT "- %" G_GUINT64_FORMAT, + string_val, puint64->minimum, puint64->maximum); + break; + } + + case G_TYPE_INT64: + { + GParamSpecInt64 *pint64 = G_PARAM_SPEC_INT64(param); + string_val = g_strdup_printf("%" G_GINT64_FORMAT, g_value_get_int64(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got uint64 value: [%s], range: %" G_GINT64_FORMAT "- %" G_GINT64_FORMAT, + string_val, pint64->minimum, pint64->maximum); + break; + } + + case G_TYPE_FLOAT: + { + GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT(param); + string_val = g_strdup_printf("%15.7g", g_value_get_float(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got float value: [%s], range:%15.7g -%15.7g", + string_val, pfloat->minimum, pfloat->maximum); + break; + } + + case G_TYPE_DOUBLE: + { + GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE(param); + string_val = g_strdup_printf("%15.7g", g_value_get_double(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got double value: [%s], range:%15.7g -%15.7g", + string_val, pdouble->minimum, pdouble->maximum); + break; + } + + default: + ms_info("Got unknown type with param->value_type [%d]", param->value_type); + break; + + MS_SAFE_FREE(string_val); + } + } + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_priv.c b/src/media_streamer_priv.c new file mode 100755 index 0000000..7e9b540 --- /dev/null +++ b/src/media_streamer_priv.c @@ -0,0 +1,203 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "media_streamer_priv.h" +#include "media_streamer_util.h" +#include "media_streamer_node.h" +#include "media_streamer_gst.h" + +int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e state) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + media_streamer_state_e previous_state= ms_streamer->state; + ms_retvm_if(previous_state == state, MEDIA_STREAMER_ERROR_NONE, "Media streamer already in this state"); + + switch(state) + { + case MEDIA_STREAMER_STATE_NONE: + /* + * Media streamer must be in IDLE state + * Unlink and destroy all bins and elements. + */ + if (previous_state != MEDIA_STREAMER_STATE_IDLE) + { + __ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_IDLE); + } + break; + case MEDIA_STREAMER_STATE_IDLE: + /* + * Unlink all gst_elements, set pipeline into state NULL + */ + if (previous_state != MEDIA_STREAMER_STATE_NONE) + { + ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_NULL); + } + break; + case MEDIA_STREAMER_STATE_READY: + break; + case MEDIA_STREAMER_STATE_PLAYING: + ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PLAYING); + break; + case MEDIA_STREAMER_STATE_PAUSED: + ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PAUSED); + break; + case MEDIA_STREAMER_STATE_SEEKING: + default: + { + ms_info("Error: invalid state [%s]", state); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } + + if(ret != MEDIA_STREAMER_ERROR_NONE) + { + ms_error("Failed change state"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + ms_streamer->state = state; + ms_info("Media streamer state changed to [%d]", state); + return ret; +} + +int __ms_create(media_streamer_s *ms_streamer) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + ret = __ms_load_ini_settings(&ms_streamer->ini); + ms_retvm_if(ret!=MEDIA_STREAMER_ERROR_NONE, + MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error load ini file"); + + ms_streamer->nodes_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, __ms_node_destroy); + ms_retvm_if(ms_streamer->nodes_table == NULL, + MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error creating hash table"); + + ret = __ms_pipeline_create(ms_streamer); + if (ret != MEDIA_STREAMER_ERROR_NONE) + { + ms_error("Error while creating media streamer pipeline."); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + ms_info("Media streamer pipeline created successfully."); + + return ret; +} + +static void __node_remove_cb(gpointer key, + gpointer value, + gpointer user_data) +{ + media_streamer_s *ms_streamer = (media_streamer_s*)user_data; + ms_retm_if(ms_streamer == NULL, "Handle is NULL"); + + media_streamer_node_s *ms_node = (media_streamer_node_s*)value; + ms_retm_if(ms_node == NULL, "Handle is NULL"); + + ms_info("Try to delete [%s] node from streamer, node type/subtype [%d/%d]", + ms_node->name, ms_node->type, ms_node->subtype); + + gchar *bin_name = NULL; + gboolean gst_ret = FALSE; + + __ms_element_set_state(ms_node->gst_element, GST_STATE_NULL); + gst_object_ref(ms_node->gst_element); + + switch(ms_node->type) + { + case MEDIA_STREAMER_NODE_TYPE_SRC: + gst_ret = gst_bin_remove(GST_BIN(ms_streamer->src_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_SRC_BIN_NAME); + break; + case MEDIA_STREAMER_NODE_TYPE_SINK: + gst_ret = gst_bin_remove(GST_BIN(ms_streamer->sink_video_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); + break; + default: + gst_ret = gst_bin_remove(GST_BIN(ms_streamer->topology_bin),ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_TOPOLOGY_BIN_NAME); + break; + } + + if(!gst_ret) + { + ms_error("Failed to remove Element [%s] from bin [%s]", ms_node->name, bin_name); + } + else + { + ms_info("Success removed Element [%s] from bin [%s]", ms_node->name, bin_name); + } + + MS_SAFE_GFREE(bin_name); + +} + + +void __ms_streamer_destroy(media_streamer_s *ms_streamer) +{ + if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_NONE) != MEDIA_STREAMER_ERROR_NONE) + { + ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); + } + + gst_element_unlink_many(ms_streamer->src_bin, + ms_streamer->topology_bin, + ms_streamer->sink_video_bin, NULL); + + g_hash_table_foreach(ms_streamer->nodes_table, __node_remove_cb,(gpointer)ms_streamer); + + if(ms_streamer->src_bin && !gst_bin_remove(GST_BIN(ms_streamer->pipeline),ms_streamer->src_bin)) + { + ms_error("Failed to remove src_bin from pipeline"); + } + else + { + ms_info("src_bin removed from pipeline"); + } + + if(ms_streamer->sink_video_bin && !gst_bin_remove(GST_BIN(ms_streamer->pipeline),ms_streamer->sink_video_bin)) + { + ms_error("Failed to remove sink_bin from pipeline"); + } + else + { + ms_info("sink_bin removed from pipeline"); + } + + + if(ms_streamer->topology_bin && !gst_bin_remove(GST_BIN(ms_streamer->pipeline),ms_streamer->topology_bin)) + { + ms_error("Failed to remove topology_bin from pipeline"); + } + else + { + ms_info("topology_bin removed from pipeline"); + } + + + ms_streamer->state = MEDIA_STREAMER_STATE_NONE; + + MS_TABLE_SAFE_UNREF(ms_streamer->nodes_table); + MS_SAFE_UNREF(ms_streamer->bus); + MS_SAFE_UNREF(ms_streamer->pipeline); + + MS_SAFE_FREE(ms_streamer); + +// gst_deinit(); +} diff --git a/src/media_streamer_util.c b/src/media_streamer_util.c new file mode 100755 index 0000000..46d9fdd --- /dev/null +++ b/src/media_streamer_util.c @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MEDIA_STREAMER_UTIL_C__ +#define __MEDIA_STREAMER_UTIL_C__ + +#include + +#include +#include + +#ifdef MEDIA_STREAMER_DEFAULT_INI + static gboolean __ms_generate_default_ini(void); +#endif + +static void __ms_check_ini_status(void); + +gchar* __ms_ini_get_string(dictionary *dict, + const char *ini_path, char *default_str) +{ + gchar *result_str = NULL; + + ms_retvm_if(ini_path == NULL, NULL, "Invalid ini path"); + + if (dict == NULL) + { + result_str = g_strdup(default_str); + } + else + { + gchar *str = NULL; + str = iniparser_getstring(dict, ini_path, default_str); + if (str && + (strlen(str) > 0) && + (strlen(str) < MEDIA_STREAMER_INI_MAX_STRLEN)) + { + result_str = g_strdup(str); + } + else + { + result_str = g_strdup(default_str); + } + } + return result_str; +} + +gboolean __ms_load_ini_dictionary(dictionary **dict) +{ + ms_retvm_if(dict == NULL, FALSE, "Handle is NULL"); + + __ms_check_ini_status(); + + dictionary *ms_dict = NULL; + + /* loading existing ini file */ + ms_dict = iniparser_load(MEDIA_STREAMER_INI_DEFAULT_PATH); + + /* if no file exists. create one with set of default values */ + if (!ms_dict) + { +#ifdef MEDIA_STREAMER_DEFAULT_INI + ms_debug("No inifile found. Media streamer will create default inifile."); + if (FALSE == __ms_generate_default_ini()) + { + ms_debug("Creating default .ini file failed. Media-streamer will use default values."); + } + else + { + /* load default ini */ + ms_dict = iniparser_load(MEDIA_STREAMER_INI_DEFAULT_PATH); + } +#else + ms_debug("No ini file found."); + return FALSE; +#endif + } + + *dict = ms_dict; + return TRUE; +} + +gboolean __ms_destroy_ini_dictionary(dictionary *dict) +{ + ms_retvm_if(dict == NULL, FALSE, "Handle is null"); + + /* free dict as we got our own structure */ + iniparser_freedict(dict); + + return TRUE; +} + +int __ms_load_ini_settings(media_streamer_ini_t *ini) +{ + dictionary *dict = NULL; + + /* get ini values */ + memset(ini, 0, sizeof(media_streamer_ini_t)); + + if (__ms_load_ini_dictionary(&dict)) + { + /* general */ + ini->generate_dot = iniparser_getboolean(dict, "general:generate dot", DEFAULT_GENERATE_DOT); + if (ini->generate_dot == TRUE) + { + gchar *dot_path = iniparser_getstring(dict, "general:dot dir" , MEDIA_STREAMER_DEFAULT_DOT_DIR); + ms_debug("generate_dot is TRUE, dot file will be stored into %s",dot_path); + g_setenv ("GST_DEBUG_DUMP_DOT_DIR", dot_path, FALSE); + } + + } + else /* if dict is not available just fill the structure with default value */ + { + ms_debug("failed to load ini. using hardcoded default"); + + /* general settings*/ + ini->generate_dot = DEFAULT_GENERATE_DOT; + } + + __ms_destroy_ini_dictionary(dict); + + /* general */ + ms_debug("generate_dot : %d\n", ini->generate_dot); + + return MEDIA_STREAMER_ERROR_NONE; +} + +static void __ms_check_ini_status(void) +{ + FILE *fp = fopen(MEDIA_STREAMER_INI_DEFAULT_PATH, "r"); + int file_size = 0; + int status = 0; + + if(fp == NULL) + { + ms_debug("Failed to get media streamer ini file."); + } + else + { + fseek(fp, 0, SEEK_END); + file_size = ftell(fp); + fclose(fp); + if (file_size < 5) + { + ms_debug("media_streamer.ini file size=%d, Corrupted! Removed", file_size); + status = g_remove(MEDIA_STREAMER_INI_DEFAULT_PATH); + if (status == -1) + { + ms_error("failed to delete corrupted ini"); + } + } + } +} + +#ifdef MEDIA_STREAMER_DEFAULT_INI +static gboolean __ms_generate_default_ini(void) +{ + FILE *fp = NULL; + gchar *default_ini = MEDIA_STREAMER_DEFAULT_INI; + + + /* create new file */ + fp = fopen(MEDIA_STREAMER_INI_DEFAULT_PATH, "wt"); + + if (!fp) + { + return FALSE; + } + + /* writing default ini file */ + if (strlen(default_ini) != fwrite(default_ini, 1, strlen(default_ini), fp)) + { + fclose(fp); + return FALSE; + } + + fclose(fp); + return TRUE; +} +#endif + +const gchar *__ms_convert_mime_to_string(media_format_mimetype_e mime) +{ + switch(mime) + { + case MEDIA_FORMAT_I420: + return "I420"; + case MEDIA_FORMAT_YV12: + return "YV12"; + case MEDIA_FORMAT_H263: + return "h263"; + case MEDIA_FORMAT_H264_HP: + case MEDIA_FORMAT_H264_MP: + case MEDIA_FORMAT_H264_SP: + return "h264"; + case MEDIA_FORMAT_PCM: + return "S16BE"; + default: + ms_error("Invalid or Unsupported media format [%d].", mime); + return NULL; + break; + } + +} +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100755 index 0000000..cccb136 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,24 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_test "${fw_name}-test") + +INCLUDE_DIRECTORIES(../include) + +link_directories(${CMAKE_SOURCE_DIR}/../) + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_test} REQUIRED glib-2.0) +FOREACH(flag ${${fw_test}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +aux_source_directory(. sources) + +FOREACH(src ${sources}) + GET_FILENAME_COMPONENT(src_name ${src} NAME_WE) + MESSAGE("${src_name}") + ADD_EXECUTABLE(${src_name} ${src}) + TARGET_LINK_LIBRARIES(${src_name} capi-media-streamer ${${fw_test}_LDFLAGS}) +ENDFOREACH() + diff --git a/test/media_streamer_test.c b/test/media_streamer_test.c new file mode 100755 index 0000000..f789c06 --- /dev/null +++ b/test/media_streamer_test.c @@ -0,0 +1,940 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include + +#include + +typedef enum +{ + MENU_STATE_UNKNOWN = 0, + MENU_STATE_MAIN_MENU, + MENU_STATE_BROADCAST_MENU, + MENU_STATE_VOIP_MENU, + MENU_STATE_PRESET_MENU +} menu_state_e; + +typedef enum +{ + SUBMENU_STATE_UNKNOWN = 0, + SUBMENU_STATE_GETTING_IP, + SUBMENU_STATE_AUTOPLUG = 3, + SUBMENU_STATE_FORMAT +} submenu_state_e; + +#define SECOND_VOIP_MASK 0x8 +#define DOUBLE_STREAMER_MASK 0x10 + +typedef enum +{ + PRESET_UNKNOWN = 0, + PRESET_RTP_STREAMER = 0x01, + PRESET_RTP_CLIENT = 0x02, + PRESET_VOIP = PRESET_RTP_STREAMER | PRESET_RTP_CLIENT, + PRESET_VOIP_2 = PRESET_VOIP | SECOND_VOIP_MASK, + PRESET_DOUBLE_VOIP_SERVER = PRESET_RTP_STREAMER | DOUBLE_STREAMER_MASK, + PRESET_DOUBLE_VOIP_SERVER_2 = PRESET_RTP_STREAMER | DOUBLE_STREAMER_MASK | SECOND_VOIP_MASK, + PRESET_DOUBLE_VOIP_CLIENT = PRESET_RTP_CLIENT | DOUBLE_STREAMER_MASK, + PRESET_DOUBLE_VOIP_CLIENT_2 = PRESET_RTP_CLIENT | DOUBLE_STREAMER_MASK | SECOND_VOIP_MASK +} preset_type_e; + +#define PACKAGE "media_streamer_test" +/*--------------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS: | +---------------------------------------------------------------------------*/ + +static media_streamer_h g_media_streamer; +static media_streamer_h g_media_streamer_2; +static media_streamer_h current_media_streamer = &g_media_streamer; + +//#define ONE_DEVICE_TEST +#define MAX_STRING_LEN 2048 +#define DEFAULT_IP_ADDR "127.0.0.1" + +#define VIDEO_PORT 5000 +#define AUDIO_PORT 6000 + +//#define DISABLE_AUDIO +//#define DISABLE_VIDEO + +/*--------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS: | +---------------------------------------------------------------------------*/ +GMainLoop *g_loop; + +gchar *g_broadcast_address = NULL; +menu_state_e g_menu_state = MENU_STATE_MAIN_MENU; +submenu_state_e g_sub_menu_state = SUBMENU_STATE_UNKNOWN; +preset_type_e g_menu_preset = PRESET_UNKNOWN; + +gboolean g_autoplug_mode = FALSE; + +media_format_h vfmt_raw = NULL; +media_format_h vfmt_encoded = NULL; +media_format_h afmt_raw = NULL; + +/*--------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------*/ + +static gboolean _create(media_streamer_h *streamer) +{ + g_print("== create \n"); + + if(*streamer != NULL) + { + return TRUE; + } + + int ret = MEDIA_STREAMER_ERROR_NONE; + + ret = media_streamer_create(streamer); + + if( ret != MEDIA_STREAMER_ERROR_NONE) + { + g_print("Fail to create media streamer"); + return FALSE; + } + + return TRUE; +} + +static gboolean _prepare(void) +{ + g_print("== prepare \n"); + int ret = MEDIA_STREAMER_ERROR_NONE; + + ret = media_streamer_prepare(current_media_streamer); + if( ret != MEDIA_STREAMER_ERROR_NONE) + { + g_print("Fail to prepare media streamer"); + return FALSE; + } + g_print("== success prepare \n"); + + return TRUE; +} + +static gboolean _unprepare(void) +{ + g_print("== unprepare \n"); + int ret = MEDIA_STREAMER_ERROR_NONE; + + ret = media_streamer_unprepare(current_media_streamer); + if( ret != MEDIA_STREAMER_ERROR_NONE) + { + g_print("Fail to unprepare media streamer"); + return FALSE; + } + g_print("== success unprepare \n"); + + return TRUE; +} + +static gboolean _play() +{ + g_print("== play \n"); + int ret = MEDIA_STREAMER_ERROR_NONE; + + ret = media_streamer_play(current_media_streamer); + if( ret != MEDIA_STREAMER_ERROR_NONE) + { + g_print("Fail to play media streamer"); + return FALSE; + } + g_print("== success play \n"); + + return TRUE; +} + +static gboolean _destroy(media_streamer_h streamer) +{ + g_print("== destroy \n"); + int ret = MEDIA_STREAMER_ERROR_NONE; + + if(streamer == NULL) + { + g_print("media streamer already destroyed"); + return TRUE; + } + + ret = media_streamer_destroy(streamer); + if( ret != MEDIA_STREAMER_ERROR_NONE) + { + g_print("Fail to destroy media streamer"); + return FALSE; + } + + g_menu_preset = PRESET_UNKNOWN; + g_print("== success destroy \n"); + return TRUE; +} + +static void create_formats(void) +{ + if(!vfmt_raw || !vfmt_encoded || afmt_raw) + { + g_print("Formats already created!"); + } + + /* Define video raw format */ + media_format_create(&vfmt_raw); + if (media_format_set_video_mime(vfmt_raw, MEDIA_FORMAT_YV12) != MEDIA_FORMAT_ERROR_NONE) + { + g_print("media_format_set_video_mime failed!"); + } + media_format_set_video_width(vfmt_raw, 800); + media_format_set_video_height(vfmt_raw, 600); + media_format_set_video_avg_bps(vfmt_raw, 10000); + media_format_set_video_max_bps(vfmt_raw, 30000); + + /* Define encoded video format */ + media_format_create(&vfmt_encoded); + if (media_format_set_video_mime(vfmt_encoded, MEDIA_FORMAT_H264_SP) != MEDIA_FORMAT_ERROR_NONE) + { + g_print("media_format_set_video_mime failed!"); + } + media_format_set_video_width(vfmt_encoded, 800); + media_format_set_video_height(vfmt_encoded, 600); + media_format_set_video_avg_bps(vfmt_encoded, 10000); + media_format_set_video_max_bps(vfmt_encoded, 30000); + + /* Define audio raw format */ + media_format_create(&afmt_raw); + if (media_format_set_audio_mime(afmt_raw, MEDIA_FORMAT_PCM) != MEDIA_FORMAT_ERROR_NONE) + { + g_print("media_format_set_audio_mime failed!"); + } + media_format_set_audio_channel(afmt_raw, 1); + media_format_set_audio_samplerate(afmt_raw, 44100); + media_format_set_audio_bit(afmt_raw, 16); +} + +static void set_rtp_params (media_streamer_node_h rtp_node, + const gchar *ip, + int video_port, + int audio_port, + gboolean port_reverse) +{ + bundle *params = bundle_create(); + +#ifndef DISABLE_AUDIO + gchar *audio_src_port = g_strdup_printf("%d", port_reverse ? (audio_port + 5) : audio_port); + gchar *audio_sink_port = g_strdup_printf("%d", port_reverse ? audio_port : (audio_port + 5)); + + if(g_menu_preset & PRESET_RTP_STREAMER) + { + bundle_add_str(params, "audio_sink,port", audio_sink_port); + bundle_add_str(params, "audio_sink,host", ip); + } + if(g_menu_preset & PRESET_RTP_CLIENT) + { + bundle_add_str(params, "audio_source,port", audio_src_port); + bundle_add_str(params, "audio_source,format", + "application/x-rtp,media=audio,clock-rate=44100,encoding-name=L16," + "encoding-params=1,channels=1,payload=96"); + } + + g_free(audio_src_port); + g_free(audio_sink_port); +#endif + +#ifndef DISABLE_VIDEO + gchar *video_src_port = g_strdup_printf("%d", port_reverse ? (video_port + 5) : video_port); + gchar *video_sink_port = g_strdup_printf("%d", port_reverse ? video_port : (video_port + 5)); + + if(g_menu_preset & PRESET_RTP_STREAMER) + { + bundle_add_str(params, "video_sink,port", video_sink_port); + bundle_add_str(params, "video_sink,host", ip); + } + if(g_menu_preset & PRESET_RTP_CLIENT) + { + bundle_add_str(params, "video_source,port", video_src_port); + bundle_add_str(params, "video_source,format", + "application/x-rtp,media=video,clock-rate=90000,encoding-name=H264"); + } + + g_free(video_src_port); + g_free(video_sink_port); +#endif + + media_streamer_node_set_params(rtp_node, params); + bundle_free(params); + params = NULL; +} + +static gboolean _create_rtp_streamer(media_streamer_node_h rtp_bin) +{ + g_print("== _create_rtp_streamer \n"); + +#ifndef DISABLE_VIDEO + //********************** video source *********************************** + media_streamer_node_h video_src = NULL; +#ifdef ONE_DEVICE_TEST + if(g_menu_preset & SECOND_VOIP_MASK) + { + media_streamer_src_create(MEDIA_STREAMER_SRC_TYPE_VIDEO_TEST, &video_src); + } + else + { + media_streamer_src_create(MEDIA_STREAMER_SRC_TYPE_CAMERA, &video_src); + } +#else + media_streamer_src_create(MEDIA_STREAMER_SRC_TYPE_CAMERA, &video_src); +#endif +// media_streamer_node_set_fmt(video_src, vfmt_raw); + media_streamer_node_add(current_media_streamer, video_src); + + //********************** encoder **************************************** + media_streamer_node_h video_enc = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER, NULL, vfmt_encoded, &video_enc); + media_streamer_node_add(current_media_streamer, video_enc); + + + //********************** videopay *************************************** + media_streamer_node_h video_pay = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_PAY, NULL, vfmt_encoded, &video_pay); + media_streamer_node_add(current_media_streamer, video_pay); + + //====================Linking Video Streamer===========================// + media_streamer_node_link(video_src, "src", video_enc, "sink"); + media_streamer_node_link(video_enc, "src", video_pay, "sink"); + media_streamer_node_link(video_pay, "src", rtp_bin, "video_sink"); + //======================================================================// + + g_print("== success streamer video part \n"); +#endif + +#ifndef DISABLE_AUDIO + //********************** audiosrc *********************************** + media_streamer_node_h audio_src = NULL; + media_streamer_src_create(MEDIA_STREAMER_SRC_TYPE_AUDIO_CAPTURE, &audio_src); + media_streamer_node_add(current_media_streamer, audio_src); + + //********************** audioencoder *********************************** + media_streamer_node_h audio_enc = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER, NULL, NULL, &audio_enc); + media_streamer_node_add(current_media_streamer, audio_enc); + + + //********************** rtpL16pay *********************************** + media_streamer_node_h audio_pay = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_PAY, NULL, NULL, &audio_pay); + media_streamer_node_add(current_media_streamer, audio_pay); + + //====================Linking Audio Streamer===========================// + media_streamer_node_link(audio_src, "src", audio_enc, "sink"); + media_streamer_node_link(audio_enc, "src", audio_pay, "sink"); + media_streamer_node_link(audio_pay, "src", rtp_bin, "audio_sink"); + //======================================================================// + + g_print("== success streamer audio part \n"); +#endif + + return TRUE; +} + +static gboolean _create_rtp_client(media_streamer_node_h rtp_bin) +{ + g_print("== _create_rtp_client \n"); + +#ifndef DISABLE_VIDEO + //********************** video_depay*********************************** + media_streamer_node_h video_depay = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_DEPAY, NULL, vfmt_encoded, &video_depay); + media_streamer_node_add(current_media_streamer, video_depay); + + //********************** videodec *********************************** + media_streamer_node_h video_dec = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER, NULL, vfmt_encoded, &video_dec); + media_streamer_node_add(current_media_streamer, video_dec); + + //********************** videosink *********************************** + media_streamer_node_h video_sink = NULL; + media_streamer_sink_create(MEDIA_STREAMER_SINK_TYPE_SCREEN, &video_sink); + media_streamer_node_add(current_media_streamer, video_sink); + + //====================Linking Video Client===========================// + media_streamer_node_link(video_depay, "src", video_dec, "sink"); + media_streamer_node_link(video_dec, "src", video_sink,"sink"); +// media_streamer_node_link(rtp_bin, "video_source", video_depay,"sink"); + + g_print("== success client video part \n"); +#endif + +#ifndef DISABLE_AUDIO + //********************** audiodepay *********************************** + media_streamer_node_h audio_depay = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_DEPAY, NULL, NULL, &audio_depay); + media_streamer_node_add(current_media_streamer, audio_depay); + + //********************** audioconvert *********************************** + media_streamer_node_h audio_converter = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_CONVERTER, NULL, NULL, &audio_converter); + media_streamer_node_add(current_media_streamer, audio_converter); + + //********************** audioresample *********************************** + media_streamer_node_h audio_res = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_RESAMPLE, NULL, NULL, &audio_res); + media_streamer_node_add(current_media_streamer, audio_res); + + //********************** audiosink *********************************** + media_streamer_node_h audio_sink = NULL; + media_streamer_sink_create(MEDIA_STREAMER_SINK_TYPE_AUDIO, &audio_sink); + media_streamer_node_add(current_media_streamer, audio_sink); + + //====================Linking Audio Client===========================// + media_streamer_node_link(audio_depay, "src", audio_converter, "sink"); + media_streamer_node_link(audio_converter, "src", audio_res, "sink"); + media_streamer_node_link(audio_res, "src", audio_sink,"sink"); +// media_streamer_node_link(rtp_bin, "audio_source", audio_depay,"sink"); + //======================================================================// + + g_print("== success client audio part \n"); +#endif + + return TRUE; +} + +static media_streamer_node_h _create_rtp( + int video_port, + int audio_port, + gboolean second_client) +{ + g_print("== create rtp node for current preset \n"); + + //********************** rtpbin *********************************** + media_streamer_node_h rtp_bin = NULL; + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_RTP, vfmt_encoded, vfmt_encoded, &rtp_bin); + set_rtp_params(rtp_bin, g_broadcast_address, video_port, audio_port, second_client); + media_streamer_node_add(current_media_streamer, rtp_bin); + return rtp_bin; +} + +/***************************************************************/ +/** Testsuite */ +/***************************************************************/ + +void quit() +{ + reset_current_menu_state(); + g_main_loop_quit(g_loop); +} + +/* + * Function resets menu state to the main menu state + * and cleans media streamer handle. + */ +void reset_current_menu_state(void) +{ + g_menu_state = MENU_STATE_MAIN_MENU; + g_autoplug_mode = FALSE; + current_media_streamer = NULL; + + if (g_media_streamer) + { + _destroy(g_media_streamer); + g_media_streamer = NULL; + } + + if (g_media_streamer_2) + { + _destroy(g_media_streamer_2); + g_media_streamer_2 = NULL; + } + + if(g_broadcast_address != NULL) + { + g_free(g_broadcast_address); + g_broadcast_address = NULL; + } +} + +static void display_getting_ip_menu(void) +{ + g_print("\n"); + g_print("Please input IP address for broadcasting\n"); + g_print("By default will be used [%s]\n", DEFAULT_IP_ADDR); +} + +static void display_autoplug_select_menu(void) +{ + g_print("\n"); + g_print("Please select Media Streamer pluging mode\n"); + g_print("By default will be used [%s] mode\n", + g_autoplug_mode == TRUE ? "autoplug" : "manual"); + g_print("1. Manual mode \n"); + g_print("2. Autoplug mode \n"); +} + +static void display_preset_menu(void) +{ + g_print("\n"); + g_print("====================================================\n"); + g_print(" media streamer test: Preset menu v0.3\n"); + g_print("----------------------------------------------------\n"); + g_print("1. create media streamer \n"); + g_print("2. set up current preset \n"); + g_print("4. prepare \n"); + g_print("5. unprepare \n"); + g_print("6. play \n"); + g_print("7. destroy media streamer \n\n"); + g_print("b. back \n"); + g_print("----------------------------------------------------\n"); + g_print("====================================================\n"); +} + +static void display_voip_menu(void) +{ + g_print("\n"); + g_print("====================================================\n"); + g_print(" media streamer test: VoIP menu v0.3\n"); + g_print("----------------------------------------------------\n"); + g_print("1. one streamer VoIP 1 \n"); + g_print("2. one streamer VoIP 2 \n"); + g_print("3. two streamers VoIP server 1 \n"); + g_print("4. two streamers VoIP server 2 \n"); + g_print("5. two streamers VoIP client 1 \n"); + g_print("6. two streamers VoIP client 2 \n"); + g_print("b. back \n"); + g_print("----------------------------------------------------\n"); + g_print("====================================================\n"); +} + +static void display_broadcast_menu(void) +{ + g_print("\n"); + g_print("====================================================\n"); + g_print(" media streamer test: Broadcast menu v0.3\n"); + g_print("----------------------------------------------------\n"); + g_print("1. Broadcast client \n"); + g_print("2. Broadcast streamer \n"); + g_print("b. back \n"); + g_print("----------------------------------------------------\n"); + g_print("====================================================\n"); +} + +static void display_main_menu(void) +{ + g_print("\n"); + g_print("====================================================\n"); + g_print(" media streamer test: Main menu v0.3\n"); + g_print("----------------------------------------------------\n"); + g_print("1. Broadcast \n"); + g_print("2. VOIP \n"); + g_print("q. quit \n"); + g_print("----------------------------------------------------\n"); + g_print("====================================================\n"); +} + +static void display_menu(void) +{ + if (g_sub_menu_state == SUBMENU_STATE_UNKNOWN) + { + switch (g_menu_state) + { + case MENU_STATE_MAIN_MENU: + display_main_menu(); + break; + case MENU_STATE_BROADCAST_MENU: + display_broadcast_menu(); + break; + case MENU_STATE_VOIP_MENU: + display_voip_menu(); + break; + case MENU_STATE_PRESET_MENU: + display_preset_menu(); + break; + default: + g_print("*** Unknown status.\n"); + break; + } + } + else + { + switch (g_sub_menu_state) + { + case SUBMENU_STATE_GETTING_IP: + display_getting_ip_menu(); + break; + case SUBMENU_STATE_AUTOPLUG: + display_autoplug_select_menu(); + break; + case SUBMENU_STATE_FORMAT: +// display_format_menu(); + break; + default: + g_print("*** Unknown Submenu state.\n"); + break; + } + } + +} + +static void run_preset(void) +{ + media_streamer_node_h rtp_bin = NULL; + create_formats(); + + switch(g_menu_preset) + { + case PRESET_RTP_STREAMER: + rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, FALSE); + _create_rtp_streamer(rtp_bin); + break; + case PRESET_RTP_CLIENT: + rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, TRUE); + _create_rtp_client(rtp_bin); + break; + case PRESET_VOIP: + rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, FALSE); + _create_rtp_streamer(rtp_bin); + _create_rtp_client(rtp_bin); + break; + case PRESET_VOIP_2: + rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, TRUE); + _create_rtp_streamer(rtp_bin); + _create_rtp_client(rtp_bin); + break; + case PRESET_DOUBLE_VOIP_SERVER: + rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, FALSE); + _create_rtp_streamer(rtp_bin); + break; + case PRESET_DOUBLE_VOIP_SERVER_2: + rtp_bin = _create_rtp(VIDEO_PORT+10, AUDIO_PORT+10, TRUE); + _create_rtp_streamer(rtp_bin); + break; + case PRESET_DOUBLE_VOIP_CLIENT: + rtp_bin = _create_rtp(VIDEO_PORT+10, AUDIO_PORT+10, FALSE); + _create_rtp_client(rtp_bin); + break; + case PRESET_DOUBLE_VOIP_CLIENT_2: + rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, TRUE); + _create_rtp_client(rtp_bin); + break; + default: + g_print("Invalid menu preset was selected!"); + break; + } +} + +void _interpret_main_menu(char *cmd) +{ + int len = strlen(cmd); + + if(len == 1) + { + if ( !strncmp(cmd, "1", len)) + { + g_menu_state = MENU_STATE_BROADCAST_MENU; + } + else if ( !strncmp(cmd, "2", len)) + { + g_menu_state = MENU_STATE_VOIP_MENU; + } + else if ( !strncmp(cmd, "q", len)) + { + quit(); + } + } + else + { + g_print("wrong command\n"); + } +} + +//=====================Broadcast Menu============================// +void _interpret_broadcast_menu(char *cmd) +{ + int len = strlen(cmd); + + if(len == 1) + { + if( !strncmp(cmd, "1", len)) + { + g_menu_preset = PRESET_RTP_CLIENT; + g_menu_state = MENU_STATE_PRESET_MENU; + } + else if( !strncmp(cmd, "2", len)) + { + g_menu_preset = PRESET_RTP_STREAMER; + g_menu_state = MENU_STATE_PRESET_MENU; + } + else if( !strncmp(cmd, "b", len)) + { + reset_current_menu_state(); + display_menu(); + } + } + else + { + g_print("wrong command\n"); + } +} + +void _interpret_voip_menu(char *cmd) +{ + int len = strlen(cmd); + + if(len == 1) + { + if( !strncmp(cmd, "1", len)) + { + g_menu_preset = PRESET_VOIP; + g_menu_state = MENU_STATE_PRESET_MENU; + } + else if( !strncmp(cmd, "2", len)) + { + g_menu_preset = PRESET_VOIP_2; + g_menu_state = MENU_STATE_PRESET_MENU; + } + else if( !strncmp(cmd, "3", len)) + { + //double Server 1 + g_menu_preset = PRESET_DOUBLE_VOIP_SERVER; + g_menu_state = MENU_STATE_PRESET_MENU; + } + else if( !strncmp(cmd, "4", len)) + { + //double Server 2 + g_menu_preset = PRESET_DOUBLE_VOIP_SERVER_2; + g_menu_state = MENU_STATE_PRESET_MENU; + } + else if( !strncmp(cmd, "5", len)) + { + //double Client 1 + g_menu_preset = PRESET_DOUBLE_VOIP_CLIENT; + g_menu_state = MENU_STATE_PRESET_MENU; + } + else if( !strncmp(cmd, "6", len)) + { + //double Client 2 + g_menu_preset = PRESET_DOUBLE_VOIP_CLIENT_2; + g_menu_state = MENU_STATE_PRESET_MENU; + } + else if( !strncmp(cmd, "b", len)) + { + reset_current_menu_state(); + //display_menu(); + } + + } + else + { + g_print("wrong command\n"); + } +} + +void _interpret_getting_ip_menu(char *cmd) +{ + int min_len = strlen("0.0.0.0"); + int cmd_len = strlen(cmd); + if(g_broadcast_address != NULL) + { + g_free(g_broadcast_address); + } + + if(cmd_len > min_len) + { + g_broadcast_address = g_strdup(cmd); + g_print("== IP address setted to [%s]\n", g_broadcast_address); + } + else + { + g_broadcast_address = g_strdup(DEFAULT_IP_ADDR); + g_print("Invalid IP. Default address will be used [%s]\n", DEFAULT_IP_ADDR); + } + + run_preset(); + g_sub_menu_state = SUBMENU_STATE_UNKNOWN; +} + +void _interpret_autoplug_menu(char *cmd) +{ + + int cmd_number = atoi(cmd)-1; + + + if(cmd_number == 1 || cmd_number == 0) + { + g_autoplug_mode = cmd_number; + } + else + { + g_print("Invalid input. Default autoplug mode will be used\n"); + } + g_print("Selected pluging mode is [%s]\n", + g_autoplug_mode == TRUE ? "autoplug" : "manual"); + + if(g_menu_preset & PRESET_RTP_STREAMER) + { + g_sub_menu_state = SUBMENU_STATE_GETTING_IP; + } + else + { + run_preset(); + g_sub_menu_state = SUBMENU_STATE_UNKNOWN; + } +} + +void _interpret_preset_menu(char *cmd) +{ + int len = strlen(cmd); + + if(len == 1 || len == 2) + { + if( !strncmp(cmd, "1", len)) + { + if((g_menu_preset & DOUBLE_STREAMER_MASK) && + (g_menu_preset & PRESET_RTP_CLIENT)) + { + _create(&g_media_streamer_2); + current_media_streamer = g_media_streamer_2; + g_print("== success create media streamer 2\n"); + } + else + { + _create(&g_media_streamer); + current_media_streamer = g_media_streamer; + g_print("== success create media streamer\n"); + } + + } + else if( !strncmp(cmd, "2", len)) + { + // call the run_preset function after autoplug mode was selected; + g_sub_menu_state = SUBMENU_STATE_AUTOPLUG; + } + else if( !strncmp(cmd, "4", len)) + { + _prepare(); + } + else if( !strncmp(cmd, "5", len)) + { + _unprepare(); + } + else if( !strncmp(cmd, "6", len)) + { + _play(g_media_streamer); + } + else if( !strncmp(cmd, "7", len)) + { + _destroy(current_media_streamer); + current_media_streamer = NULL; + } + else if( !strncmp(cmd, "b", len)) + { + if(g_menu_preset & DOUBLE_STREAMER_MASK) + { + g_menu_state = MENU_STATE_VOIP_MENU; + g_autoplug_mode = FALSE; + current_media_streamer = NULL; + } + else + { + reset_current_menu_state(); + } + display_menu(); + } + + } + else + { + g_print("wrong command\n"); + } +} + +static void interpret_cmd(char *cmd) +{ + if(g_sub_menu_state == SUBMENU_STATE_UNKNOWN) + { + switch(g_menu_state) + { + case MENU_STATE_MAIN_MENU: + _interpret_main_menu(cmd); + break; + case MENU_STATE_BROADCAST_MENU: + _interpret_broadcast_menu(cmd); + break; + case MENU_STATE_VOIP_MENU: + _interpret_voip_menu(cmd); + break; + case MENU_STATE_PRESET_MENU: + _interpret_preset_menu(cmd); + break; + default: + g_print("Invalid command\n"); + return; + break; + } + } + else + { + switch (g_sub_menu_state) + { + case SUBMENU_STATE_GETTING_IP: + _interpret_getting_ip_menu(cmd); + break; + case SUBMENU_STATE_AUTOPLUG: + _interpret_autoplug_menu(cmd); + break; + case SUBMENU_STATE_FORMAT: + //display_format_menu(); + break; + default: + g_print("*** Unknown Submenu state.\n"); + break; + } + } + + display_menu(); +} + +gboolean input(GIOChannel *channel) +{ + gchar buf[MAX_STRING_LEN]; + gsize read; + GError *error = NULL; + + g_io_channel_read_chars(channel, buf, MAX_STRING_LEN, &read, &error); + + buf[read] = '\0'; + g_strstrip(buf); + interpret_cmd(buf); + + return TRUE; + +} + +int main(int argc, char **argv) +{ + GIOChannel *stdin_channel; + stdin_channel = g_io_channel_unix_new(0); + g_io_channel_set_flags(stdin_channel, G_IO_FLAG_NONBLOCK, NULL); + g_io_add_watch(stdin_channel, G_IO_IN,(GIOFunc)input, NULL); + + display_menu(); + + g_loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(g_loop); + return 0; +} -- 2.7.4 From e9faa413cf217bfed80c43a8ad3b05b7c4c878d1 Mon Sep 17 00:00:00 2001 From: "eunhae1.choi" Date: Wed, 10 Jun 2015 20:35:38 +0900 Subject: [PATCH 3/5] modify the spec file to fix buile error for 64bits and apply tizen coding rule Change-Id: I4499a29fccf551ae91671212e35a61cba643bd62 --- include/media_streamer.h | 108 +++--- include/media_streamer_priv.h | 21 +- include/media_streamer_util.h | 45 ++- packaging/capi-media-streamer.spec | 13 +- src/media_streamer.c | 172 ++++----- src/media_streamer_gst.c | 712 +++++++++++++++---------------------- src/media_streamer_node.c | 279 +++++++-------- src/media_streamer_priv.c | 90 ++--- src/media_streamer_util.c | 70 ++-- test/media_streamer_test.c | 353 +++++++----------- 10 files changed, 773 insertions(+), 1090 deletions(-) diff --git a/include/media_streamer.h b/include/media_streamer.h index 5fd99f8..04ac0b6 100755 --- a/include/media_streamer.h +++ b/include/media_streamer.h @@ -67,8 +67,7 @@ typedef long long media_streamer_time_value; * * @since_tizen 3.0 */ -typedef enum -{ +typedef enum { MEDIA_STREAMER_NODE_TYPE_NONE, /**< Not defined type */ MEDIA_STREAMER_NODE_TYPE_SRC, /**< Src node type */ MEDIA_STREAMER_NODE_TYPE_SINK, /**< Sink node type */ @@ -102,8 +101,7 @@ typedef enum * * @since_tizen 3.0 */ -typedef enum -{ +typedef enum { MEDIA_STREAMER_SRC_TYPE_NONE, /**< Not defined src type */ MEDIA_STREAMER_SRC_TYPE_FILE, /**< Local file src type */ MEDIA_STREAMER_SRC_TYPE_HTTP, /**< Http src type */ @@ -121,8 +119,7 @@ typedef enum * * @since_tizen 3.0 */ -typedef enum -{ +typedef enum { MEDIA_STREAMER_SINK_TYPE_NONE, /**< Not defined sink type */ MEDIA_STREAMER_SINK_TYPE_FILE, /**< Local file sink type */ MEDIA_STREAMER_SINK_TYPE_RTSP, /**< Rtsp sink type */ @@ -138,8 +135,7 @@ typedef enum * * @since_tizen 3.0 */ -typedef enum -{ +typedef enum { MEDIA_STREAMER_STATE_NONE, /**< Streamer is not created */ MEDIA_STREAMER_STATE_IDLE, /**< Streamer is created but not prepared */ MEDIA_STREAMER_STATE_READY, /**< Streamer is ready to play */ @@ -153,17 +149,16 @@ typedef enum * * @since_tizen 3.0 */ -typedef enum -{ +typedef enum { MEDIA_STREAMER_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ 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_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 */ - MEDIA_STREAMER_ERROR_RESOURCE_CONFLICT = TIZEN_ERROR_MEDIA_STREAMER|0x03, /**< Resource conflict */ + MEDIA_STREAMER_ERROR_INVALID_STATE = TIZEN_ERROR_MEDIA_STREAMER | 0x01, /**< Invalid state */ + MEDIA_STREAMER_ERROR_CONNECTION_FAILED = TIZEN_ERROR_MEDIA_STREAMER | 0x02, /**< Connection failed */ + MEDIA_STREAMER_ERROR_RESOURCE_CONFLICT = TIZEN_ERROR_MEDIA_STREAMER | 0x03, /**< Resource conflict */ } media_streamer_error_e; /** @@ -171,10 +166,9 @@ typedef enum * * @since_tizen 3.0 */ -typedef enum -{ - MEDIA_STREAMER_CUSTOM_BUFFER_UNDERRUN, /**< buffer underrun of custom src */ - MEDIA_STREAMER_CUSTOM_BUFFER_OVERFLOW, /**< buffer overflow of custom src */ +typedef enum { + MEDIA_STREAMER_CUSTOM_BUFFER_UNDERRUN, /**< buffer underrun of custom src */ + MEDIA_STREAMER_CUSTOM_BUFFER_OVERFLOW, /**< buffer overflow of custom src */ } media_streamer_custom_buffer_status_e; /** @@ -190,8 +184,8 @@ typedef enum * @see media_streamer_unset_error_cb() */ typedef void (*media_streamer_error_cb)(media_streamer_h streamer, - media_streamer_error_e error, - void *user_data); + media_streamer_error_e error, + void *user_data); /** * @brief Called when media streamer state was changed. @@ -207,9 +201,9 @@ typedef void (*media_streamer_error_cb)(media_streamer_h streamer, * @see media_streamer_unset_state_change_cb() */ typedef void (*media_streamer_state_changed_cb)(media_streamer_h streamer, - media_streamer_state_e previous_state, - media_streamer_state_e current_state, - void *user_data); + media_streamer_state_e previous_state, + media_streamer_state_e current_state, + void *user_data); /** * @brief Called when the custom source needs more data or has enough data. @@ -223,9 +217,9 @@ typedef void (*media_streamer_state_changed_cb)(media_streamer_h streamer, * @see media_streamer_node_get_param_list() * @see media_streamer_node_set_params() */ -typedef void (*media_streamer_custom_buffer_status_cb) (media_streamer_node_h node, - media_streamer_custom_buffer_status_e status, - void *user_data); +typedef void (*media_streamer_custom_buffer_status_cb)(media_streamer_node_h node, + media_streamer_custom_buffer_status_e status, + void *user_data); /** * @brief Called when new data is available from custom sink. @@ -241,7 +235,7 @@ typedef void (*media_streamer_custom_buffer_status_cb) (media_streamer_node_h no * @see media_streamer_sink_unset_data_ready_cb() */ typedef void (*media_streamer_sink_data_ready_cb)(media_streamer_node_h node, - void *user_data); + void *user_data); /** * @brief Called when the end-of-stream has been reached. @@ -257,7 +251,7 @@ typedef void (*media_streamer_sink_data_ready_cb)(media_streamer_node_h node, * @see media_streamer_sink_unset_eos_cb() */ typedef void (*media_streamer_sink_eos_cb)(media_streamer_node_h node, - void *user_data); + void *user_data); /** * @brief Register a error callback function to be invoked when an error occurs. @@ -279,8 +273,8 @@ typedef void (*media_streamer_sink_eos_cb)(media_streamer_node_h node, * @see media_streamer_error_cb() */ int media_streamer_set_error_cb(media_streamer_h streamer, - media_streamer_error_cb callback, - void *user_data); + media_streamer_error_cb callback, + void *user_data); /** * @brief Unregisters the error callback function. @@ -315,8 +309,8 @@ int media_streamer_unset_error_cb(media_streamer_h streamer); * @see media_streamer_state_change_cb() */ int media_streamer_set_state_change_cb(media_streamer_h streamer, - media_streamer_state_changed_cb callback, - void *user_data); + media_streamer_state_changed_cb callback, + void *user_data); /** * @brief Unregisters the state changed callback function. @@ -354,8 +348,8 @@ int media_streamer_unset_state_change_cb(media_streamer_h streamer); * @see media_streamer_custom_buffer_status_cb() */ int media_streamer_src_set_buffer_status_cb(media_streamer_node_h source, - media_streamer_custom_buffer_status_cb callback, - void *user_data); + media_streamer_custom_buffer_status_cb callback, + void *user_data); /** * @brief Unregisters the src buffer status callback function. @@ -392,8 +386,8 @@ int media_streamer_src_unset_buffer_status_cb(media_streamer_node_h source); * @see media_streamer_sink_data_ready_cb() */ int media_streamer_sink_set_data_ready_cb(media_streamer_node_h sink, - media_streamer_sink_data_ready_cb callback, - void *user_data); + media_streamer_sink_data_ready_cb callback, + void *user_data); /** * @brief Unregisters the sink data ready callback function. @@ -429,8 +423,8 @@ int media_streamer_sink_unset_data_ready_cb(media_streamer_h streamer); * @see media_streamer_sink_eos_cb() */ int media_streamer_sink_set_eos_cb(media_streamer_node_h sink, - media_streamer_sink_eos_cb callback, - void *user_data); + media_streamer_sink_eos_cb callback, + void *user_data); /** * @brief Unregisters the sink end-of-stream callback function. @@ -585,7 +579,7 @@ int media_streamer_destroy(media_streamer_h streamer); * @see #media_streamer_state_e */ int media_streamer_get_state(media_streamer_h streamer, - media_streamer_state_e *state); + media_streamer_state_e *state); /** * @brief Creates media streamer source node. @@ -615,7 +609,7 @@ int media_streamer_get_state(media_streamer_h streamer, * @see media_streamer_node_destroy() */ int media_streamer_src_create(media_streamer_src_type_e type, - media_streamer_node_h *src); + media_streamer_node_h *src); /** * @brief Pushes packet into custom source node. @@ -635,7 +629,7 @@ int media_streamer_src_create(media_streamer_src_type_e type, * @see #media_packet_h */ int media_streamer_push_packet(media_streamer_node_h src, - media_packet_h packet); + media_packet_h packet); /** * @brief Creates media streamer sink node. @@ -662,7 +656,7 @@ int media_streamer_push_packet(media_streamer_node_h src, * @see media_streamer_node_destroy() */ int media_streamer_sink_create(media_streamer_sink_type_e type, - media_streamer_node_h *sink); + media_streamer_node_h *sink); /** * @brief Pulls packet from custom sink node. @@ -682,7 +676,7 @@ int media_streamer_sink_create(media_streamer_sink_type_e type, * @see media_streamer_sink_create() */ int media_streamer_pull_packet(media_streamer_node_h sink, - media_packet_h *packet); + media_packet_h *packet); /** * @brief Creates media streamer node except src and sink. @@ -704,9 +698,9 @@ int media_streamer_pull_packet(media_streamer_node_h sink, * @see media_streamer_node_destroy() */ int media_streamer_node_create(media_streamer_node_type_e type, - media_format_h in_fmt, - media_format_h out_fmt, - media_streamer_node_h *node); + media_format_h in_fmt, + media_format_h out_fmt, + media_streamer_node_h *node); /** * @brief Adds node to media streamer. @@ -727,7 +721,7 @@ int media_streamer_node_create(media_streamer_node_type_e type, * @see media_streamer_sink_create() */ int media_streamer_node_add(media_streamer_h streamer, - media_streamer_node_h node); + media_streamer_node_h node); /** * @brief Destroys media streamer node. @@ -764,7 +758,7 @@ int media_streamer_node_destroy(media_streamer_node_h node); * @see media_streamer_node_add() */ int media_streamer_node_remove(media_streamer_h streamer, - media_streamer_node_h node); + media_streamer_node_h node); /** * @brief Sets media format for media streamer node. @@ -781,7 +775,7 @@ int media_streamer_node_remove(media_streamer_h streamer, * @see #media_format_h */ int media_streamer_node_set_format(media_streamer_node_h node, - media_format_h fmt); + media_format_h fmt); /** * @brief Gets media format for media streamer node. @@ -798,7 +792,7 @@ int media_streamer_node_set_format(media_streamer_node_h node, * @see #media_format_h */ int media_streamer_node_get_format(media_streamer_node_h node, - media_format_h *fmt); + media_format_h *fmt); /** * @brief Links two media streamer nodes. @@ -820,9 +814,9 @@ int media_streamer_node_get_format(media_streamer_node_h node, * @see media_streamer_node_add() */ int media_streamer_node_link(media_streamer_node_h src_node, - const char *src_pad, - media_streamer_node_h dest_node, - const char *sink_pad); + const char *src_pad, + media_streamer_node_h dest_node, + const char *sink_pad); /** * @brief Gets formats of node pads. @@ -843,8 +837,8 @@ int media_streamer_node_link(media_streamer_node_h src_node, * @see media_streamer_sink_create() */ int media_streamer_node_get_pad_format(media_streamer_node_h node, - char **src_fmt, - char **sink_fmt); + char **src_fmt, + char **sink_fmt); /** * @brief Sets parameters of node. @@ -867,7 +861,7 @@ int media_streamer_node_get_pad_format(media_streamer_node_h node, * @see media_streamer_node_set_single_param() */ int media_streamer_node_set_params(media_streamer_node_h node, - bundle *param_list); + bundle *param_list); /** * @brief Sets single parameter of node. @@ -891,7 +885,7 @@ int media_streamer_node_set_params(media_streamer_node_h node, * @see media_streamer_node_set_params() */ int media_streamer_node_set_single_param(media_streamer_node_h node, - const char *param_name, const char *param_value); + const char *param_name, const char *param_value); /** * @brief Gets node parameter list. @@ -913,7 +907,7 @@ int media_streamer_node_set_single_param(media_streamer_node_h node, * @see media_streamer_node_set_params() */ int media_streamer_node_get_param_list(media_streamer_node_h node, - bundle **param_list); + bundle **param_list); /** * @} diff --git a/include/media_streamer_priv.h b/include/media_streamer_priv.h index 10070cc..67ecfc5 100755 --- a/include/media_streamer_priv.h +++ b/include/media_streamer_priv.h @@ -33,8 +33,7 @@ extern "C" { * * @since_tizen 3.0 */ -typedef struct -{ +typedef struct { void *callback; void *user_data; } media_streamer_callback_s; @@ -44,8 +43,7 @@ typedef struct * * @since_tizen 3.0 */ -typedef struct -{ +typedef struct { media_streamer_callback_s enough_data_cb; media_streamer_callback_s need_data_cb; } media_streamer_src_callbacks_s; @@ -55,8 +53,7 @@ typedef struct * * @since_tizen 3.0 */ -typedef struct -{ +typedef struct { media_streamer_callback_s data_ready_cb; media_streamer_callback_s eos_cb; } media_streamer_sink_callbacks_s; @@ -66,8 +63,7 @@ typedef struct * * @since_tizen 3.0 */ -typedef struct -{ +typedef struct { media_streamer_ini_t ini; GstElement *pipeline; @@ -94,17 +90,16 @@ typedef struct * @since_tizen 3.0 */ typedef int (*media_streamer_node_set_param)( - struct media_streamer_node_s *node, - const gchar *param_key, - const gchar *param_value); + struct media_streamer_node_s *node, + const gchar *param_key, + const gchar *param_value); /** * @brief Media Streamer node type handle. * * @since_tizen 3.0 */ -typedef struct -{ +typedef struct { GstElement *gst_element; char *name; media_streamer_s *parent_streamer; diff --git a/include/media_streamer_util.h b/include/media_streamer_util.h index dbd052c..e0018c5 100755 --- a/include/media_streamer_util.h +++ b/include/media_streamer_util.h @@ -43,38 +43,38 @@ extern "C" { #define FONT_COLOR_GRAY "\033[37m" #define ms_debug(fmt, arg...) do { \ - LOGD(FONT_COLOR_RESET""fmt"", ##arg); \ -} while(0) + LOGD(FONT_COLOR_RESET""fmt"", ##arg); \ + } while(0) #define ms_info(fmt, arg...) do { \ - LOGI(FONT_COLOR_GREEN""fmt"", ##arg); \ -} while(0) + LOGI(FONT_COLOR_GREEN""fmt"", ##arg); \ + } while(0) #define ms_error(fmt, arg...) do { \ - LOGE(FONT_COLOR_RED""fmt"", ##arg); \ -} while(0) + LOGE(FONT_COLOR_RED""fmt"", ##arg); \ + } while(0) #define ms_debug_fenter() do { \ - LOGD(FONT_COLOR_YELLOW""); \ -} while(0) + LOGD(FONT_COLOR_YELLOW""); \ + } while(0) #define ms_debug_fleave() do { \ - LOGD(FONT_COLOR_PURPLE""); \ -} while(0) + LOGD(FONT_COLOR_PURPLE""); \ + } while(0) #define ms_retm_if(expr, fmt, arg...) do { \ - if(expr) { \ - LOGE(FONT_COLOR_RED""fmt"", ##arg); \ - return; \ -} \ -} while(0) + if(expr) { \ + LOGE(FONT_COLOR_RED""fmt"", ##arg); \ + return; \ + } \ + } while(0) #define ms_retvm_if(expr, val, fmt, arg...) do { \ - if(expr) { \ - LOGE(FONT_COLOR_RED""fmt"", ##arg); \ - return(val); \ -} \ -} while(0) + if(expr) { \ + LOGE(FONT_COLOR_RED""fmt"", ##arg); \ + return(val); \ + } \ + } while(0) #define MS_SAFE_FREE(src) {if(src) {free(src); src = NULL;}} @@ -91,8 +91,7 @@ extern "C" { * * @since_tizen 3.0 */ -typedef struct __media_streamer_ini -{ +typedef struct __media_streamer_ini { /* general */ gboolean generate_dot; @@ -214,7 +213,7 @@ gboolean __ms_destroy_ini_dictionary(dictionary *dict); * @since_tizen 3.0 */ gchar *__ms_ini_get_string(dictionary *dict, const char *ini_path, - char *default_str); + char *default_str); /** * @brief Converts Media Format mime type into string. diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index cf1d34b..74010b8 100755 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -43,16 +43,15 @@ export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE" export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE" %endif MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` -cmake . -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER} - +%cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DFULLVER=%{version} -DMAJORVER=${MAJORVER} make %{?jobs:-j%jobs} %install rm -rf %{buildroot} -mkdir -p %{buildroot}/usr/share/license +mkdir -p %{buildroot}%{_datadir}/license mkdir -p %{buildroot}/usr/bin -cp LICENSE.APLv2 %{buildroot}/usr/share/license/%{name} +cp LICENSE.APLv2 %{buildroot}%{_datadir}/license/%{name} cp test/media_streamer_test %{buildroot}/usr/bin %make_install @@ -64,12 +63,14 @@ cp test/media_streamer_test %{buildroot}/usr/bin %files -%manifest capi-media-streamer.manifest +%manifest %{name}.manifest +%license LICENSE.APLv2 %{_libdir}/libcapi-media-streamer.so.* %{_datadir}/license/%{name} -/usr/bin/* +%{_bindir}/* %files devel +%manifest %{name}.manifest %{_includedir}/media/*.h %{_libdir}/pkgconfig/*.pc %{_libdir}/libcapi-media-streamer.so diff --git a/src/media_streamer.c b/src/media_streamer.c index ccfedcc..459ff70 100755 --- a/src/media_streamer.c +++ b/src/media_streamer.c @@ -30,11 +30,11 @@ */ int media_streamer_src_create(media_streamer_src_type_e type, - media_streamer_node_h *src) + media_streamer_node_h *src) { int ret = MEDIA_STREAMER_ERROR_NONE; - media_streamer_node_s *ms_src = (media_streamer_node_s*)src; + media_streamer_node_s *ms_src = (media_streamer_node_s *)src; ms_retvm_if(ms_src == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_src = (media_streamer_node_s *)calloc(1, sizeof(media_streamer_node_s)); @@ -43,10 +43,9 @@ int media_streamer_src_create(media_streamer_src_type_e type, ms_src->type = MEDIA_STREAMER_NODE_TYPE_SRC; ms_src->subtype = (media_streamer_src_type_e)type; ret = __ms_src_node_create(ms_src); - if(ret != MEDIA_STREAMER_ERROR_NONE) - { + if (ret != MEDIA_STREAMER_ERROR_NONE) { MS_SAFE_FREE(ms_src); - ms_error( "Error creating Src node [%d]",ret); + ms_error("Error creating Src node [%d]", ret); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -57,11 +56,11 @@ int media_streamer_src_create(media_streamer_src_type_e type, } int media_streamer_sink_create(media_streamer_sink_type_e type, - media_streamer_node_h *sink) + media_streamer_node_h *sink) { int ret = MEDIA_STREAMER_ERROR_NONE; - media_streamer_node_s *ms_sink = (media_streamer_node_s*)sink; + media_streamer_node_s *ms_sink = (media_streamer_node_s *)sink; ms_retvm_if(ms_sink == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_sink = (media_streamer_node_s *)calloc(1, sizeof(media_streamer_node_s)); @@ -70,10 +69,9 @@ int media_streamer_sink_create(media_streamer_sink_type_e type, ms_sink->type = MEDIA_STREAMER_NODE_TYPE_SINK; ms_sink->subtype = (media_streamer_sink_type_e)type; ret = __ms_sink_node_create(ms_sink); - if(ret != MEDIA_STREAMER_ERROR_NONE) - { + if (ret != MEDIA_STREAMER_ERROR_NONE) { MS_SAFE_FREE(ms_sink); - ms_error( "Error creating Sink node [%d]",ret); + ms_error("Error creating Sink node [%d]", ret); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -84,13 +82,13 @@ int media_streamer_sink_create(media_streamer_sink_type_e type, } int media_streamer_node_create(media_streamer_node_type_e type, - media_format_h in_fmt, - media_format_h out_fmt, - media_streamer_node_h *node) + media_format_h in_fmt, + media_format_h out_fmt, + media_streamer_node_h *node) { int ret = MEDIA_STREAMER_ERROR_NONE; - media_streamer_node_s *ms_node = (media_streamer_node_s*)node; + media_streamer_node_s *ms_node = (media_streamer_node_s *)node; ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_node = (media_streamer_node_s *)calloc(1, sizeof(media_streamer_node_s)); @@ -100,10 +98,9 @@ int media_streamer_node_create(media_streamer_node_type_e type, ms_node->subtype = 0; ret = __ms_node_create(ms_node, in_fmt, out_fmt); - if(ret != MEDIA_STREAMER_ERROR_NONE) - { + if (ret != MEDIA_STREAMER_ERROR_NONE) { MS_SAFE_FREE(ms_node); - ms_error( "Error creating Node [%d]",ret); + ms_error("Error creating Node [%d]", ret); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -115,19 +112,16 @@ int media_streamer_node_create(media_streamer_node_type_e type, int media_streamer_node_destroy(media_streamer_node_h node) { - media_streamer_node_s *ms_node = (media_streamer_node_s*)node; + media_streamer_node_s *ms_node = (media_streamer_node_s *)node; ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); - if (ms_node->parent_streamer == NULL) - { - // This node was not added into any media streamer + if (ms_node->parent_streamer == NULL) { + /* This node was not added into any media streamer */ __ms_node_destroy(ms_node); - } - else - { + } else { int ret = __ms_node_remove_from_table(ms_node->parent_streamer->nodes_table, ms_node); ms_retvm_if(ret != MEDIA_STREAMER_ERROR_NONE, MEDIA_STREAMER_ERROR_INVALID_OPERATION, - "Current key was not removed from nodes_table"); + "Current key was not removed from nodes_table"); } ms_info("Node destroyed successfully"); @@ -135,19 +129,19 @@ int media_streamer_node_destroy(media_streamer_node_h node) } int media_streamer_node_add(media_streamer_h streamer, - media_streamer_node_h node) + media_streamer_node_h node) { int ret = MEDIA_STREAMER_ERROR_NONE; - media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; ms_retvm_if(streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); - media_streamer_node_s* ms_node = (media_streamer_node_s*)node; + media_streamer_node_s *ms_node = (media_streamer_node_s *)node; ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); g_mutex_lock(&ms_streamer->mutex_lock); - __ms_node_insert_into_table(ms_streamer->nodes_table,ms_node); + __ms_node_insert_into_table(ms_streamer->nodes_table, ms_node); ms_node->parent_streamer = ms_streamer; __ms_add_node_into_bin(ms_streamer, ms_node); @@ -159,21 +153,19 @@ int media_streamer_node_add(media_streamer_h streamer, int media_streamer_prepare(media_streamer_h streamer) { - media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_retvm_if(ms_streamer->pipeline == NULL, MEDIA_STREAMER_ERROR_INVALID_STATE, "Pipeline doesn`t exist"); g_mutex_lock(&ms_streamer->mutex_lock); - if(ms_streamer->state > MEDIA_STREAMER_STATE_IDLE) - { + if (ms_streamer->state > MEDIA_STREAMER_STATE_IDLE) { ms_error("Error: Media streamer already prepared [%d]!", - MEDIA_STREAMER_ERROR_INVALID_OPERATION); + MEDIA_STREAMER_ERROR_INVALID_OPERATION); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } - if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_READY) != MEDIA_STREAMER_ERROR_NONE) - { + if (__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_READY) != MEDIA_STREAMER_ERROR_NONE) { ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -186,14 +178,13 @@ int media_streamer_prepare(media_streamer_h streamer) int media_streamer_unprepare(media_streamer_h streamer) { - media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_retvm_if(ms_streamer->pipeline == NULL, MEDIA_STREAMER_ERROR_INVALID_STATE, "Pipeline doesn`t exist"); g_mutex_lock(&ms_streamer->mutex_lock); - if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_IDLE) != MEDIA_STREAMER_ERROR_NONE) - { + if (__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_IDLE) != MEDIA_STREAMER_ERROR_NONE) { ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -205,20 +196,18 @@ int media_streamer_unprepare(media_streamer_h streamer) int media_streamer_play(media_streamer_h streamer) { - media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); g_mutex_lock(&ms_streamer->mutex_lock); - if(ms_streamer->state < MEDIA_STREAMER_STATE_READY) - { + if (ms_streamer->state < MEDIA_STREAMER_STATE_READY) { ms_error("Error: Media streamer must be prepared first [%d]!", - MEDIA_STREAMER_ERROR_INVALID_OPERATION); + MEDIA_STREAMER_ERROR_INVALID_OPERATION); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } - if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_PLAYING) != MEDIA_STREAMER_ERROR_NONE) - { + if (__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_PLAYING) != MEDIA_STREAMER_ERROR_NONE) { ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -243,8 +232,7 @@ int media_streamer_create(media_streamer_h *streamer) ms_streamer->state = MEDIA_STREAMER_STATE_NONE; ret = __ms_create(ms_streamer); - if(ret!=MEDIA_STREAMER_ERROR_NONE) - { + if (ret != MEDIA_STREAMER_ERROR_NONE) { ms_error("Error creating Media Streamer"); __ms_streamer_destroy(ms_streamer); @@ -253,8 +241,7 @@ int media_streamer_create(media_streamer_h *streamer) return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } - if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_IDLE) != MEDIA_STREAMER_ERROR_NONE) - { + if (__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_IDLE) != MEDIA_STREAMER_ERROR_NONE) { ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -266,7 +253,7 @@ int media_streamer_create(media_streamer_h *streamer) int media_streamer_destroy(media_streamer_h streamer) { - media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); g_mutex_lock(&ms_streamer->mutex_lock); @@ -282,8 +269,8 @@ int media_streamer_destroy(media_streamer_h streamer) } int media_streamer_set_error_cb(media_streamer_h streamer, - media_streamer_error_cb callback, - void *data) + media_streamer_error_cb callback, + void *data) { return MEDIA_STREAMER_ERROR_NONE; } @@ -294,8 +281,8 @@ int media_streamer_unset_error_cb(media_streamer_h streamer) } int media_streamer_set_state_change_cb(media_streamer_h streamer, - media_streamer_state_changed_cb callback, - void *data) + media_streamer_state_changed_cb callback, + void *data) { return MEDIA_STREAMER_ERROR_NONE; } @@ -306,8 +293,8 @@ int media_streamer_unset_state_change_cb(media_streamer_h streamer) } int media_streamer_src_set_buffer_status_cb(media_streamer_node_h source, - media_streamer_custom_buffer_status_cb callback, - void *user_data) + media_streamer_custom_buffer_status_cb callback, + void *user_data) { return MEDIA_STREAMER_ERROR_NONE; } @@ -318,8 +305,8 @@ int media_streamer_src_unset_buffer_status_cb(media_streamer_node_h source) } int media_streamer_sink_set_data_ready_cb(media_streamer_node_h sink, - media_streamer_sink_data_ready_cb callback, - void *data) + media_streamer_sink_data_ready_cb callback, + void *data) { return MEDIA_STREAMER_ERROR_NONE; } @@ -330,8 +317,8 @@ int media_streamer_sink_unset_data_ready_cb(media_streamer_node_h source) } int media_streamer_sink_set_eos_cb(media_streamer_node_h sink, - media_streamer_sink_eos_cb callback, - void *data) + media_streamer_sink_eos_cb callback, + void *data) { return MEDIA_STREAMER_ERROR_NONE; } @@ -343,13 +330,12 @@ int media_streamer_sink_unset_eos_cb(media_streamer_node_h source) int media_streamer_pause(media_streamer_h streamer) { - media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); g_mutex_lock(&ms_streamer->mutex_lock); - if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_PAUSED) != MEDIA_STREAMER_ERROR_NONE) - { + if (__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_PAUSED) != MEDIA_STREAMER_ERROR_NONE) { ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -361,20 +347,18 @@ int media_streamer_pause(media_streamer_h streamer) int media_streamer_stop(media_streamer_h streamer) { - media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); g_mutex_lock(&ms_streamer->mutex_lock); - if(ms_streamer->state < MEDIA_STREAMER_STATE_READY) - { + if (ms_streamer->state < MEDIA_STREAMER_STATE_READY) { ms_error("Error: Media streamer must be prepared first [%d]!", - MEDIA_STREAMER_ERROR_INVALID_OPERATION); + MEDIA_STREAMER_ERROR_INVALID_OPERATION); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } - if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_READY) != MEDIA_STREAMER_ERROR_NONE) - { + if (__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_READY) != MEDIA_STREAMER_ERROR_NONE) { ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -385,9 +369,9 @@ int media_streamer_stop(media_streamer_h streamer) } int media_streamer_get_state(media_streamer_h streamer, - media_streamer_state_e *state) + media_streamer_state_e *state) { - media_streamer_s *ms_streamer = (media_streamer_s*)streamer; + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); *state = ms_streamer->state; @@ -396,28 +380,28 @@ int media_streamer_get_state(media_streamer_h streamer, } int media_streamer_seek(media_streamer_h streamer, - media_streamer_time_value time) + media_streamer_time_value time) { return MEDIA_STREAMER_ERROR_NONE; } int media_streamer_push_packet(media_streamer_node_h src, - media_packet_h packet) + media_packet_h packet) { return MEDIA_STREAMER_ERROR_NONE; } int media_streamer_pull_packet(media_streamer_node_h sink, - media_packet_h *packet) + media_packet_h *packet) { return MEDIA_STREAMER_ERROR_NONE; } int media_streamer_node_set_format(media_streamer_node_h node, - media_format_h fmt) + media_format_h fmt) { int ret = MEDIA_STREAMER_ERROR_NONE; - media_streamer_node_s *ms_node = (media_streamer_node_s*)node; + media_streamer_node_s *ms_node = (media_streamer_node_s *)node; ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Format is NULL"); @@ -426,10 +410,10 @@ int media_streamer_node_set_format(media_streamer_node_h node, } int media_streamer_node_get_format(media_streamer_node_h node, - media_format_h *fmt) + media_format_h *fmt) { int ret = MEDIA_STREAMER_ERROR_NONE; - media_streamer_node_s *ms_node = (media_streamer_node_s*)node; + media_streamer_node_s *ms_node = (media_streamer_node_s *)node; ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Format is NULL"); @@ -438,15 +422,15 @@ int media_streamer_node_get_format(media_streamer_node_h node, } int media_streamer_node_link(media_streamer_node_h src_node, - const char *src_pad, - media_streamer_node_h dest_node, - const char *sink_pad) + const char *src_pad, + media_streamer_node_h dest_node, + const char *sink_pad) { int ret = MEDIA_STREAMER_ERROR_NONE; - media_streamer_node_s *ms_src_node = (media_streamer_node_s*)src_node; + media_streamer_node_s *ms_src_node = (media_streamer_node_s *)src_node; ms_retvm_if(ms_src_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); - media_streamer_node_s *ms_dest_node = (media_streamer_node_s*)dest_node; + media_streamer_node_s *ms_dest_node = (media_streamer_node_s *)dest_node; ms_retvm_if(ms_dest_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); gchar *src_element_name = gst_element_get_name(ms_src_node->gst_element); gchar *sink_element_name = gst_element_get_name(ms_dest_node->gst_element); @@ -456,9 +440,8 @@ int media_streamer_node_link(media_streamer_node_h src_node, gboolean link_ret; - link_ret = gst_element_link_pads (ms_src_node->gst_element, src_pad, ms_dest_node->gst_element, sink_pad); - if(!link_ret) - { + link_ret = gst_element_link_pads(ms_src_node->gst_element, src_pad, ms_dest_node->gst_element, sink_pad); + if (!link_ret) { ms_error("Can not link [%s]->%s pad to [%s]->%s pad, ret code [%d] ", src_pad, sink_pad, src_element_name, sink_element_name, link_ret); ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -469,33 +452,33 @@ int media_streamer_node_link(media_streamer_node_h src_node, } int media_streamer_node_get_pad_format(media_streamer_node_h node, - char **in_fmt, - char **out_fmt) + char **in_fmt, + char **out_fmt) { return MEDIA_STREAMER_ERROR_NONE; } int media_streamer_node_set_params(media_streamer_node_h node, - bundle *param_list) + bundle *param_list) { int ret = MEDIA_STREAMER_ERROR_NONE; - media_streamer_node_s *ms_node = (media_streamer_node_s*)node; + media_streamer_node_s *ms_node = (media_streamer_node_s *)node; ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_retvm_if(ms_node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_retvm_if(param_list == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Parameters list is NULL"); - ret = __ms_node_read_params_from_bundle(ms_node,param_list); + ret = __ms_node_read_params_from_bundle(ms_node, param_list); ms_retvm_if(ret != MEDIA_STREAMER_ERROR_NONE, MEDIA_STREAMER_ERROR_INVALID_OPERATION, - "Parameters list is NULL"); + "Parameters list is NULL"); return ret; } int media_streamer_node_get_param_list(media_streamer_node_h node, - bundle **param_list) + bundle **param_list) { - media_streamer_node_s *ms_node =(media_streamer_node_s*)node; + media_streamer_node_s *ms_node = (media_streamer_node_s *)node; ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_retvm_if(param_list == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Param list pionter is NULL"); @@ -503,8 +486,7 @@ int media_streamer_node_get_param_list(media_streamer_node_h node, ms_params = bundle_create(); ms_retvm_if(ms_params == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Error creating new params object"); - if (__ms_node_write_params_into_bundle(ms_node, ms_params) != MEDIA_STREAMER_ERROR_NONE) - { + if (__ms_node_write_params_into_bundle(ms_node, ms_params) != MEDIA_STREAMER_ERROR_NONE) { ms_info("Node [%s] do not have any params.", ms_node->name); bundle_free(ms_params); *param_list = NULL; diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index e452e03..b63ce9a 100755 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -27,18 +27,15 @@ void __ms_generate_dots(GstElement *bin, gchar *name_tag) gchar *dot_name; ms_retm_if(bin == NULL, "Handle is NULL"); - if (!name_tag) - { + if (!name_tag) { dot_name = g_strdup(DOT_FILE_NAME); - } - else - { - dot_name = g_strconcat (DOT_FILE_NAME, ".", name_tag, NULL); + } else { + dot_name = g_strconcat(DOT_FILE_NAME, ".", name_tag, NULL); } GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(bin), GST_DEBUG_GRAPH_SHOW_ALL, dot_name); - MS_SAFE_GFREE (dot_name); + MS_SAFE_GFREE(dot_name); } const char *_ms_state_to_string(GstState state) @@ -48,8 +45,7 @@ const char *_ms_state_to_string(GstState state) static const char ready[] = "READY\0"; static const char paused[] = "PAUSED\0"; static const char playing[] = "PLAYING\0"; - switch(state) - { + switch (state) { case GST_STATE_VOID_PENDING: return pending; break; @@ -73,9 +69,9 @@ const char *_ms_state_to_string(GstState state) } static int __ms_add_ghostpad(GstElement *gst_element, - const char *pad_name, - GstElement *gst_bin, - const char *ghost_pad_name) + const char *pad_name, + GstElement *gst_bin, + const char *ghost_pad_name) { ms_retvm_if(!ghost_pad_name || !gst_bin, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); @@ -84,24 +80,19 @@ static int __ms_add_ghostpad(GstElement *gst_element, GstPad *ghost_pad = NULL; gchar *bin_name = gst_element_get_name(gst_bin); - if(!gst_element || !pad_name) - { + if (!gst_element || !pad_name) { ghost_pad = gst_ghost_pad_new_no_target(ghost_pad_name, GST_PAD_SRC); gst_element_add_pad(GST_ELEMENT(gst_bin), ghost_pad); - ms_info("Added %s empty ghostpad into [%s]", bin_name); - ret = MEDIA_STREAMER_ERROR_NONE; - } - else - { + ms_info("Added %s empty ghostpad into [%s]", bin_name); + ret = MEDIA_STREAMER_ERROR_NONE; + } else { gchar *element_name = gst_element_get_name(gst_element); GstPad *element_pad = gst_element_get_static_pad(gst_element, pad_name); - if(!element_pad) - { - //maybe it is request pad + if (!element_pad) { + /*maybe it is request pad */ element_pad = gst_element_get_request_pad(gst_element, pad_name); } - if(element_pad != NULL) - { + if (element_pad != NULL) { ghost_pad = gst_ghost_pad_new(ghost_pad_name, element_pad); gst_pad_set_active(ghost_pad, TRUE); @@ -111,11 +102,9 @@ static int __ms_add_ghostpad(GstElement *gst_element, MS_SAFE_GFREE(element_name); ret = MEDIA_STREAMER_ERROR_NONE; - } - else - { + } else { ms_error("Error: element [%s] does not have valid [%s] pad for adding into [%s] bin", - element_name, pad_name, bin_name); + element_name, pad_name, bin_name); ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; } } @@ -130,35 +119,28 @@ static GObject *__ms_get_property_owner(GstElement *element, const gchar *key, G GParamSpec *param; GObject *obj = NULL; - if (GST_IS_CHILD_PROXY(element)) - { + if (GST_IS_CHILD_PROXY(element)) { int i; int childs_count = gst_child_proxy_get_children_count(GST_CHILD_PROXY(element)); param = NULL; - for(i = 0; (i < childs_count) && (param == NULL); ++i) - { - obj = gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(element),i); + for (i = 0; (i < childs_count) && (param == NULL); ++i) { + obj = gst_child_proxy_get_child_by_index(GST_CHILD_PROXY(element), i); param = g_object_class_find_property(G_OBJECT_GET_CLASS(obj), key); } ms_retvm_if(param == NULL || obj == NULL, NULL, "Error: Bin object does not have property [%s].", key); - } - else - { + } else { obj = G_OBJECT(element); param = g_object_class_find_property - (G_OBJECT_GET_CLASS(obj), key); + (G_OBJECT_GET_CLASS(obj), key); } g_value_init(value, param->value_type); - if (param->flags & G_PARAM_WRITABLE) - { + if (param->flags & G_PARAM_WRITABLE) { g_object_get_property(G_OBJECT(obj), key, value); - } - else - { - // Skip properties which user can not change. + } else { + /* Skip properties which user can not change. */ ms_error("Error: node param [%s] is not writable!", key); return NULL; } @@ -173,112 +155,95 @@ static void __ms_element_set_property(GstElement *element, const gchar *key, con GValue value = G_VALUE_INIT; GObject *obj = __ms_get_property_owner(element, key, &value); - if(obj == NULL) - { + if (obj == NULL) { ms_debug("Element [%s] does not have property [%s].", element_name, key); MS_SAFE_GFREE(element_name); return; } - switch(G_VALUE_TYPE(&value)) - { + switch (G_VALUE_TYPE(&value)) { case G_TYPE_STRING: g_value_set_string(&value, param_value); ms_info("Set string value: [%s]", g_value_get_string(&value)); break; - case G_TYPE_BOOLEAN: - { - gboolean bool_val = !g_strcmp0(param_value, "true") ? TRUE : FALSE; - g_value_set_boolean(&value, bool_val); - ms_info("Set boolean value: [%d]", g_value_get_boolean(&value)); - break; - } + case G_TYPE_BOOLEAN: { + gboolean bool_val = !g_strcmp0(param_value, "true") ? TRUE : FALSE; + g_value_set_boolean(&value, bool_val); + ms_info("Set boolean value: [%d]", g_value_get_boolean(&value)); + break; + } - case G_TYPE_ULONG: - { - unsigned long pulong = atol(param_value); - g_value_set_ulong(&value, pulong); - ms_info("Set ulong value: [%lu]", g_value_get_ulong(&value)); - break; - } + case G_TYPE_ULONG: { + unsigned long pulong = atol(param_value); + g_value_set_ulong(&value, pulong); + ms_info("Set ulong value: [%lu]", g_value_get_ulong(&value)); + break; + } - case G_TYPE_LONG: - { - long plong = atol(param_value); - g_value_set_long(&value, plong); - ms_info("Set long value: [%ld]", g_value_get_long(&value)); - break; - } + case G_TYPE_LONG: { + long plong = atol(param_value); + g_value_set_long(&value, plong); + ms_info("Set long value: [%ld]", g_value_get_long(&value)); + break; + } - case G_TYPE_UINT: - { - unsigned int puint = atoi(param_value); - g_value_set_uint(&value, puint); - ms_info("Set uint value: [%u]", g_value_get_uint(&value)); - break; - } + case G_TYPE_UINT: { + unsigned int puint = atoi(param_value); + g_value_set_uint(&value, puint); + ms_info("Set uint value: [%u]", g_value_get_uint(&value)); + break; + } - case G_TYPE_INT: - { - int pint = atoi(param_value); - g_value_set_int(&value, pint); - ms_info("Set int value: [%d]", g_value_get_int(&value)); - break; - } + case G_TYPE_INT: { + int pint = atoi(param_value); + g_value_set_int(&value, pint); + ms_info("Set int value: [%d]", g_value_get_int(&value)); + break; + } - case G_TYPE_UINT64: - { - unsigned long long puint64 = strtoull(param_value, NULL, 10); - g_value_set_uint64(&value, puint64); - ms_info("Set long value: [%llu]", g_value_get_uint64(&value)); - break; - } + case G_TYPE_UINT64: { + unsigned long long puint64 = strtoull(param_value, NULL, 10); + g_value_set_uint64(&value, puint64); + ms_info("Set long value: [%llu]", g_value_get_uint64(&value)); + break; + } - case G_TYPE_INT64: - { - long long pint64 = strtoll(param_value, NULL, 10); - g_value_set_int64(&value, pint64); - ms_info("Set long value: [%ll]", g_value_get_int64(&value)); - break; - } - case G_TYPE_FLOAT: - { - float pfloat = strtof(param_value, NULL); - g_value_set_float(&value, pfloat); - ms_info("Set long value: [%15.7g]", g_value_get_float(&value)); - break; - } - case G_TYPE_DOUBLE: - { - double pdouble = strtod(param_value, NULL); - g_value_set_double(&value, pdouble); - ms_info("Set long value: [%15.7g]", g_value_get_float(&value)); - break; - } - default: - if(G_VALUE_TYPE(&value) == GST_TYPE_CAPS) - { - GstCaps *caps = gst_caps_from_string(param_value); - - if (!caps) - { - ms_error("Can not create caps from param value."); + case G_TYPE_INT64: { + long long pint64 = strtoll(param_value, NULL, 10); + g_value_set_int64(&value, pint64); + ms_info("Set long value: [%ll]", g_value_get_int64(&value)); + break; } - else - { - ms_info("Create Caps from params and set to the object."); - g_object_set(obj, key, caps, NULL); - gst_caps_unref(caps); + case G_TYPE_FLOAT: { + float pfloat = strtof(param_value, NULL); + g_value_set_float(&value, pfloat); + ms_info("Set long value: [%15.7g]", g_value_get_float(&value)); + break; } - return; - } - else - { - ms_info("Got unknown type with param->value_type [%d]", G_VALUE_TYPE(&value)); - return; - } - break; + case G_TYPE_DOUBLE: { + double pdouble = strtod(param_value, NULL); + g_value_set_double(&value, pdouble); + ms_info("Set long value: [%15.7g]", g_value_get_float(&value)); + break; + } + default: + if (G_VALUE_TYPE(&value) == GST_TYPE_CAPS) { + GstCaps *caps = gst_caps_from_string(param_value); + + if (!caps) { + ms_error("Can not create caps from param value."); + } else { + ms_info("Create Caps from params and set to the object."); + g_object_set(obj, key, caps, NULL); + gst_caps_unref(caps); + } + return; + } else { + ms_info("Got unknown type with param->value_type [%d]", G_VALUE_TYPE(&value)); + return; + } + break; } g_object_set_property(obj, key, &value); MS_SAFE_GFREE(element_name); @@ -300,44 +265,32 @@ static void __ms_link_elements_on_pad_added_cb(GstPad *new_pad, GstElement *sink sink_element_name = gst_element_get_name(sink_element); new_pad_name = gst_pad_get_name(new_pad); - if(!gst_pad_is_linked(sink_pad)) - { + if (!gst_pad_is_linked(sink_pad)) { ms_info("Pads [rtpbin].[%s] and [%s].[sink] are not linked\n", new_pad_name, sink_element_name); ret = gst_pad_link(new_pad, sink_pad); - if(GST_PAD_LINK_FAILED (ret)) - { + if (GST_PAD_LINK_FAILED(ret)) { ms_error("Failed to link [rtpbin].[%s] and [%s].[sink]\n", new_pad_name, sink_element_name); - } - else - { + } else { ms_info("Succeeded to link [rtpbin].[%s]->[%s].[sink]\n", new_pad_name, sink_element_name); } - } - else - { + } else { peer_pad = gst_pad_get_peer(sink_pad); peer_pad_name = gst_pad_get_name(peer_pad); ms_debug("Pads [rtpbin].[%s]->[%s].[sink] are previously linked\n", peer_pad_name, sink_element_name); ret = gst_pad_unlink(peer_pad, sink_pad); - if(!ret) - { + if (!ret) { ms_error("Filed to unlink pads [rtpbin].[%s] <-and-> [%s].[sink] \n", peer_pad_name, sink_element_name); - } - else - { + } else { ms_info("Pads [rtpbin].[%s] <-and-> [%s].[sink] are unlinked successfully\n", peer_pad_name, sink_element_name); } ret = gst_pad_link(new_pad, sink_pad); - if(GST_PAD_LINK_FAILED(ret)) - { + if (GST_PAD_LINK_FAILED(ret)) { ms_error("Failed to link [rtpbin].[%s] and [%s].[sink]\n", new_pad_name, sink_element_name); - } - else - { + } else { ms_info("Succeeded to link [rtpbin].[%s]->[%s].[sink]\n", new_pad_name, sink_element_name); } } @@ -356,7 +309,7 @@ static void __ms_got_rtpstream_on_pad_added_cb(media_streamer_node_s *ms_node, G gchar *sink_element_name = NULL; GstElement *sink_element; - GValue elem=G_VALUE_INIT; + GValue elem = G_VALUE_INIT; const gchar *depay_klass_name = "Codec/Depayloader/Network/RTP"; GstIterator *bin_iterator; @@ -364,25 +317,22 @@ static void __ms_got_rtpstream_on_pad_added_cb(media_streamer_node_s *ms_node, G gchar *source_pad_name = g_strdup_printf("%s_source", compared_type); bin_iterator = gst_bin_iterate_elements(GST_BIN(ms_node->parent_streamer->topology_bin)); - while(GST_ITERATOR_OK == gst_iterator_next(bin_iterator, &elem)) - { + while (GST_ITERATOR_OK == gst_iterator_next(bin_iterator, &elem)) { sink_element = (GstElement *)g_value_get_object(&elem); sink_element_name = gst_element_get_name(sink_element); const gchar *klass_name = gst_element_factory_get_klass(gst_element_get_factory(sink_element)); - if( g_strrstr(klass_name, depay_klass_name)) - { - src_pad = gst_element_get_static_pad (sink_element, "src"); + if (g_strrstr(klass_name, depay_klass_name)) { + src_pad = gst_element_get_static_pad(sink_element, "src"); ms_retm_if(src_pad == NULL, "Src pad is NULL"); - src_pad_caps = gst_pad_query_caps(src_pad,NULL); + src_pad_caps = gst_pad_query_caps(src_pad, NULL); src_pad_struct = gst_caps_get_structure(src_pad_caps, 0); const gchar *src_pad_type = gst_structure_get_name(src_pad_struct); - if (g_strrstr(src_pad_type, compared_type)) - { + if (g_strrstr(src_pad_type, compared_type)) { ms_debug("Element to connect [%s] has type [%s] \n", sink_element_name, src_pad_type); GstPad *video_source_pad = gst_element_get_static_pad(ms_node->gst_element, source_pad_name); @@ -422,35 +372,27 @@ static void __ms_rtpbin_pad_added_cb(GstElement *src, GstPad *new_pad, gpointer ms_debug("Pad [%s] added on [%s]\n", new_pad_name, src_element_name); target_pad = gst_ghost_pad_get_target(GST_GHOST_PAD(new_pad)); - src_pad_caps = gst_pad_query_caps(target_pad,NULL); + src_pad_caps = gst_pad_query_caps(target_pad, NULL); src_pad_struct = gst_caps_get_structure(src_pad_caps, 0); const gchar *src_pad_type = gst_structure_get_string(src_pad_struct, "media"); ms_debug("type is [%s]", src_pad_type); - if(ms_node->parent_streamer == NULL) - { + if (ms_node->parent_streamer == NULL) { ms_error("Node doesn`t have parent streamer:\n"); - } - else - { + } else { gchar *source_pad_name = NULL; GstElement *sink_bin = NULL; - if(g_strrstr(src_pad_type, "video")) - { + if (g_strrstr(src_pad_type, "video")) { source_pad_name = g_strdup_printf("%s_source", "video"); sink_bin = ms_node->parent_streamer->sink_video_bin; - } - else if(g_strrstr(src_pad_type, "audio")) - { + } else if (g_strrstr(src_pad_type, "audio")) { source_pad_name = g_strdup_printf("%s_source", "audio"); sink_bin = ms_node->parent_streamer->sink_audio_bin; } - if(source_pad_name != NULL) - { - if(gst_object_get_parent(GST_OBJECT(sink_bin)) == NULL) - { + if (source_pad_name != NULL) { + if (gst_object_get_parent(GST_OBJECT(sink_bin)) == NULL) { gst_bin_add(GST_BIN(ms_node->parent_streamer->pipeline), sink_bin); } gst_element_sync_state_with_parent(sink_bin); @@ -461,16 +403,12 @@ static void __ms_rtpbin_pad_added_cb(GstElement *src, GstPad *new_pad, gpointer gst_pad_set_active(source_pad, TRUE); GstPad *sink_pad = gst_bin_find_unlinked_pad(GST_BIN(sink_bin), GST_PAD_SINK); - if(sink_pad != NULL) - { + if (sink_pad != NULL) { __ms_add_ghostpad(gst_pad_get_parent(sink_pad), "sink", sink_bin, "sink"); - if (gst_element_link_pads(ms_node->gst_element, source_pad_name, sink_bin, "sink")) - { + if (gst_element_link_pads(ms_node->gst_element, source_pad_name, sink_bin, "sink")) { __ms_element_set_state(ms_node->gst_element, GST_STATE_PLAYING); __ms_generate_dots(ms_node->parent_streamer->pipeline, "playing"); - } - else - { + } else { ms_error("Failed to link [rtp_containeer].[%s] and [sink_bin].[sink]\n", source_pad_name); } MS_SAFE_UNREF(sink_pad); @@ -494,8 +432,7 @@ int __ms_element_set_state(GstElement *gst_element, GstState gst_state) gchar *element_name = gst_element_get_name(gst_element); ret_state = gst_element_set_state(gst_element, gst_state); - if(ret_state == GST_STATE_CHANGE_FAILURE) - { + if (ret_state == GST_STATE_CHANGE_FAILURE) { ms_error("Failed to set element [%s] into %s state", element_name, _ms_state_to_string(gst_state)); MS_SAFE_GFREE(element_name); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; @@ -507,14 +444,14 @@ int __ms_element_set_state(GstElement *gst_element, GstState gst_state) GstElement *__ms_element_create(const char *plugin_name, const char *name) { - ms_retvm_if(plugin_name == NULL, (GstElement*)NULL, "Error empty plugin name"); + ms_retvm_if(plugin_name == NULL, (GstElement *)NULL, "Error empty plugin name"); ms_info("Creating [%s] element", plugin_name); return gst_element_factory_make(plugin_name, name); } GstElement *__ms_camera_element_create(const char *camera_plugin_name) { - ms_retvm_if(camera_plugin_name == NULL, (GstElement*)NULL, "Error empty camera plugin name"); + ms_retvm_if(camera_plugin_name == NULL, (GstElement *)NULL, "Error empty camera plugin name"); gboolean gst_ret = FALSE; GstElement *camera_bin = gst_bin_new("camera_src"); @@ -522,17 +459,16 @@ GstElement *__ms_camera_element_create(const char *camera_plugin_name) GstElement *filter = __ms_element_create("capsfilter", NULL); GstElement *scale = __ms_element_create("videoscale", NULL); GstElement *videoconvert = __ms_element_create("videoconvert", NULL); - ms_retvm_if(!filter || !camera_elem || !camera_bin || !scale || !videoconvert , (GstElement*)NULL, - "Error: creating elements for camera bin"); + ms_retvm_if(!filter || !camera_elem || !camera_bin || !scale || !videoconvert , (GstElement *)NULL, + "Error: creating elements for camera bin"); GstCaps *videoCaps = gst_caps_from_string(MEDIA_STREAMER_DEFAULT_CAMERA_FORMAT); - g_object_set (G_OBJECT (filter), "caps", videoCaps, NULL); + g_object_set(G_OBJECT(filter), "caps", videoCaps, NULL); gst_caps_unref(videoCaps); gst_bin_add_many(GST_BIN(camera_bin), camera_elem, filter, scale, videoconvert, NULL); gst_ret = gst_element_link_many(camera_elem, filter, scale, videoconvert, NULL); - if (gst_ret != TRUE) - { + if (gst_ret != TRUE) { ms_error("Failed to link elements into camerabin"); MS_SAFE_UNREF(camera_bin); } @@ -549,24 +485,24 @@ GstElement *__ms_video_encoder_element_create(dictionary *dict , media_format_mi format_prefix = g_strdup_printf("%s:encoder", __ms_convert_mime_to_string(mime)); plugin_name = __ms_ini_get_string(dict, format_prefix, DEFAULT_VIDEO_DECODER); - GstElement *encoder_elem = __ms_element_create(plugin_name,NULL); + GstElement *encoder_elem = __ms_element_create(plugin_name, NULL); MS_SAFE_FREE(format_prefix); MS_SAFE_FREE(plugin_name); format_prefix = g_strdup_printf("%s:parser", __ms_convert_mime_to_string(mime)); plugin_name = __ms_ini_get_string(dict, format_prefix, DEFAULT_VIDEO_PARSER); - GstElement *encoder_parser = __ms_element_create(plugin_name,NULL); + GstElement *encoder_parser = __ms_element_create(plugin_name, NULL); MS_SAFE_FREE(format_prefix); MS_SAFE_FREE(plugin_name); gboolean gst_ret = FALSE; GstElement *encoder_bin = gst_bin_new("video_encoder"); GstElement *filter = __ms_element_create("capsfilter", NULL); - ms_retvm_if(!filter || !encoder_elem || !encoder_bin || !encoder_parser, (GstElement*)NULL, - "Error: creating elements for video encoder bin"); + ms_retvm_if(!filter || !encoder_elem || !encoder_bin || !encoder_parser, (GstElement *)NULL, + "Error: creating elements for video encoder bin"); format_prefix = g_strdup_printf("video/x-%s,stream-format=byte-stream,profile=high", - __ms_convert_mime_to_string(mime)); + __ms_convert_mime_to_string(mime)); GstCaps *videoCaps = gst_caps_from_string(format_prefix); g_object_set(G_OBJECT(filter), "caps", videoCaps, NULL); MS_SAFE_FREE(format_prefix); @@ -575,8 +511,7 @@ GstElement *__ms_video_encoder_element_create(dictionary *dict , media_format_mi gst_bin_add_many(GST_BIN(encoder_bin), encoder_elem, filter, encoder_parser, NULL); gst_ret = gst_element_link_many(encoder_elem, filter, encoder_parser, NULL); - if (gst_ret != TRUE) - { + if (gst_ret != TRUE) { ms_error("Failed to link elements into encoder_bin"); MS_SAFE_UNREF(encoder_bin); } @@ -596,16 +531,15 @@ GstElement *__ms_video_decoder_element_create(dictionary *dict , media_format_mi format_prefix = g_strdup_printf("%s:decoder", __ms_convert_mime_to_string(mime)); plugin_name = __ms_ini_get_string(dict, format_prefix, DEFAULT_VIDEO_DECODER); - GstElement *decoder_elem = __ms_element_create(plugin_name,NULL); + GstElement *decoder_elem = __ms_element_create(plugin_name, NULL); MS_SAFE_FREE(format_prefix); MS_SAFE_FREE(plugin_name); format_prefix = g_strdup_printf("%s:parser", __ms_convert_mime_to_string(mime)); plugin_name = __ms_ini_get_string(dict, format_prefix, DEFAULT_VIDEO_PARSER); - GstElement *decoder_parser = __ms_element_create(plugin_name,NULL); + GstElement *decoder_parser = __ms_element_create(plugin_name, NULL); - if(mime == MEDIA_FORMAT_H264_SP) - { + if (mime == MEDIA_FORMAT_H264_SP) { g_object_set(G_OBJECT(decoder_parser), "config-interval", 5, NULL); } @@ -615,30 +549,27 @@ GstElement *__ms_video_decoder_element_create(dictionary *dict , media_format_mi gboolean gst_ret = FALSE; GstElement *decoder_bin = gst_bin_new("video_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 video decoder bin"); + 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 video decoder bin"); 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) - { + if (gst_ret != TRUE) { ms_error("Failed to link elements into decoder_bin"); MS_SAFE_UNREF(decoder_bin); return NULL; } last_elem = decoder_elem; - if(!is_omx) - { - GstElement *video_conv = __ms_element_create("videoconvert",NULL); - GstElement *video_scale = __ms_element_create("videoscale",NULL); - ms_retvm_if(!video_conv || !video_scale, (GstElement*)NULL, - "Error: creating elements for video decoder bin"); + if (!is_omx) { + GstElement *video_conv = __ms_element_create("videoconvert", NULL); + GstElement *video_scale = __ms_element_create("videoscale", NULL); + ms_retvm_if(!video_conv || !video_scale, (GstElement *)NULL, + "Error: creating elements for video decoder bin"); gst_bin_add_many(GST_BIN(decoder_bin), video_conv, video_scale, NULL); gst_ret = gst_element_link_many(decoder_elem, video_conv, video_scale, NULL); - if (gst_ret != TRUE) - { + if (gst_ret != TRUE) { ms_error("Failed to link elements into decoder_bin"); MS_SAFE_UNREF(decoder_bin); return NULL; @@ -655,11 +586,11 @@ GstElement *__ms_video_decoder_element_create(dictionary *dict , media_format_mi GstElement *__ms_audio_encoder_element_create(void) { gboolean gst_ret = FALSE; - GstElement *audio_convert = __ms_element_create("audioconvert",NULL); - GstElement *audio_filter = __ms_element_create("capsfilter",NULL); + GstElement *audio_convert = __ms_element_create("audioconvert", NULL); + GstElement *audio_filter = __ms_element_create("capsfilter", NULL); GstElement *audio_enc_bin = gst_bin_new("audio_encoder"); - ms_retvm_if(!audio_convert || !audio_filter || !audio_enc_bin, (GstElement*)NULL, - "Error: creating elements for encoder bin"); + ms_retvm_if(!audio_convert || !audio_filter || !audio_enc_bin, (GstElement *)NULL, + "Error: creating elements for encoder bin"); GstCaps *audioCaps = gst_caps_from_string(MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT); g_object_set(G_OBJECT(audio_filter), "caps", audioCaps, NULL); @@ -667,8 +598,7 @@ GstElement *__ms_audio_encoder_element_create(void) gst_bin_add_many(GST_BIN(audio_enc_bin), audio_convert, audio_filter, NULL); gst_ret = gst_element_link_many(audio_filter, audio_convert, NULL); - if (gst_ret != TRUE) - { + if (gst_ret != TRUE) { ms_error("Failed to link elements into decoder_bin"); MS_SAFE_UNREF(audio_enc_bin); } @@ -681,21 +611,21 @@ GstElement *__ms_audio_encoder_element_create(void) GstElement *__ms_rtp_element_create(media_streamer_node_s *ms_node) { - ms_retvm_if(ms_node == NULL, (GstElement*)NULL, "Error empty rtp node Handle"); + ms_retvm_if(ms_node == NULL, (GstElement *)NULL, "Error empty rtp node Handle"); GstElement *rtp_container = gst_bin_new("rtp_container"); GstElement *rtp_elem = __ms_element_create("rtpbin", "rtpbin"); - ms_retvm_if(!rtp_container || !rtp_elem, (GstElement*)NULL, - "Error: creating elements for rtp container"); + ms_retvm_if(!rtp_container || !rtp_elem, (GstElement *)NULL, + "Error: creating elements for rtp container"); gst_bin_add(GST_BIN(rtp_container), rtp_elem); - g_signal_connect (rtp_elem, "pad-added", G_CALLBACK (__ms_rtpbin_pad_added_cb), ms_node); + g_signal_connect(rtp_elem, "pad-added", G_CALLBACK(__ms_rtpbin_pad_added_cb), ms_node); return rtp_container; } static gboolean __ms_get_rtp_elements(media_streamer_node_s *ms_node, - GstElement **rtp_elem, GstElement **rtcp_elem, const gchar *elem_name) + GstElement **rtp_elem, GstElement **rtcp_elem, const gchar *elem_name) { gboolean ret = FALSE; gchar *rtp_elem_name = NULL; @@ -706,16 +636,11 @@ static gboolean __ms_get_rtp_elements(media_streamer_node_s *ms_node, ms_retvm_if(!elem_name, FALSE, "Empty rtp element name."); - if(MS_ELEMENT_IS_SOURCE(elem_name)) - { + if (MS_ELEMENT_IS_SOURCE(elem_name)) { plugin_name = g_strdup("udpsrc"); - } - else if(MS_ELEMENT_IS_SINK(elem_name)) - { + } else if (MS_ELEMENT_IS_SINK(elem_name)) { plugin_name = g_strdup("udpsink"); - } - else - { + } else { ms_error("Error: invalid parameter name [%s]", elem_name); return FALSE; } @@ -723,19 +648,16 @@ static gboolean __ms_get_rtp_elements(media_streamer_node_s *ms_node, rtp_elem_name = g_strdup_printf("%s_rtp", elem_name); rtcp_elem_name = g_strdup_printf("%s_rtcp", elem_name); - // Find video udp rtp/rtcp element if it present. + /* Find video udp rtp/rtcp element if it present. */ *rtp_elem = gst_bin_get_by_name(GST_BIN(ms_node->gst_element), rtp_elem_name); *rtcp_elem = gst_bin_get_by_name(GST_BIN(ms_node->gst_element), rtcp_elem_name); - // Create new udp element if it did not found. - if((NULL == *rtp_elem) && (NULL == *rtcp_elem)) - { + /* Create new udp element if it did not found. */ + if ((NULL == *rtp_elem) && (NULL == *rtcp_elem)) { *rtp_elem = __ms_element_create(plugin_name, rtp_elem_name); *rtcp_elem = __ms_element_create(plugin_name, rtcp_elem_name); - } - else - { - //rtp/rtcp elements already into rtp bin. + } else { + /*rtp/rtcp elements already into rtp bin. */ MS_SAFE_GFREE(rtp_elem_name); MS_SAFE_GFREE(rtcp_elem_name); MS_SAFE_GFREE(plugin_name); @@ -743,44 +665,34 @@ static gboolean __ms_get_rtp_elements(media_streamer_node_s *ms_node, } gst_bin_add_many(GST_BIN(ms_node->gst_element), - *rtp_elem, *rtcp_elem, NULL); + *rtp_elem, *rtcp_elem, NULL); - if(MS_ELEMENT_IS_SINK(elem_name)) - { + if (MS_ELEMENT_IS_SINK(elem_name)) { g_object_set(GST_OBJECT(*rtcp_elem), "sync", FALSE, NULL); g_object_set(GST_OBJECT(*rtcp_elem), "async", FALSE, NULL); - if(MS_ELEMENT_IS_VIDEO(elem_name)) - { + if (MS_ELEMENT_IS_VIDEO(elem_name)) { __ms_add_ghostpad(rtpbin, "send_rtp_sink_0", ms_node->gst_element, "video_sink"); ret = gst_element_link_pads(rtpbin, "send_rtp_src_0", *rtp_elem, "sink") && - gst_element_link_pads(rtpbin, "send_rtcp_src_0",*rtcp_elem, "sink"); - } - else - { + gst_element_link_pads(rtpbin, "send_rtcp_src_0", *rtcp_elem, "sink"); + } else { __ms_add_ghostpad(rtpbin, "send_rtp_sink_1", ms_node->gst_element, "audio_sink"); ret = gst_element_link_pads(rtpbin, "send_rtp_src_1", *rtp_elem, "sink") && - gst_element_link_pads(rtpbin, "send_rtcp_src_1",*rtcp_elem, "sink"); + gst_element_link_pads(rtpbin, "send_rtcp_src_1", *rtcp_elem, "sink"); } - } - else - { - if(MS_ELEMENT_IS_VIDEO(elem_name)) - { + } else { + if (MS_ELEMENT_IS_VIDEO(elem_name)) { ret = gst_element_link_pads(*rtp_elem, "src", rtpbin, "recv_rtp_sink_0") && - gst_element_link_pads (*rtcp_elem, "src", rtpbin, "recv_rtcp_sink_0"); + gst_element_link_pads(*rtcp_elem, "src", rtpbin, "recv_rtcp_sink_0"); __ms_add_ghostpad(NULL, NULL, ms_node->gst_element, "video_source"); - } - else - { + } else { ret = gst_element_link_pads(*rtp_elem, "src", rtpbin, "recv_rtp_sink_1") && - gst_element_link_pads (*rtcp_elem, "src", rtpbin, "recv_rtcp_sink_1"); + gst_element_link_pads(*rtcp_elem, "src", rtpbin, "recv_rtcp_sink_1"); __ms_add_ghostpad(NULL, NULL, ms_node->gst_element, "audio_source"); } } - if(!ret) - { + if (!ret) { ms_error("Can not link [rtpbin] pad to [%s] pad, ret code [%d] ", rtp_elem, ret); ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -794,9 +706,9 @@ static gboolean __ms_get_rtp_elements(media_streamer_node_s *ms_node, } int __ms_rtp_set_param( - media_streamer_node_s *ms_node, - const gchar *param_key, - const gchar *param_value) + media_streamer_node_s *ms_node, + const gchar *param_key, + const gchar *param_value) { ms_retvm_if(!ms_node && !ms_node->gst_element, MEDIA_STREAMER_ERROR_NONE, "Error: empty node"); @@ -806,37 +718,30 @@ int __ms_rtp_set_param( GstElement *rtp_elem = NULL; GstElement *rtcp_elem = NULL; - tokens = g_strsplit(param_key,",",3); + tokens = g_strsplit(param_key, ",", 3); ms_retvm_if(tokens == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Invalid rtp parameter line."); elem_name = tokens[0]; - if(FALSE == __ms_get_rtp_elements(ms_node, &rtp_elem, &rtcp_elem, elem_name)) - { + if (FALSE == __ms_get_rtp_elements(ms_node, &rtp_elem, &rtcp_elem, elem_name)) { ms_error("Error: invalid parameter [%s]", param_key); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } - for(i = 1; (tokens && tokens[i]); i++) - { + for (i = 1; (tokens && tokens[i]); i++) { ms_retvm_if(!rtp_elem || !rtcp_elem, - MEDIA_STREAMER_ERROR_INVALID_OPERATION, - "Error: [%s] did not found or created into streamer", tokens[i]); + MEDIA_STREAMER_ERROR_INVALID_OPERATION, + "Error: [%s] did not found or created into streamer", tokens[i]); - if(!g_strcmp0(tokens[i], "port")) - { + if (!g_strcmp0(tokens[i], "port")) { __ms_element_set_property(rtp_elem, tokens[i], param_value); gchar *next_port = g_strdup(param_value); - next_port[strlen(next_port)-1] += 1; + next_port[strlen(next_port) - 1] += 1; __ms_element_set_property(rtcp_elem, tokens[i], next_port); MS_SAFE_GFREE(next_port); - } - else if(!g_strcmp0(tokens[i], "host") && MS_ELEMENT_IS_SINK(elem_name)) - { + } else if (!g_strcmp0(tokens[i], "host") && MS_ELEMENT_IS_SINK(elem_name)) { __ms_element_set_property(rtp_elem, tokens[i], param_value); __ms_element_set_property(rtcp_elem, tokens[i], param_value); - } - else if(!g_strcmp0(tokens[i], "format") && MS_ELEMENT_IS_SOURCE(elem_name)) - { + } else if (!g_strcmp0(tokens[i], "format") && MS_ELEMENT_IS_SOURCE(elem_name)) { __ms_element_set_property(rtp_elem, "caps", param_value); } @@ -846,79 +751,74 @@ int __ms_rtp_set_param( return MEDIA_STREAMER_ERROR_NONE; } -int __ms_add_node_into_bin(media_streamer_s *ms_streamer,media_streamer_node_s *ms_node) +int __ms_add_node_into_bin(media_streamer_s *ms_streamer, media_streamer_node_s *ms_node) { int ret = MEDIA_STREAMER_ERROR_NONE; ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Handle is NULL"); ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Handle is NULL"); ms_info("Try to add [%s] node into streamer, node type/subtype [%d/%d]", - ms_node->name, ms_node->type, ms_node->subtype); + ms_node->name, ms_node->type, ms_node->subtype); gchar *bin_name = NULL; gboolean gst_ret = FALSE; - switch(ms_node->type) - { + switch (ms_node->type) { case MEDIA_STREAMER_NODE_TYPE_SRC: - gst_ret = gst_bin_add(GST_BIN(ms_streamer->src_bin),ms_node->gst_element); + gst_ret = gst_bin_add(GST_BIN(ms_streamer->src_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_SRC_BIN_NAME); break; case MEDIA_STREAMER_NODE_TYPE_SINK: - switch(ms_node->subtype) - { + switch (ms_node->subtype) { case MEDIA_STREAMER_SINK_TYPE_SCREEN: - gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin),ms_node->gst_element); + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); break; case MEDIA_STREAMER_SINK_TYPE_AUDIO: - gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin),ms_node->gst_element); + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_AUDIO_SINK_BIN_NAME); break; default: - gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin),ms_node->gst_element); + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); break; } break; case MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER: - gst_ret = gst_bin_add(GST_BIN(ms_streamer->topology_bin),ms_node->gst_element); + gst_ret = gst_bin_add(GST_BIN(ms_streamer->topology_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_TOPOLOGY_BIN_NAME); break; case MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER: - gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin),ms_node->gst_element); + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); break; case MEDIA_STREAMER_NODE_TYPE_VIDEO_DEPAY: - gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin),ms_node->gst_element); + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); break; case MEDIA_STREAMER_NODE_TYPE_AUDIO_DEPAY: - gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin),ms_node->gst_element); + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_AUDIO_SINK_BIN_NAME); break; case MEDIA_STREAMER_NODE_TYPE_AUDIO_RESAMPLE: - gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin),ms_node->gst_element); + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_AUDIO_SINK_BIN_NAME); break; case MEDIA_STREAMER_NODE_TYPE_AUDIO_CONVERTER: - gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin),ms_node->gst_element); + gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_AUDIO_SINK_BIN_NAME); break; default: - // Another elements will be add into topology bin - gst_ret = gst_bin_add(GST_BIN(ms_streamer->topology_bin),ms_node->gst_element); + /* Another elements will be add into topology bin */ + gst_ret = gst_bin_add(GST_BIN(ms_streamer->topology_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_TOPOLOGY_BIN_NAME); break; } - if(!gst_ret) - { + if (!gst_ret) { ms_error("Failed to add Element [%s] into [%s] bin.", ms_node->name, bin_name); ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; - } - else - { + } else { ms_info("Success added Element [%s] into [%s] bin.", ms_node->name, bin_name); ret = MEDIA_STREAMER_ERROR_NONE; } @@ -932,88 +832,77 @@ int __ms_add_node_into_bin(media_streamer_s *ms_streamer,media_streamer_node_s * static gboolean __ms_bus_cb(GstBus *bus, GstMessage *message, gpointer userdata) { int ret = MEDIA_STREAMER_ERROR_NONE; - media_streamer_s *ms_streamer = (media_streamer_s*)userdata; + media_streamer_s *ms_streamer = (media_streamer_s *)userdata; ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_retvm_if(ms_streamer->pipeline == NULL, MEDIA_STREAMER_ERROR_INVALID_STATE, "Pipeline doesn`t exist"); /* Parse message */ - if (message != NULL) - { - switch (GST_MESSAGE_TYPE(message)) - { - case GST_MESSAGE_ERROR: - { - GError *err; - gchar *debug; - gst_message_parse_error (message, &err, &debug); - - ms_error("[Source: %s] Error: %s", GST_OBJECT_NAME(GST_OBJECT_CAST(GST_ELEMENT(GST_MESSAGE_SRC (message)))), err->message); - - MS_SAFE_FREE(err); - MS_SAFE_FREE(debug); - break; - } + if (message != NULL) { + switch (GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_ERROR: { + GError *err; + gchar *debug; + gst_message_parse_error(message, &err, &debug); + + ms_error("[Source: %s] Error: %s", GST_OBJECT_NAME(GST_OBJECT_CAST(GST_ELEMENT(GST_MESSAGE_SRC(message)))), err->message); - case GST_MESSAGE_STATE_CHANGED: - { - if (GST_MESSAGE_SRC (message) == GST_OBJECT (ms_streamer->pipeline)) - { - GstState state_old, state_new, state_pending; - gchar *state_transition_name; - - gst_message_parse_state_changed (message, &state_old, &state_new, &state_pending); - ms_info ("GST_MESSAGE_STATE_CHANGED: [%s] %s -> %s\n", - gst_object_get_name(GST_MESSAGE_SRC(message)), - _ms_state_to_string(state_old), - _ms_state_to_string(state_new)); - - state_transition_name = g_strdup_printf ("%s_%s", - gst_element_state_get_name (state_old), - gst_element_state_get_name (state_new)); - - __ms_generate_dots(ms_streamer->pipeline, state_transition_name); - - MS_SAFE_GFREE (state_transition_name); - - if (state_old == GST_STATE_NULL && state_new == GST_STATE_READY) - { - ms_info("[Success] GST_STATE_NULL => GST_STATE_READY"); - - /* Pause Media_Streamer */ - ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PAUSED); - if(ret != MEDIA_STREAMER_ERROR_NONE) - { - ms_error("ERROR - Pause pipeline"); - return FALSE; + MS_SAFE_FREE(err); + MS_SAFE_FREE(debug); + break; + } + + case GST_MESSAGE_STATE_CHANGED: { + if (GST_MESSAGE_SRC(message) == GST_OBJECT(ms_streamer->pipeline)) { + GstState state_old, state_new, state_pending; + gchar *state_transition_name; + + gst_message_parse_state_changed(message, &state_old, &state_new, &state_pending); + ms_info("GST_MESSAGE_STATE_CHANGED: [%s] %s -> %s\n", + gst_object_get_name(GST_MESSAGE_SRC(message)), + _ms_state_to_string(state_old), + _ms_state_to_string(state_new)); + + state_transition_name = g_strdup_printf("%s_%s", + gst_element_state_get_name(state_old), + gst_element_state_get_name(state_new)); + + __ms_generate_dots(ms_streamer->pipeline, state_transition_name); + + MS_SAFE_GFREE(state_transition_name); + + if (state_old == GST_STATE_NULL && state_new == GST_STATE_READY) { + ms_info("[Success] GST_STATE_NULL => GST_STATE_READY"); + + /* Pause Media_Streamer */ + ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PAUSED); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("ERROR - Pause pipeline"); + return FALSE; + } } - } - if (state_old == GST_STATE_READY && state_new == GST_STATE_PAUSED) - { - ms_info("[Success] GST_STATE_READY => GST_STATE_PAUSED"); + if (state_old == GST_STATE_READY && state_new == GST_STATE_PAUSED) { + ms_info("[Success] GST_STATE_READY => GST_STATE_PAUSED"); - ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PLAYING); - if(ret != MEDIA_STREAMER_ERROR_NONE) - { - ms_error("ERROR - Play Pipeline"); - return FALSE; + ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PLAYING); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("ERROR - Play Pipeline"); + return FALSE; + } } } + break; } - break; - } - case GST_MESSAGE_EOS: - { - ms_info("GST_MESSAGE_EOS end-of-stream"); - ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PAUSED); - if(ret != MEDIA_STREAMER_ERROR_NONE) - { - ms_error("ERROR - Pause Pipeline"); - return FALSE; + case GST_MESSAGE_EOS: { + ms_info("GST_MESSAGE_EOS end-of-stream"); + ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PAUSED); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("ERROR - Pause Pipeline"); + return FALSE; + } + break; } - break; - } default: break; } @@ -1029,36 +918,36 @@ int __ms_pipeline_create(media_streamer_s *ms_streamer) ms_streamer->pipeline = gst_pipeline_new(MEDIA_STREAMER_PIPELINE_NAME); ms_retvm_if(ms_streamer->pipeline == NULL, - MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error creating pipeline"); + MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating pipeline"); ms_streamer->bus = gst_pipeline_get_bus(GST_PIPELINE(ms_streamer->pipeline)); ms_retvm_if(ms_streamer->bus == NULL, - MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error getting the bus of the pipeline"); + MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error getting the bus of the pipeline"); - ms_streamer->bus_watcher = gst_bus_add_watch (ms_streamer->bus, (GstBusFunc)__ms_bus_cb, ms_streamer); + ms_streamer->bus_watcher = gst_bus_add_watch(ms_streamer->bus, (GstBusFunc)__ms_bus_cb, ms_streamer); ms_streamer->src_bin = gst_bin_new(MEDIA_STREAMER_SRC_BIN_NAME); ms_retvm_if(ms_streamer->src_bin == NULL, - MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error creating Src bin"); + MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating Src bin"); -// g_signal_connect(ms_streamer->src_bin, "element-added", G_CALLBACK(__src_bin_element_added_cb), ms_streamer); + /* g_signal_connect(ms_streamer->src_bin, "element-added", G_CALLBACK(__src_bin_element_added_cb), ms_streamer); */ ms_streamer->sink_video_bin = gst_bin_new(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); ms_retvm_if(ms_streamer->sink_video_bin == NULL, - MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error creating Sink bin"); -// g_signal_connect(ms_streamer->sink_bin, "element-added", G_CALLBACK(__sink_bin_element_added_cb), ms_streamer); + MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating Sink bin"); + /* g_signal_connect(ms_streamer->sink_bin, "element-added", G_CALLBACK(__sink_bin_element_added_cb), ms_streamer); */ ms_streamer->sink_audio_bin = gst_bin_new(MEDIA_STREAMER_AUDIO_SINK_BIN_NAME); ms_retvm_if(ms_streamer->sink_audio_bin == NULL, - MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error creating Audio Sink bin"); + MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating Audio Sink bin"); ms_streamer->topology_bin = gst_bin_new(MEDIA_STREAMER_TOPOLOGY_BIN_NAME); ms_retvm_if(ms_streamer->topology_bin == NULL, - MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error creating Topology bin"); -// g_signal_connect(ms_streamer->topology_bin, "element-added", G_CALLBACK(__bin_element_added_cb), ms_streamer); + MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating Topology bin"); + /* g_signal_connect(ms_streamer->topology_bin, "element-added", G_CALLBACK(__bin_element_added_cb), ms_streamer); */ gst_bin_add_many(GST_BIN(ms_streamer->pipeline), ms_streamer->src_bin, - ms_streamer->topology_bin, NULL); + ms_streamer->topology_bin, NULL); return MEDIA_STREAMER_ERROR_NONE; } @@ -1076,52 +965,41 @@ static GstCaps *__ms_create_caps_from_fmt(media_format_h fmt) int samplerate; int bit; - if (media_format_get_video_info(fmt, &mime, &width, &height, &avg_bps, &max_bps) == MEDIA_PACKET_ERROR_NONE) - { + if (media_format_get_video_info(fmt, &mime, &width, &height, &avg_bps, &max_bps) == MEDIA_PACKET_ERROR_NONE) { ms_info("Creating video Caps from media format [width=%d, height=%d, bps=%d, mime=%d]", - width, height, avg_bps, mime); + width, height, avg_bps, mime); - if (mime & MEDIA_FORMAT_RAW) - { + if (mime & MEDIA_FORMAT_RAW) { format_name = g_strdup(__ms_convert_mime_to_string(mime)); caps = gst_caps_new_simple("video/x-raw", -// "framerate", GST_TYPE_FRACTION, max_bps, avg_bps, - "format", G_TYPE_STRING, format_name, - "width", G_TYPE_INT, width, - "height", G_TYPE_INT, height, NULL); - } - else - { - //mime & MEDIA_FORMAT_ENCODED + /*"framerate", GST_TYPE_FRACTION, max_bps, avg_bps, */ + "format", G_TYPE_STRING, format_name, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, NULL); + } else { + /*mime & MEDIA_FORMAT_ENCODED */ format_name = g_strdup_printf("video/x-%s", __ms_convert_mime_to_string(mime)); caps = gst_caps_new_simple(format_name, - "framerate", GST_TYPE_FRACTION, max_bps, avg_bps, - "width", G_TYPE_INT, width, - "height", G_TYPE_INT, height, NULL); + "framerate", GST_TYPE_FRACTION, max_bps, avg_bps, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, NULL); } - } - else if (media_format_get_audio_info(fmt, &mime, &channel, &samplerate, &bit, &avg_bps) == MEDIA_PACKET_ERROR_NONE) - { + } else if (media_format_get_audio_info(fmt, &mime, &channel, &samplerate, &bit, &avg_bps) == MEDIA_PACKET_ERROR_NONE) { ms_info("Creating audio Caps from media format [channel=%d, samplerate=%d, bit=%d, avg_bps=%d, mime=%d]", - channel, samplerate, bit, avg_bps, mime); + channel, samplerate, bit, avg_bps, mime); - if (mime & MEDIA_FORMAT_RAW) - { + if (mime & MEDIA_FORMAT_RAW) { format_name = g_strdup(__ms_convert_mime_to_string(mime)); caps = gst_caps_new_simple("audio/x-raw", - "channels", G_TYPE_INT, channel, - "format", G_TYPE_STRING, format_name, - "rate", G_TYPE_INT, samplerate, NULL); - } - else - { + "channels", G_TYPE_INT, channel, + "format", G_TYPE_STRING, format_name, + "rate", G_TYPE_INT, samplerate, NULL); + } else { ms_error("Encoded audio formats does not supported yet."); } - } - else - { + } else { ms_error("Failed getting media info from fmt."); } MS_SAFE_GFREE(format_name); diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 5fb4413..7077070 100755 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -19,8 +19,8 @@ #include int __ms_node_create(media_streamer_node_s *node, - media_format_h in_fmt, - media_format_h out_fmt) + media_format_h in_fmt, + media_format_h out_fmt) { ms_retvm_if(node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); @@ -28,32 +28,30 @@ int __ms_node_create(media_streamer_node_s *node, char *plugin_name = NULL; media_format_mimetype_e mime; - if (MEDIA_FORMAT_ERROR_NONE != media_format_get_video_info(out_fmt, &mime, NULL, NULL, NULL, NULL)) - { + if (MEDIA_FORMAT_ERROR_NONE != media_format_get_video_info(out_fmt, &mime, NULL, NULL, NULL, NULL)) { media_format_get_audio_info(out_fmt, &mime, NULL, NULL, NULL, NULL); } - char* format_prefix = NULL; + char *format_prefix = NULL; __ms_load_ini_dictionary(&dict); - switch(node->type) - { + switch (node->type) { case MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER: format_prefix = g_strdup_printf("%s:encoder", __ms_convert_mime_to_string(mime)); plugin_name = __ms_ini_get_string(dict, - format_prefix, DEFAULT_VIDEO_ENCODER); + format_prefix, DEFAULT_VIDEO_ENCODER); node->gst_element = __ms_video_encoder_element_create(dict, mime); break; case MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER: format_prefix = g_strdup_printf("%s:decoder", __ms_convert_mime_to_string(mime)); plugin_name = __ms_ini_get_string(dict, - format_prefix, DEFAULT_VIDEO_DECODER); + format_prefix, DEFAULT_VIDEO_DECODER); node->gst_element = __ms_video_decoder_element_create(dict, mime); break; case MEDIA_STREAMER_NODE_TYPE_PARSER: format_prefix = g_strdup_printf("%s:parser", __ms_convert_mime_to_string(mime)); plugin_name = __ms_ini_get_string(dict, - format_prefix, DEFAULT_VIDEO_PARSER); + format_prefix, DEFAULT_VIDEO_PARSER); node->gst_element = __ms_element_create(plugin_name, NULL); break; case MEDIA_STREAMER_NODE_TYPE_FILTER: @@ -62,23 +60,23 @@ int __ms_node_create(media_streamer_node_s *node, case MEDIA_STREAMER_NODE_TYPE_VIDEO_PAY: format_prefix = g_strdup_printf("%s:rtppay", __ms_convert_mime_to_string(mime)); plugin_name = __ms_ini_get_string(dict, - format_prefix, DEFAULT_VIDEO_RTPPAY); + format_prefix, DEFAULT_VIDEO_RTPPAY); node->gst_element = __ms_element_create(plugin_name, NULL); break; case MEDIA_STREAMER_NODE_TYPE_AUDIO_PAY: plugin_name = __ms_ini_get_string(dict, - "audio-raw:rtppay", DEFAULT_AUDIO_RTPPAY); + "audio-raw:rtppay", DEFAULT_AUDIO_RTPPAY); node->gst_element = __ms_element_create(plugin_name, NULL); break; case MEDIA_STREAMER_NODE_TYPE_VIDEO_DEPAY: format_prefix = g_strdup_printf("%s:rtpdepay", __ms_convert_mime_to_string(mime)); plugin_name = __ms_ini_get_string(dict, - format_prefix, DEFAULT_VIDEO_RTPDEPAY); + format_prefix, DEFAULT_VIDEO_RTPDEPAY); node->gst_element = __ms_element_create(plugin_name, NULL); break; case MEDIA_STREAMER_NODE_TYPE_AUDIO_DEPAY: plugin_name = __ms_ini_get_string(dict, - "audio-raw:rtpdepay", DEFAULT_AUDIO_RTPPAY); + "audio-raw:rtpdepay", DEFAULT_AUDIO_RTPPAY); node->gst_element = __ms_element_create(plugin_name, NULL); break; case MEDIA_STREAMER_NODE_TYPE_RTP: @@ -101,7 +99,7 @@ int __ms_node_create(media_streamer_node_s *node, node->gst_element = __ms_element_create("audioresample", NULL); break; default: - ms_error( "Error: invalid node Type [%d]",node->type); + ms_error("Error: invalid node Type [%d]", node->type); break; } @@ -126,8 +124,7 @@ int __ms_src_node_create(media_streamer_node_s *node) __ms_load_ini_dictionary(&dict); - switch(node->subtype) - { + switch (node->subtype) { case MEDIA_STREAMER_SRC_TYPE_FILE: ms_error("Error: not implemented yet"); break; @@ -139,23 +136,23 @@ int __ms_src_node_create(media_streamer_node_s *node) break; case MEDIA_STREAMER_SRC_TYPE_CAMERA: plugin_name = __ms_ini_get_string(dict, - "sources:camera_source",DEFAULT_CAMERA_SOURCE); + "sources:camera_source", DEFAULT_CAMERA_SOURCE); node->gst_element = __ms_camera_element_create(plugin_name); break; case MEDIA_STREAMER_SRC_TYPE_AUDIO_CAPTURE: plugin_name = __ms_ini_get_string(dict, - "sources:audio_source",DEFAULT_AUDIO_SOURCE); + "sources:audio_source", DEFAULT_AUDIO_SOURCE); node->gst_element = __ms_element_create(plugin_name, NULL); break; case MEDIA_STREAMER_SRC_TYPE_VIDEO_CAPTURE: plugin_name = __ms_ini_get_string(dict, - "sources:video_source",DEFAULT_VIDEO_SOURCE); + "sources:video_source", DEFAULT_VIDEO_SOURCE); node->gst_element = __ms_element_create(plugin_name, NULL); break; case MEDIA_STREAMER_SRC_TYPE_VIDEO_TEST: node->gst_element = __ms_element_create(DEFAULT_VIDEO_TEST_SOURCE, NULL); - g_object_set (G_OBJECT (node->gst_element), "is-live", true, NULL); + g_object_set(G_OBJECT(node->gst_element), "is-live", true, NULL); break; case MEDIA_STREAMER_SRC_TYPE_AUDIO_TEST: node->gst_element = __ms_element_create(DEFAULT_AUDIO_TEST_SOURCE, NULL); @@ -164,7 +161,7 @@ int __ms_src_node_create(media_streamer_node_s *node) ms_error("Error: not implemented yet"); break; default: - ms_error( "Error: invalid Src node Type [%d]",node->subtype); + ms_error("Error: invalid Src node Type [%d]", node->subtype); break; } @@ -186,8 +183,7 @@ int __ms_sink_node_create(media_streamer_node_s *node) __ms_load_ini_dictionary(&dict); - switch(node->subtype) - { + switch (node->subtype) { case MEDIA_STREAMER_SINK_TYPE_FILE: ms_error("Error: not implemented yet"); break; @@ -199,12 +195,12 @@ int __ms_sink_node_create(media_streamer_node_s *node) break; case MEDIA_STREAMER_SINK_TYPE_AUDIO: plugin_name = __ms_ini_get_string(dict, - "sinks:audio_sink",DEFAULT_AUDIO_SINK); + "sinks:audio_sink", DEFAULT_AUDIO_SINK); node->gst_element = __ms_element_create(plugin_name, NULL); break; case MEDIA_STREAMER_SINK_TYPE_SCREEN: plugin_name = __ms_ini_get_string(dict, - "sinks:video_sink",DEFAULT_VIDEO_SINK); + "sinks:video_sink", DEFAULT_VIDEO_SINK); node->gst_element = __ms_element_create(plugin_name, NULL); break; case MEDIA_STREAMER_SINK_TYPE_FAKE: @@ -214,7 +210,7 @@ int __ms_sink_node_create(media_streamer_node_s *node) break; default: - ms_error( "Error: invalid Sink node Type [%d]",node->subtype); + ms_error("Error: invalid Sink node Type [%d]", node->subtype); break; } @@ -230,7 +226,7 @@ int __ms_sink_node_create(media_streamer_node_s *node) void __ms_node_destroy(void *data) { char *node_name = NULL; - media_streamer_node_s *node = (media_streamer_node_s*)data; + media_streamer_node_s *node = (media_streamer_node_s *)data; ms_retm_if(node == NULL, "Empty value while deleting element from table"); node_name = g_strdup(node->name); @@ -242,38 +238,37 @@ void __ms_node_destroy(void *data) } void __ms_node_insert_into_table(GHashTable *nodes_table, - media_streamer_node_s *ms_node) + media_streamer_node_s *ms_node) { - if(g_hash_table_contains(nodes_table,ms_node->name)) - { - ms_debug( "Current Node [%s] already added", ms_node->name); + if (g_hash_table_contains(nodes_table, ms_node->name)) { + ms_debug("Current Node [%s] already added", ms_node->name); return; } - g_hash_table_insert(nodes_table,(gpointer)ms_node->name,(gpointer)ms_node); + g_hash_table_insert(nodes_table, (gpointer)ms_node->name, (gpointer)ms_node); ms_info("Node [%s] added into streamer, node type/subtype [%d/%d]", - ms_node->name, ms_node->type, ms_node->subtype); + ms_node->name, ms_node->type, ms_node->subtype); } int __ms_node_remove_from_table(GHashTable *nodes_table, - media_streamer_node_s *ms_node) + media_streamer_node_s *ms_node) { ms_retvm_if(nodes_table == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Handle is NULL"); ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Handle is NULL"); gboolean g_ret = g_hash_table_remove(nodes_table, ms_node->name); ms_retvm_if(g_ret != TRUE, MEDIA_STREAMER_ERROR_INVALID_OPERATION, - "Error while removing element from table"); + "Error while removing element from table"); return MEDIA_STREAMER_ERROR_NONE; } static void __params_foreach_cb(const char *key, - const int type, - const bundle_keyval_t *kv, - void *user_data) + const int type, + const bundle_keyval_t *kv, + void *user_data) { int ret = MEDIA_STREAMER_ERROR_NONE; - media_streamer_node_s *ms_node = (media_streamer_node_s*)user_data; + media_streamer_node_s *ms_node = (media_streamer_node_s *)user_data; ms_retm_if(ms_node == NULL, "Handle is NULL"); void *basic_val = NULL; @@ -281,76 +276,64 @@ static void __params_foreach_cb(const char *key, ms_info("Try to add parameter [%s] with type [%d] to the node [%s].", key, type, ms_node->name); - if(!bundle_keyval_type_is_array((bundle_keyval_t *)kv)) - { + if (!bundle_keyval_type_is_array((bundle_keyval_t *)kv)) { bundle_keyval_get_basic_val((bundle_keyval_t *)kv, &basic_val, &basic_size); - ms_info("Read param value[%s] with size [%d].", (gchar*)basic_val, basic_size); + ms_info("Read param value[%s] with size [%d].", (gchar *)basic_val, basic_size); - if(ms_node->set_param != NULL) - { - ret = ms_node->set_param(ms_node, (gchar*)key, (gchar*)basic_val); - } - else - { + if (ms_node->set_param != NULL) { + ret = ms_node->set_param(ms_node, (gchar *)key, (gchar *)basic_val); + } else { ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; } - } - else - { + } else { ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; } ms_retm_if(ret != MEDIA_STREAMER_ERROR_NONE, - "Error while adding param [%s,%s] to the node [%s]", - key, type, ms_node->name); + "Error while adding param [%s,%s] to the node [%s]", + key, type, ms_node->name); } -int __ms_node_read_params_from_bundle (media_streamer_node_s *node, - bundle *param_list) +int __ms_node_read_params_from_bundle(media_streamer_node_s *node, + bundle *param_list) { int ret = MEDIA_STREAMER_ERROR_NONE; - bundle_foreach(param_list, __params_foreach_cb, (void*)node); + bundle_foreach(param_list, __params_foreach_cb, (void *)node); return ret; } -int __ms_node_write_params_into_bundle (media_streamer_node_s *node, - bundle *param_list) +int __ms_node_write_params_into_bundle(media_streamer_node_s *node, + bundle *param_list) { GParamSpec **property_specs; guint num_properties, i; char *string_val = NULL; property_specs = g_object_class_list_properties - (G_OBJECT_GET_CLASS(node->gst_element), &num_properties); + (G_OBJECT_GET_CLASS(node->gst_element), &num_properties); - if (num_properties <= 0) - { + if (num_properties <= 0) { return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } - ms_info("Getting parameter of the Node [%s]", node->name ); + ms_info("Getting parameter of the Node [%s]", node->name); - for (i = 0; i < num_properties; i++) - { + for (i = 0; i < num_properties; i++) { GValue value = { 0, }; GParamSpec *param = property_specs[i]; g_value_init(&value, param->value_type); - if (param->flags & G_PARAM_READWRITE) - { + if (param->flags & G_PARAM_READWRITE) { g_object_get_property(G_OBJECT(node->gst_element), param->name, &value); - } - else - { - // Skip properties which user can not change. + } else { + /* Skip properties which user can not change. */ continue; } ms_info("%-20s: %s\n", g_param_spec_get_name(param), g_param_spec_get_blurb(param)); - switch(G_VALUE_TYPE(&value)) - { + switch (G_VALUE_TYPE(&value)) { case G_TYPE_STRING: bundle_add_str(param_list, g_param_spec_get_name(param), g_value_get_string(&value)); ms_info("Got string value: [%s]", g_value_get_string(&value)); @@ -362,85 +345,77 @@ int __ms_node_write_params_into_bundle (media_streamer_node_s *node, ms_info("Got boolean value: [%s]", string_val); break; - case G_TYPE_ULONG: - { - GParamSpecULong *pulong = G_PARAM_SPEC_ULONG(param); - string_val = g_strdup_printf("%lu", g_value_get_ulong(&value)); - bundle_add_str(param_list, g_param_spec_get_name(param), string_val); - ms_info("Got ulong value: [%s], range: %lu - %lu (default %s)", - string_val, pulong->minimum, pulong->maximum); - break; - } - - case G_TYPE_LONG: - { - GParamSpecLong *plong = G_PARAM_SPEC_LONG(param); - string_val = g_strdup_printf("%ld", g_value_get_long(&value)); - bundle_add_str(param_list, g_param_spec_get_name(param), string_val); - ms_info("Got long value: [%s], range: %ld - %ld (default %s)", - string_val, plong->minimum, plong->maximum); - break; - } - - case G_TYPE_UINT: - { - GParamSpecUInt *puint = G_PARAM_SPEC_UINT(param); - string_val = g_strdup_printf("%u", g_value_get_uint(&value)); - bundle_add_str(param_list, g_param_spec_get_name(param), string_val); - ms_info("Got uint value: [%s], range: %u - %u", - string_val, puint->minimum, puint->maximum); - break; - } - - case G_TYPE_INT: - { - GParamSpecInt *pint = G_PARAM_SPEC_INT(param); - string_val = g_strdup_printf("%d", g_value_get_int(&value)); - bundle_add_str(param_list, g_param_spec_get_name(param), string_val); - ms_info("Got int value: [%s], range: %d - %d", - string_val, pint->minimum, pint->maximum); - break; - } - - case G_TYPE_UINT64: - { - GParamSpecUInt64 *puint64 = G_PARAM_SPEC_UINT64(param); - string_val = g_strdup_printf("%" G_GUINT64_FORMAT, g_value_get_uint64(&value)); - bundle_add_str(param_list, g_param_spec_get_name(param), string_val); - ms_info("Got uint64 value: [%s], range: %" G_GUINT64_FORMAT "- %" G_GUINT64_FORMAT, - string_val, puint64->minimum, puint64->maximum); - break; - } - - case G_TYPE_INT64: - { - GParamSpecInt64 *pint64 = G_PARAM_SPEC_INT64(param); - string_val = g_strdup_printf("%" G_GINT64_FORMAT, g_value_get_int64(&value)); - bundle_add_str(param_list, g_param_spec_get_name(param), string_val); - ms_info("Got uint64 value: [%s], range: %" G_GINT64_FORMAT "- %" G_GINT64_FORMAT, - string_val, pint64->minimum, pint64->maximum); - break; - } - - case G_TYPE_FLOAT: - { - GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT(param); - string_val = g_strdup_printf("%15.7g", g_value_get_float(&value)); - bundle_add_str(param_list, g_param_spec_get_name(param), string_val); - ms_info("Got float value: [%s], range:%15.7g -%15.7g", - string_val, pfloat->minimum, pfloat->maximum); - break; - } - - case G_TYPE_DOUBLE: - { - GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE(param); - string_val = g_strdup_printf("%15.7g", g_value_get_double(&value)); - bundle_add_str(param_list, g_param_spec_get_name(param), string_val); - ms_info("Got double value: [%s], range:%15.7g -%15.7g", - string_val, pdouble->minimum, pdouble->maximum); - break; - } + case G_TYPE_ULONG: { + GParamSpecULong *pulong = G_PARAM_SPEC_ULONG(param); + string_val = g_strdup_printf("%lu", g_value_get_ulong(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got ulong value: [%s], range: %lu - %lu (default %s)", + string_val, pulong->minimum, pulong->maximum); + break; + } + + case G_TYPE_LONG: { + GParamSpecLong *plong = G_PARAM_SPEC_LONG(param); + string_val = g_strdup_printf("%ld", g_value_get_long(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got long value: [%s], range: %ld - %ld (default %s)", + string_val, plong->minimum, plong->maximum); + break; + } + + case G_TYPE_UINT: { + GParamSpecUInt *puint = G_PARAM_SPEC_UINT(param); + string_val = g_strdup_printf("%u", g_value_get_uint(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got uint value: [%s], range: %u - %u", + string_val, puint->minimum, puint->maximum); + break; + } + + case G_TYPE_INT: { + GParamSpecInt *pint = G_PARAM_SPEC_INT(param); + string_val = g_strdup_printf("%d", g_value_get_int(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got int value: [%s], range: %d - %d", + string_val, pint->minimum, pint->maximum); + break; + } + + case G_TYPE_UINT64: { + GParamSpecUInt64 *puint64 = G_PARAM_SPEC_UINT64(param); + string_val = g_strdup_printf("%" G_GUINT64_FORMAT, g_value_get_uint64(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got uint64 value: [%s], range: %" G_GUINT64_FORMAT "- %" G_GUINT64_FORMAT, + string_val, puint64->minimum, puint64->maximum); + break; + } + + case G_TYPE_INT64: { + GParamSpecInt64 *pint64 = G_PARAM_SPEC_INT64(param); + string_val = g_strdup_printf("%" G_GINT64_FORMAT, g_value_get_int64(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got uint64 value: [%s], range: %" G_GINT64_FORMAT "- %" G_GINT64_FORMAT, + string_val, pint64->minimum, pint64->maximum); + break; + } + + case G_TYPE_FLOAT: { + GParamSpecFloat *pfloat = G_PARAM_SPEC_FLOAT(param); + string_val = g_strdup_printf("%15.7g", g_value_get_float(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got float value: [%s], range:%15.7g -%15.7g", + string_val, pfloat->minimum, pfloat->maximum); + break; + } + + case G_TYPE_DOUBLE: { + GParamSpecDouble *pdouble = G_PARAM_SPEC_DOUBLE(param); + string_val = g_strdup_printf("%15.7g", g_value_get_double(&value)); + bundle_add_str(param_list, g_param_spec_get_name(param), string_val); + ms_info("Got double value: [%s], range:%15.7g -%15.7g", + string_val, pdouble->minimum, pdouble->maximum); + break; + } default: ms_info("Got unknown type with param->value_type [%d]", param->value_type); diff --git a/src/media_streamer_priv.c b/src/media_streamer_priv.c index 7e9b540..9c6f051 100755 --- a/src/media_streamer_priv.c +++ b/src/media_streamer_priv.c @@ -25,18 +25,16 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); - media_streamer_state_e previous_state= ms_streamer->state; + media_streamer_state_e previous_state = ms_streamer->state; ms_retvm_if(previous_state == state, MEDIA_STREAMER_ERROR_NONE, "Media streamer already in this state"); - switch(state) - { + switch (state) { case MEDIA_STREAMER_STATE_NONE: /* * Media streamer must be in IDLE state * Unlink and destroy all bins and elements. */ - if (previous_state != MEDIA_STREAMER_STATE_IDLE) - { + if (previous_state != MEDIA_STREAMER_STATE_IDLE) { __ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_IDLE); } break; @@ -44,8 +42,7 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat /* * Unlink all gst_elements, set pipeline into state NULL */ - if (previous_state != MEDIA_STREAMER_STATE_NONE) - { + if (previous_state != MEDIA_STREAMER_STATE_NONE) { ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_NULL); } break; @@ -58,15 +55,13 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PAUSED); break; case MEDIA_STREAMER_STATE_SEEKING: - default: - { - ms_info("Error: invalid state [%s]", state); - return MEDIA_STREAMER_ERROR_INVALID_OPERATION; - } + default: { + ms_info("Error: invalid state [%s]", state); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } } - if(ret != MEDIA_STREAMER_ERROR_NONE) - { + if (ret != MEDIA_STREAMER_ERROR_NONE) { ms_error("Failed change state"); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -81,16 +76,15 @@ int __ms_create(media_streamer_s *ms_streamer) int ret = MEDIA_STREAMER_ERROR_NONE; ret = __ms_load_ini_settings(&ms_streamer->ini); - ms_retvm_if(ret!=MEDIA_STREAMER_ERROR_NONE, - MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error load ini file"); + ms_retvm_if(ret != MEDIA_STREAMER_ERROR_NONE, + MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error load ini file"); ms_streamer->nodes_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, __ms_node_destroy); ms_retvm_if(ms_streamer->nodes_table == NULL, - MEDIA_STREAMER_ERROR_INVALID_OPERATION,"Error creating hash table"); + MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating hash table"); ret = __ms_pipeline_create(ms_streamer); - if (ret != MEDIA_STREAMER_ERROR_NONE) - { + if (ret != MEDIA_STREAMER_ERROR_NONE) { ms_error("Error while creating media streamer pipeline."); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -101,17 +95,17 @@ int __ms_create(media_streamer_s *ms_streamer) } static void __node_remove_cb(gpointer key, - gpointer value, - gpointer user_data) + gpointer value, + gpointer user_data) { - media_streamer_s *ms_streamer = (media_streamer_s*)user_data; + media_streamer_s *ms_streamer = (media_streamer_s *)user_data; ms_retm_if(ms_streamer == NULL, "Handle is NULL"); - media_streamer_node_s *ms_node = (media_streamer_node_s*)value; + media_streamer_node_s *ms_node = (media_streamer_node_s *)value; ms_retm_if(ms_node == NULL, "Handle is NULL"); ms_info("Try to delete [%s] node from streamer, node type/subtype [%d/%d]", - ms_node->name, ms_node->type, ms_node->subtype); + ms_node->name, ms_node->type, ms_node->subtype); gchar *bin_name = NULL; gboolean gst_ret = FALSE; @@ -119,28 +113,24 @@ static void __node_remove_cb(gpointer key, __ms_element_set_state(ms_node->gst_element, GST_STATE_NULL); gst_object_ref(ms_node->gst_element); - switch(ms_node->type) - { + switch (ms_node->type) { case MEDIA_STREAMER_NODE_TYPE_SRC: - gst_ret = gst_bin_remove(GST_BIN(ms_streamer->src_bin),ms_node->gst_element); + gst_ret = gst_bin_remove(GST_BIN(ms_streamer->src_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_SRC_BIN_NAME); break; case MEDIA_STREAMER_NODE_TYPE_SINK: - gst_ret = gst_bin_remove(GST_BIN(ms_streamer->sink_video_bin),ms_node->gst_element); + gst_ret = gst_bin_remove(GST_BIN(ms_streamer->sink_video_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); break; default: - gst_ret = gst_bin_remove(GST_BIN(ms_streamer->topology_bin),ms_node->gst_element); + gst_ret = gst_bin_remove(GST_BIN(ms_streamer->topology_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_TOPOLOGY_BIN_NAME); break; } - if(!gst_ret) - { + if (!gst_ret) { ms_error("Failed to remove Element [%s] from bin [%s]", ms_node->name, bin_name); - } - else - { + } else { ms_info("Success removed Element [%s] from bin [%s]", ms_node->name, bin_name); } @@ -151,42 +141,32 @@ static void __node_remove_cb(gpointer key, void __ms_streamer_destroy(media_streamer_s *ms_streamer) { - if(__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_NONE) != MEDIA_STREAMER_ERROR_NONE) - { + if (__ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_NONE) != MEDIA_STREAMER_ERROR_NONE) { ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); } gst_element_unlink_many(ms_streamer->src_bin, - ms_streamer->topology_bin, - ms_streamer->sink_video_bin, NULL); + ms_streamer->topology_bin, + ms_streamer->sink_video_bin, NULL); - g_hash_table_foreach(ms_streamer->nodes_table, __node_remove_cb,(gpointer)ms_streamer); + g_hash_table_foreach(ms_streamer->nodes_table, __node_remove_cb, (gpointer)ms_streamer); - if(ms_streamer->src_bin && !gst_bin_remove(GST_BIN(ms_streamer->pipeline),ms_streamer->src_bin)) - { + if (ms_streamer->src_bin && !gst_bin_remove(GST_BIN(ms_streamer->pipeline), ms_streamer->src_bin)) { ms_error("Failed to remove src_bin from pipeline"); - } - else - { + } else { ms_info("src_bin removed from pipeline"); } - if(ms_streamer->sink_video_bin && !gst_bin_remove(GST_BIN(ms_streamer->pipeline),ms_streamer->sink_video_bin)) - { + if (ms_streamer->sink_video_bin && !gst_bin_remove(GST_BIN(ms_streamer->pipeline), ms_streamer->sink_video_bin)) { ms_error("Failed to remove sink_bin from pipeline"); - } - else - { + } else { ms_info("sink_bin removed from pipeline"); } - if(ms_streamer->topology_bin && !gst_bin_remove(GST_BIN(ms_streamer->pipeline),ms_streamer->topology_bin)) - { + if (ms_streamer->topology_bin && !gst_bin_remove(GST_BIN(ms_streamer->pipeline), ms_streamer->topology_bin)) { ms_error("Failed to remove topology_bin from pipeline"); - } - else - { + } else { ms_info("topology_bin removed from pipeline"); } @@ -199,5 +179,5 @@ void __ms_streamer_destroy(media_streamer_s *ms_streamer) MS_SAFE_FREE(ms_streamer); -// gst_deinit(); + /* gst_deinit(); */ } diff --git a/src/media_streamer_util.c b/src/media_streamer_util.c index 46d9fdd..5e1520b 100755 --- a/src/media_streamer_util.c +++ b/src/media_streamer_util.c @@ -23,34 +23,28 @@ #include #ifdef MEDIA_STREAMER_DEFAULT_INI - static gboolean __ms_generate_default_ini(void); +static gboolean __ms_generate_default_ini(void); #endif static void __ms_check_ini_status(void); -gchar* __ms_ini_get_string(dictionary *dict, - const char *ini_path, char *default_str) +gchar *__ms_ini_get_string(dictionary *dict, + const char *ini_path, char *default_str) { gchar *result_str = NULL; ms_retvm_if(ini_path == NULL, NULL, "Invalid ini path"); - if (dict == NULL) - { + if (dict == NULL) { result_str = g_strdup(default_str); - } - else - { + } else { gchar *str = NULL; str = iniparser_getstring(dict, ini_path, default_str); if (str && - (strlen(str) > 0) && - (strlen(str) < MEDIA_STREAMER_INI_MAX_STRLEN)) - { + (strlen(str) > 0) && + (strlen(str) < MEDIA_STREAMER_INI_MAX_STRLEN)) { result_str = g_strdup(str); - } - else - { + } else { result_str = g_strdup(default_str); } } @@ -69,16 +63,12 @@ gboolean __ms_load_ini_dictionary(dictionary **dict) ms_dict = iniparser_load(MEDIA_STREAMER_INI_DEFAULT_PATH); /* if no file exists. create one with set of default values */ - if (!ms_dict) - { + if (!ms_dict) { #ifdef MEDIA_STREAMER_DEFAULT_INI ms_debug("No inifile found. Media streamer will create default inifile."); - if (FALSE == __ms_generate_default_ini()) - { + if (FALSE == __ms_generate_default_ini()) { ms_debug("Creating default .ini file failed. Media-streamer will use default values."); - } - else - { + } else { /* load default ini */ ms_dict = iniparser_load(MEDIA_STREAMER_INI_DEFAULT_PATH); } @@ -109,20 +99,16 @@ int __ms_load_ini_settings(media_streamer_ini_t *ini) /* get ini values */ memset(ini, 0, sizeof(media_streamer_ini_t)); - if (__ms_load_ini_dictionary(&dict)) - { + if (__ms_load_ini_dictionary(&dict)) { /* general */ ini->generate_dot = iniparser_getboolean(dict, "general:generate dot", DEFAULT_GENERATE_DOT); - if (ini->generate_dot == TRUE) - { + if (ini->generate_dot == TRUE) { gchar *dot_path = iniparser_getstring(dict, "general:dot dir" , MEDIA_STREAMER_DEFAULT_DOT_DIR); - ms_debug("generate_dot is TRUE, dot file will be stored into %s",dot_path); - g_setenv ("GST_DEBUG_DUMP_DOT_DIR", dot_path, FALSE); + ms_debug("generate_dot is TRUE, dot file will be stored into %s", dot_path); + g_setenv("GST_DEBUG_DUMP_DOT_DIR", dot_path, FALSE); } - } - else /* if dict is not available just fill the structure with default value */ - { + } else { /* if dict is not available just fill the structure with default value */ ms_debug("failed to load ini. using hardcoded default"); /* general settings*/ @@ -143,21 +129,16 @@ static void __ms_check_ini_status(void) int file_size = 0; int status = 0; - if(fp == NULL) - { + if (fp == NULL) { ms_debug("Failed to get media streamer ini file."); - } - else - { + } else { fseek(fp, 0, SEEK_END); file_size = ftell(fp); fclose(fp); - if (file_size < 5) - { + if (file_size < 5) { ms_debug("media_streamer.ini file size=%d, Corrupted! Removed", file_size); status = g_remove(MEDIA_STREAMER_INI_DEFAULT_PATH); - if (status == -1) - { + if (status == -1) { ms_error("failed to delete corrupted ini"); } } @@ -174,14 +155,12 @@ static gboolean __ms_generate_default_ini(void) /* create new file */ fp = fopen(MEDIA_STREAMER_INI_DEFAULT_PATH, "wt"); - if (!fp) - { + if (!fp) { return FALSE; } /* writing default ini file */ - if (strlen(default_ini) != fwrite(default_ini, 1, strlen(default_ini), fp)) - { + if (strlen(default_ini) != fwrite(default_ini, 1, strlen(default_ini), fp)) { fclose(fp); return FALSE; } @@ -193,8 +172,7 @@ static gboolean __ms_generate_default_ini(void) const gchar *__ms_convert_mime_to_string(media_format_mimetype_e mime) { - switch(mime) - { + switch (mime) { case MEDIA_FORMAT_I420: return "I420"; case MEDIA_FORMAT_YV12: @@ -210,7 +188,7 @@ const gchar *__ms_convert_mime_to_string(media_format_mimetype_e mime) default: ms_error("Invalid or Unsupported media format [%d].", mime); return NULL; - break; + break; } } diff --git a/test/media_streamer_test.c b/test/media_streamer_test.c index f789c06..8eba035 100755 --- a/test/media_streamer_test.c +++ b/test/media_streamer_test.c @@ -23,8 +23,7 @@ #include -typedef enum -{ +typedef enum { MENU_STATE_UNKNOWN = 0, MENU_STATE_MAIN_MENU, MENU_STATE_BROADCAST_MENU, @@ -32,8 +31,7 @@ typedef enum MENU_STATE_PRESET_MENU } menu_state_e; -typedef enum -{ +typedef enum { SUBMENU_STATE_UNKNOWN = 0, SUBMENU_STATE_GETTING_IP, SUBMENU_STATE_AUTOPLUG = 3, @@ -43,8 +41,7 @@ typedef enum #define SECOND_VOIP_MASK 0x8 #define DOUBLE_STREAMER_MASK 0x10 -typedef enum -{ +typedef enum { PRESET_UNKNOWN = 0, PRESET_RTP_STREAMER = 0x01, PRESET_RTP_CLIENT = 0x02, @@ -65,15 +62,15 @@ static media_streamer_h g_media_streamer; static media_streamer_h g_media_streamer_2; static media_streamer_h current_media_streamer = &g_media_streamer; -//#define ONE_DEVICE_TEST +/*#define ONE_DEVICE_TEST */ #define MAX_STRING_LEN 2048 #define DEFAULT_IP_ADDR "127.0.0.1" #define VIDEO_PORT 5000 #define AUDIO_PORT 6000 -//#define DISABLE_AUDIO -//#define DISABLE_VIDEO +/*#define DISABLE_AUDIO */ +/*#define DISABLE_VIDEO */ /*--------------------------------------------------------------------------- | LOCAL VARIABLE DEFINITIONS: | @@ -99,8 +96,7 @@ static gboolean _create(media_streamer_h *streamer) { g_print("== create \n"); - if(*streamer != NULL) - { + if (*streamer != NULL) { return TRUE; } @@ -108,8 +104,7 @@ static gboolean _create(media_streamer_h *streamer) ret = media_streamer_create(streamer); - if( ret != MEDIA_STREAMER_ERROR_NONE) - { + if (ret != MEDIA_STREAMER_ERROR_NONE) { g_print("Fail to create media streamer"); return FALSE; } @@ -123,8 +118,7 @@ static gboolean _prepare(void) int ret = MEDIA_STREAMER_ERROR_NONE; ret = media_streamer_prepare(current_media_streamer); - if( ret != MEDIA_STREAMER_ERROR_NONE) - { + if (ret != MEDIA_STREAMER_ERROR_NONE) { g_print("Fail to prepare media streamer"); return FALSE; } @@ -139,8 +133,7 @@ static gboolean _unprepare(void) int ret = MEDIA_STREAMER_ERROR_NONE; ret = media_streamer_unprepare(current_media_streamer); - if( ret != MEDIA_STREAMER_ERROR_NONE) - { + if (ret != MEDIA_STREAMER_ERROR_NONE) { g_print("Fail to unprepare media streamer"); return FALSE; } @@ -155,8 +148,7 @@ static gboolean _play() int ret = MEDIA_STREAMER_ERROR_NONE; ret = media_streamer_play(current_media_streamer); - if( ret != MEDIA_STREAMER_ERROR_NONE) - { + if (ret != MEDIA_STREAMER_ERROR_NONE) { g_print("Fail to play media streamer"); return FALSE; } @@ -170,15 +162,13 @@ static gboolean _destroy(media_streamer_h streamer) g_print("== destroy \n"); int ret = MEDIA_STREAMER_ERROR_NONE; - if(streamer == NULL) - { + if (streamer == NULL) { g_print("media streamer already destroyed"); return TRUE; } ret = media_streamer_destroy(streamer); - if( ret != MEDIA_STREAMER_ERROR_NONE) - { + if (ret != MEDIA_STREAMER_ERROR_NONE) { g_print("Fail to destroy media streamer"); return FALSE; } @@ -190,15 +180,13 @@ static gboolean _destroy(media_streamer_h streamer) static void create_formats(void) { - if(!vfmt_raw || !vfmt_encoded || afmt_raw) - { + if (!vfmt_raw || !vfmt_encoded || afmt_raw) { g_print("Formats already created!"); } /* Define video raw format */ media_format_create(&vfmt_raw); - if (media_format_set_video_mime(vfmt_raw, MEDIA_FORMAT_YV12) != MEDIA_FORMAT_ERROR_NONE) - { + if (media_format_set_video_mime(vfmt_raw, MEDIA_FORMAT_YV12) != MEDIA_FORMAT_ERROR_NONE) { g_print("media_format_set_video_mime failed!"); } media_format_set_video_width(vfmt_raw, 800); @@ -208,8 +196,7 @@ static void create_formats(void) /* Define encoded video format */ media_format_create(&vfmt_encoded); - if (media_format_set_video_mime(vfmt_encoded, MEDIA_FORMAT_H264_SP) != MEDIA_FORMAT_ERROR_NONE) - { + if (media_format_set_video_mime(vfmt_encoded, MEDIA_FORMAT_H264_SP) != MEDIA_FORMAT_ERROR_NONE) { g_print("media_format_set_video_mime failed!"); } media_format_set_video_width(vfmt_encoded, 800); @@ -219,8 +206,7 @@ static void create_formats(void) /* Define audio raw format */ media_format_create(&afmt_raw); - if (media_format_set_audio_mime(afmt_raw, MEDIA_FORMAT_PCM) != MEDIA_FORMAT_ERROR_NONE) - { + if (media_format_set_audio_mime(afmt_raw, MEDIA_FORMAT_PCM) != MEDIA_FORMAT_ERROR_NONE) { g_print("media_format_set_audio_mime failed!"); } media_format_set_audio_channel(afmt_raw, 1); @@ -228,11 +214,11 @@ static void create_formats(void) media_format_set_audio_bit(afmt_raw, 16); } -static void set_rtp_params (media_streamer_node_h rtp_node, - const gchar *ip, - int video_port, - int audio_port, - gboolean port_reverse) +static void set_rtp_params(media_streamer_node_h rtp_node, + const gchar *ip, + int video_port, + int audio_port, + gboolean port_reverse) { bundle *params = bundle_create(); @@ -240,17 +226,15 @@ static void set_rtp_params (media_streamer_node_h rtp_node, gchar *audio_src_port = g_strdup_printf("%d", port_reverse ? (audio_port + 5) : audio_port); gchar *audio_sink_port = g_strdup_printf("%d", port_reverse ? audio_port : (audio_port + 5)); - if(g_menu_preset & PRESET_RTP_STREAMER) - { + if (g_menu_preset & PRESET_RTP_STREAMER) { bundle_add_str(params, "audio_sink,port", audio_sink_port); bundle_add_str(params, "audio_sink,host", ip); } - if(g_menu_preset & PRESET_RTP_CLIENT) - { + if (g_menu_preset & PRESET_RTP_CLIENT) { bundle_add_str(params, "audio_source,port", audio_src_port); bundle_add_str(params, "audio_source,format", - "application/x-rtp,media=audio,clock-rate=44100,encoding-name=L16," - "encoding-params=1,channels=1,payload=96"); + "application/x-rtp,media=audio,clock-rate=44100,encoding-name=L16," + "encoding-params=1,channels=1,payload=96"); } g_free(audio_src_port); @@ -261,16 +245,14 @@ static void set_rtp_params (media_streamer_node_h rtp_node, gchar *video_src_port = g_strdup_printf("%d", port_reverse ? (video_port + 5) : video_port); gchar *video_sink_port = g_strdup_printf("%d", port_reverse ? video_port : (video_port + 5)); - if(g_menu_preset & PRESET_RTP_STREAMER) - { + if (g_menu_preset & PRESET_RTP_STREAMER) { bundle_add_str(params, "video_sink,port", video_sink_port); bundle_add_str(params, "video_sink,host", ip); } - if(g_menu_preset & PRESET_RTP_CLIENT) - { + if (g_menu_preset & PRESET_RTP_CLIENT) { bundle_add_str(params, "video_source,port", video_src_port); bundle_add_str(params, "video_source,format", - "application/x-rtp,media=video,clock-rate=90000,encoding-name=H264"); + "application/x-rtp,media=video,clock-rate=90000,encoding-name=H264"); } g_free(video_src_port); @@ -287,65 +269,62 @@ static gboolean _create_rtp_streamer(media_streamer_node_h rtp_bin) g_print("== _create_rtp_streamer \n"); #ifndef DISABLE_VIDEO - //********************** video source *********************************** + /*********************** video source *********************************** */ media_streamer_node_h video_src = NULL; #ifdef ONE_DEVICE_TEST - if(g_menu_preset & SECOND_VOIP_MASK) - { + if (g_menu_preset & SECOND_VOIP_MASK) { media_streamer_src_create(MEDIA_STREAMER_SRC_TYPE_VIDEO_TEST, &video_src); - } - else - { + } else { media_streamer_src_create(MEDIA_STREAMER_SRC_TYPE_CAMERA, &video_src); } #else media_streamer_src_create(MEDIA_STREAMER_SRC_TYPE_CAMERA, &video_src); #endif -// media_streamer_node_set_fmt(video_src, vfmt_raw); + /* media_streamer_node_set_fmt(video_src, vfmt_raw); */ media_streamer_node_add(current_media_streamer, video_src); - //********************** encoder **************************************** + /*********************** encoder **************************************** */ media_streamer_node_h video_enc = NULL; media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER, NULL, vfmt_encoded, &video_enc); media_streamer_node_add(current_media_streamer, video_enc); - //********************** videopay *************************************** + /*********************** videopay *************************************** */ media_streamer_node_h video_pay = NULL; media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_PAY, NULL, vfmt_encoded, &video_pay); media_streamer_node_add(current_media_streamer, video_pay); - //====================Linking Video Streamer===========================// + /*====================Linking Video Streamer=========================== */ media_streamer_node_link(video_src, "src", video_enc, "sink"); media_streamer_node_link(video_enc, "src", video_pay, "sink"); media_streamer_node_link(video_pay, "src", rtp_bin, "video_sink"); - //======================================================================// + /*====================================================================== */ g_print("== success streamer video part \n"); #endif #ifndef DISABLE_AUDIO - //********************** audiosrc *********************************** + /*********************** audiosrc *********************************** */ media_streamer_node_h audio_src = NULL; media_streamer_src_create(MEDIA_STREAMER_SRC_TYPE_AUDIO_CAPTURE, &audio_src); media_streamer_node_add(current_media_streamer, audio_src); - //********************** audioencoder *********************************** + /*********************** audioencoder *********************************** */ media_streamer_node_h audio_enc = NULL; media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER, NULL, NULL, &audio_enc); media_streamer_node_add(current_media_streamer, audio_enc); - //********************** rtpL16pay *********************************** + /*********************** rtpL16pay *********************************** */ media_streamer_node_h audio_pay = NULL; media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_PAY, NULL, NULL, &audio_pay); media_streamer_node_add(current_media_streamer, audio_pay); - //====================Linking Audio Streamer===========================// + /*====================Linking Audio Streamer========================== */ media_streamer_node_link(audio_src, "src", audio_enc, "sink"); media_streamer_node_link(audio_enc, "src", audio_pay, "sink"); media_streamer_node_link(audio_pay, "src", rtp_bin, "audio_sink"); - //======================================================================// + /*====================================================================== */ g_print("== success streamer audio part \n"); #endif @@ -358,56 +337,56 @@ static gboolean _create_rtp_client(media_streamer_node_h rtp_bin) g_print("== _create_rtp_client \n"); #ifndef DISABLE_VIDEO - //********************** video_depay*********************************** + /*********************** video_depay*********************************** */ media_streamer_node_h video_depay = NULL; media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_DEPAY, NULL, vfmt_encoded, &video_depay); media_streamer_node_add(current_media_streamer, video_depay); - //********************** videodec *********************************** + /*********************** videodec *********************************** */ media_streamer_node_h video_dec = NULL; media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER, NULL, vfmt_encoded, &video_dec); media_streamer_node_add(current_media_streamer, video_dec); - //********************** videosink *********************************** + /*********************** videosink *********************************** */ media_streamer_node_h video_sink = NULL; media_streamer_sink_create(MEDIA_STREAMER_SINK_TYPE_SCREEN, &video_sink); media_streamer_node_add(current_media_streamer, video_sink); - //====================Linking Video Client===========================// + /*====================Linking Video Client=========================== */ media_streamer_node_link(video_depay, "src", video_dec, "sink"); - media_streamer_node_link(video_dec, "src", video_sink,"sink"); -// media_streamer_node_link(rtp_bin, "video_source", video_depay,"sink"); + media_streamer_node_link(video_dec, "src", video_sink, "sink"); + /* media_streamer_node_link(rtp_bin, "video_source", video_depay,"sink"); */ g_print("== success client video part \n"); #endif #ifndef DISABLE_AUDIO - //********************** audiodepay *********************************** + /*********************** audiodepay *********************************** */ media_streamer_node_h audio_depay = NULL; media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_DEPAY, NULL, NULL, &audio_depay); media_streamer_node_add(current_media_streamer, audio_depay); - //********************** audioconvert *********************************** + /*********************** audioconvert *********************************** */ media_streamer_node_h audio_converter = NULL; media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_CONVERTER, NULL, NULL, &audio_converter); media_streamer_node_add(current_media_streamer, audio_converter); - //********************** audioresample *********************************** + /*********************** audioresample *********************************** */ media_streamer_node_h audio_res = NULL; media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_AUDIO_RESAMPLE, NULL, NULL, &audio_res); media_streamer_node_add(current_media_streamer, audio_res); - //********************** audiosink *********************************** + /*********************** audiosink *********************************** */ media_streamer_node_h audio_sink = NULL; media_streamer_sink_create(MEDIA_STREAMER_SINK_TYPE_AUDIO, &audio_sink); media_streamer_node_add(current_media_streamer, audio_sink); - //====================Linking Audio Client===========================// + /*====================Linking Audio Client=========================== */ media_streamer_node_link(audio_depay, "src", audio_converter, "sink"); media_streamer_node_link(audio_converter, "src", audio_res, "sink"); - media_streamer_node_link(audio_res, "src", audio_sink,"sink"); -// media_streamer_node_link(rtp_bin, "audio_source", audio_depay,"sink"); - //======================================================================// + media_streamer_node_link(audio_res, "src", audio_sink, "sink"); + /*media_streamer_node_link(rtp_bin, "audio_source", audio_depay,"sink"); */ + /*====================================================================== */ g_print("== success client audio part \n"); #endif @@ -416,13 +395,13 @@ static gboolean _create_rtp_client(media_streamer_node_h rtp_bin) } static media_streamer_node_h _create_rtp( - int video_port, - int audio_port, - gboolean second_client) + int video_port, + int audio_port, + gboolean second_client) { g_print("== create rtp node for current preset \n"); - //********************** rtpbin *********************************** + /*********************** rtpbin *********************************** */ media_streamer_node_h rtp_bin = NULL; media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_RTP, vfmt_encoded, vfmt_encoded, &rtp_bin); set_rtp_params(rtp_bin, g_broadcast_address, video_port, audio_port, second_client); @@ -450,20 +429,17 @@ void reset_current_menu_state(void) g_autoplug_mode = FALSE; current_media_streamer = NULL; - if (g_media_streamer) - { + if (g_media_streamer) { _destroy(g_media_streamer); g_media_streamer = NULL; } - if (g_media_streamer_2) - { + if (g_media_streamer_2) { _destroy(g_media_streamer_2); g_media_streamer_2 = NULL; } - if(g_broadcast_address != NULL) - { + if (g_broadcast_address != NULL) { g_free(g_broadcast_address); g_broadcast_address = NULL; } @@ -481,7 +457,7 @@ static void display_autoplug_select_menu(void) g_print("\n"); g_print("Please select Media Streamer pluging mode\n"); g_print("By default will be used [%s] mode\n", - g_autoplug_mode == TRUE ? "autoplug" : "manual"); + g_autoplug_mode == TRUE ? "autoplug" : "manual"); g_print("1. Manual mode \n"); g_print("2. Autoplug mode \n"); } @@ -548,10 +524,8 @@ static void display_main_menu(void) static void display_menu(void) { - if (g_sub_menu_state == SUBMENU_STATE_UNKNOWN) - { - switch (g_menu_state) - { + if (g_sub_menu_state == SUBMENU_STATE_UNKNOWN) { + switch (g_menu_state) { case MENU_STATE_MAIN_MENU: display_main_menu(); break; @@ -568,11 +542,8 @@ static void display_menu(void) g_print("*** Unknown status.\n"); break; } - } - else - { - switch (g_sub_menu_state) - { + } else { + switch (g_sub_menu_state) { case SUBMENU_STATE_GETTING_IP: display_getting_ip_menu(); break; @@ -580,7 +551,7 @@ static void display_menu(void) display_autoplug_select_menu(); break; case SUBMENU_STATE_FORMAT: -// display_format_menu(); + /* display_format_menu(); */ break; default: g_print("*** Unknown Submenu state.\n"); @@ -595,8 +566,7 @@ static void run_preset(void) media_streamer_node_h rtp_bin = NULL; create_formats(); - switch(g_menu_preset) - { + switch (g_menu_preset) { case PRESET_RTP_STREAMER: rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, FALSE); _create_rtp_streamer(rtp_bin); @@ -620,11 +590,11 @@ static void run_preset(void) _create_rtp_streamer(rtp_bin); break; case PRESET_DOUBLE_VOIP_SERVER_2: - rtp_bin = _create_rtp(VIDEO_PORT+10, AUDIO_PORT+10, TRUE); + rtp_bin = _create_rtp(VIDEO_PORT + 10, AUDIO_PORT + 10, TRUE); _create_rtp_streamer(rtp_bin); break; case PRESET_DOUBLE_VOIP_CLIENT: - rtp_bin = _create_rtp(VIDEO_PORT+10, AUDIO_PORT+10, FALSE); + rtp_bin = _create_rtp(VIDEO_PORT + 10, AUDIO_PORT + 10, FALSE); _create_rtp_client(rtp_bin); break; case PRESET_DOUBLE_VOIP_CLIENT_2: @@ -641,52 +611,36 @@ void _interpret_main_menu(char *cmd) { int len = strlen(cmd); - if(len == 1) - { - if ( !strncmp(cmd, "1", len)) - { + if (len == 1) { + if (!strncmp(cmd, "1", len)) { g_menu_state = MENU_STATE_BROADCAST_MENU; - } - else if ( !strncmp(cmd, "2", len)) - { + } else if (!strncmp(cmd, "2", len)) { g_menu_state = MENU_STATE_VOIP_MENU; - } - else if ( !strncmp(cmd, "q", len)) - { + } else if (!strncmp(cmd, "q", len)) { quit(); } - } - else - { + } else { g_print("wrong command\n"); } } -//=====================Broadcast Menu============================// +/*=====================Broadcast Menu============================// */ void _interpret_broadcast_menu(char *cmd) { int len = strlen(cmd); - if(len == 1) - { - if( !strncmp(cmd, "1", len)) - { + if (len == 1) { + if (!strncmp(cmd, "1", len)) { g_menu_preset = PRESET_RTP_CLIENT; g_menu_state = MENU_STATE_PRESET_MENU; - } - else if( !strncmp(cmd, "2", len)) - { + } else if (!strncmp(cmd, "2", len)) { g_menu_preset = PRESET_RTP_STREAMER; g_menu_state = MENU_STATE_PRESET_MENU; - } - else if( !strncmp(cmd, "b", len)) - { + } else if (!strncmp(cmd, "b", len)) { reset_current_menu_state(); display_menu(); } - } - else - { + } else { g_print("wrong command\n"); } } @@ -695,51 +649,35 @@ void _interpret_voip_menu(char *cmd) { int len = strlen(cmd); - if(len == 1) - { - if( !strncmp(cmd, "1", len)) - { + if (len == 1) { + if (!strncmp(cmd, "1", len)) { g_menu_preset = PRESET_VOIP; g_menu_state = MENU_STATE_PRESET_MENU; - } - else if( !strncmp(cmd, "2", len)) - { + } else if (!strncmp(cmd, "2", len)) { g_menu_preset = PRESET_VOIP_2; g_menu_state = MENU_STATE_PRESET_MENU; - } - else if( !strncmp(cmd, "3", len)) - { - //double Server 1 + } else if (!strncmp(cmd, "3", len)) { + /*double Server 1 */ g_menu_preset = PRESET_DOUBLE_VOIP_SERVER; g_menu_state = MENU_STATE_PRESET_MENU; - } - else if( !strncmp(cmd, "4", len)) - { - //double Server 2 + } else if (!strncmp(cmd, "4", len)) { + /*double Server 2 */ g_menu_preset = PRESET_DOUBLE_VOIP_SERVER_2; g_menu_state = MENU_STATE_PRESET_MENU; - } - else if( !strncmp(cmd, "5", len)) - { - //double Client 1 + } else if (!strncmp(cmd, "5", len)) { + /*double Client 1 */ g_menu_preset = PRESET_DOUBLE_VOIP_CLIENT; g_menu_state = MENU_STATE_PRESET_MENU; - } - else if( !strncmp(cmd, "6", len)) - { - //double Client 2 + } else if (!strncmp(cmd, "6", len)) { + /*double Client 2 */ g_menu_preset = PRESET_DOUBLE_VOIP_CLIENT_2; g_menu_state = MENU_STATE_PRESET_MENU; - } - else if( !strncmp(cmd, "b", len)) - { + } else if (!strncmp(cmd, "b", len)) { reset_current_menu_state(); - //display_menu(); + /*display_menu(); */ } - } - else - { + } else { g_print("wrong command\n"); } } @@ -748,18 +686,14 @@ void _interpret_getting_ip_menu(char *cmd) { int min_len = strlen("0.0.0.0"); int cmd_len = strlen(cmd); - if(g_broadcast_address != NULL) - { + if (g_broadcast_address != NULL) { g_free(g_broadcast_address); } - if(cmd_len > min_len) - { + if (cmd_len > min_len) { g_broadcast_address = g_strdup(cmd); g_print("== IP address setted to [%s]\n", g_broadcast_address); - } - else - { + } else { g_broadcast_address = g_strdup(DEFAULT_IP_ADDR); g_print("Invalid IP. Default address will be used [%s]\n", DEFAULT_IP_ADDR); } @@ -771,26 +705,20 @@ void _interpret_getting_ip_menu(char *cmd) void _interpret_autoplug_menu(char *cmd) { - int cmd_number = atoi(cmd)-1; + int cmd_number = atoi(cmd) - 1; - if(cmd_number == 1 || cmd_number == 0) - { + if (cmd_number == 1 || cmd_number == 0) { g_autoplug_mode = cmd_number; - } - else - { + } else { g_print("Invalid input. Default autoplug mode will be used\n"); } g_print("Selected pluging mode is [%s]\n", - g_autoplug_mode == TRUE ? "autoplug" : "manual"); + g_autoplug_mode == TRUE ? "autoplug" : "manual"); - if(g_menu_preset & PRESET_RTP_STREAMER) - { + if (g_menu_preset & PRESET_RTP_STREAMER) { g_sub_menu_state = SUBMENU_STATE_GETTING_IP; - } - else - { + } else { run_preset(); g_sub_menu_state = SUBMENU_STATE_UNKNOWN; } @@ -800,75 +728,51 @@ void _interpret_preset_menu(char *cmd) { int len = strlen(cmd); - if(len == 1 || len == 2) - { - if( !strncmp(cmd, "1", len)) - { - if((g_menu_preset & DOUBLE_STREAMER_MASK) && - (g_menu_preset & PRESET_RTP_CLIENT)) - { + if (len == 1 || len == 2) { + if (!strncmp(cmd, "1", len)) { + if ((g_menu_preset & DOUBLE_STREAMER_MASK) && + (g_menu_preset & PRESET_RTP_CLIENT)) { _create(&g_media_streamer_2); current_media_streamer = g_media_streamer_2; g_print("== success create media streamer 2\n"); - } - else - { + } else { _create(&g_media_streamer); current_media_streamer = g_media_streamer; g_print("== success create media streamer\n"); } - } - else if( !strncmp(cmd, "2", len)) - { - // call the run_preset function after autoplug mode was selected; + } else if (!strncmp(cmd, "2", len)) { + /* call the run_preset function after autoplug mode was selected; */ g_sub_menu_state = SUBMENU_STATE_AUTOPLUG; - } - else if( !strncmp(cmd, "4", len)) - { + } else if (!strncmp(cmd, "4", len)) { _prepare(); - } - else if( !strncmp(cmd, "5", len)) - { + } else if (!strncmp(cmd, "5", len)) { _unprepare(); - } - else if( !strncmp(cmd, "6", len)) - { + } else if (!strncmp(cmd, "6", len)) { _play(g_media_streamer); - } - else if( !strncmp(cmd, "7", len)) - { + } else if (!strncmp(cmd, "7", len)) { _destroy(current_media_streamer); current_media_streamer = NULL; - } - else if( !strncmp(cmd, "b", len)) - { - if(g_menu_preset & DOUBLE_STREAMER_MASK) - { + } else if (!strncmp(cmd, "b", len)) { + if (g_menu_preset & DOUBLE_STREAMER_MASK) { g_menu_state = MENU_STATE_VOIP_MENU; g_autoplug_mode = FALSE; current_media_streamer = NULL; - } - else - { + } else { reset_current_menu_state(); } display_menu(); } - } - else - { + } else { g_print("wrong command\n"); } } static void interpret_cmd(char *cmd) { - if(g_sub_menu_state == SUBMENU_STATE_UNKNOWN) - { - switch(g_menu_state) - { + if (g_sub_menu_state == SUBMENU_STATE_UNKNOWN) { + switch (g_menu_state) { case MENU_STATE_MAIN_MENU: _interpret_main_menu(cmd); break; @@ -886,11 +790,8 @@ static void interpret_cmd(char *cmd) return; break; } - } - else - { - switch (g_sub_menu_state) - { + } else { + switch (g_sub_menu_state) { case SUBMENU_STATE_GETTING_IP: _interpret_getting_ip_menu(cmd); break; @@ -898,7 +799,7 @@ static void interpret_cmd(char *cmd) _interpret_autoplug_menu(cmd); break; case SUBMENU_STATE_FORMAT: - //display_format_menu(); + /*display_format_menu(); */ break; default: g_print("*** Unknown Submenu state.\n"); @@ -930,7 +831,7 @@ int main(int argc, char **argv) GIOChannel *stdin_channel; stdin_channel = g_io_channel_unix_new(0); g_io_channel_set_flags(stdin_channel, G_IO_FLAG_NONBLOCK, NULL); - g_io_add_watch(stdin_channel, G_IO_IN,(GIOFunc)input, NULL); + g_io_add_watch(stdin_channel, G_IO_IN, (GIOFunc)input, NULL); display_menu(); -- 2.7.4 From 729614aae84e00ded3b6addc9afaa1d7bf40e689 Mon Sep 17 00:00:00 2001 From: "eunhae1.choi" Date: Thu, 11 Jun 2015 13:02:46 +0900 Subject: [PATCH 4/5] modify lib path with macro for build 64bit Change-Id: I5189914d1db96880769c3cdb8193587341f1b871 --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index df8d4a5..e3d5fcc 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ ENDIF("${ARCH}" STREQUAL "arm") ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") ADD_DEFINITIONS("-DTIZEN_DEBUG") -SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib") +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}") AUX_SOURCE_DIRECTORY (src MAIN_SRC) @@ -48,7 +48,7 @@ SET_TARGET_PROPERTIES(${fw_name} CLEAN_DIRECT_OUTPUT 1 ) -INSTALL(TARGETS ${fw_name} DESTINATION lib) +INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR}) INSTALL( DIRECTORY ${INC_DIR}/ DESTINATION include/media FILES_MATCHING @@ -67,7 +67,7 @@ CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc @ONLY ) -INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION lib/pkgconfig) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) ADD_SUBDIRECTORY(test) -- 2.7.4 From 0a781ca0f2c005ca2555248c8f835828a91983d9 Mon Sep 17 00:00:00 2001 From: "eunhae1.choi" Date: Fri, 3 Jul 2015 12:18:10 +0900 Subject: [PATCH 5/5] sync code with spin dev including ACR feedback Change-Id: I123afa64a1ec52fe3ae25a9c9c5ef3b73d711677 --- include/media_streamer.h | 550 ++++++++++++++++++++++++++++++------------ include/media_streamer_gst.h | 49 +++- include/media_streamer_node.h | 23 +- include/media_streamer_priv.h | 18 +- include/media_streamer_util.h | 46 ++-- src/media_streamer.c | 277 ++++++++++++++++----- src/media_streamer_gst.c | 437 +++++++++++++++++++++++---------- src/media_streamer_node.c | 235 ++++++++++++++++-- src/media_streamer_priv.c | 37 ++- src/media_streamer_util.c | 19 ++ test/media_streamer_test.c | 191 +++++++++++++-- 11 files changed, 1436 insertions(+), 446 deletions(-) diff --git a/include/media_streamer.h b/include/media_streamer.h index 04ac0b6..eb239fe 100755 --- a/include/media_streamer.h +++ b/include/media_streamer.h @@ -19,7 +19,6 @@ #include #include -#include #include #include @@ -56,21 +55,14 @@ typedef void *media_streamer_h; typedef void *media_streamer_node_h; /** - * @brief Media streamer time type. - * - * @since_tizen 3.0 - */ -typedef long long media_streamer_time_value; - -/** * @brief Enumeration for media streamer node type. * * @since_tizen 3.0 */ typedef enum { MEDIA_STREAMER_NODE_TYPE_NONE, /**< Not defined type */ - MEDIA_STREAMER_NODE_TYPE_SRC, /**< Src node type */ - MEDIA_STREAMER_NODE_TYPE_SINK, /**< Sink node type */ + MEDIA_STREAMER_NODE_TYPE_SRC, /**< Src node type. Not available for media_streamer_node_create(). Use media_streamer_node_create_src() */ + MEDIA_STREAMER_NODE_TYPE_SINK, /**< Sink node type. Not available for media_streamer_node_create(). Use media_streamer_node_create_sink() */ MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER, /**< Video encoder node type */ MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER, /**< Video decoder node type */ MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER, /**< Audio encoder node type */ @@ -102,17 +94,17 @@ typedef enum { * @since_tizen 3.0 */ typedef enum { - MEDIA_STREAMER_SRC_TYPE_NONE, /**< Not defined src type */ - MEDIA_STREAMER_SRC_TYPE_FILE, /**< Local file src type */ - MEDIA_STREAMER_SRC_TYPE_HTTP, /**< Http src type */ - MEDIA_STREAMER_SRC_TYPE_RTSP, /**< Rtsp src type */ - MEDIA_STREAMER_SRC_TYPE_CAMERA, /**< Camera src type */ - MEDIA_STREAMER_SRC_TYPE_AUDIO_CAPTURE, /**< Audio capture src type */ - MEDIA_STREAMER_SRC_TYPE_VIDEO_CAPTURE, /**< Video capture src type */ - MEDIA_STREAMER_SRC_TYPE_AUDIO_TEST, /**< Audio test src type */ - MEDIA_STREAMER_SRC_TYPE_VIDEO_TEST, /**< Video test src type */ - MEDIA_STREAMER_SRC_TYPE_CUSTOM /**< Custom src type */ -} media_streamer_src_type_e; + MEDIA_STREAMER_NODE_SRC_TYPE_NONE, /**< Not defined src type */ + MEDIA_STREAMER_NODE_SRC_TYPE_FILE, /**< Local file src type */ + MEDIA_STREAMER_NODE_SRC_TYPE_HTTP, /**< Http src type, Network internet feature is required */ + MEDIA_STREAMER_NODE_SRC_TYPE_RTSP, /**< Rtsp src type, Network internet feature is required */ + MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA, /**< Camera src type, Camera feature is required */ + MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_CAPTURE, /**< Audio capture src type, Microphone feature is required */ + 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_e; /** * @brief Enumeration for media streamer sink node type. @@ -120,15 +112,15 @@ typedef enum { * @since_tizen 3.0 */ typedef enum { - MEDIA_STREAMER_SINK_TYPE_NONE, /**< Not defined sink type */ - MEDIA_STREAMER_SINK_TYPE_FILE, /**< Local file sink type */ - MEDIA_STREAMER_SINK_TYPE_RTSP, /**< Rtsp sink type */ - MEDIA_STREAMER_SINK_TYPE_HTTP, /**< Http sink type */ - MEDIA_STREAMER_SINK_TYPE_AUDIO, /**< Audio sink type */ - MEDIA_STREAMER_SINK_TYPE_SCREEN, /**< Screen sink type */ - MEDIA_STREAMER_SINK_TYPE_FAKE, /**< Fake sink type */ - MEDIA_STREAMER_SINK_TYPE_CUSTOM /**< Custom sink type */ -} media_streamer_sink_type_e; + MEDIA_STREAMER_NODE_SINK_TYPE_NONE, /**< Not defined sink type */ + MEDIA_STREAMER_NODE_SINK_TYPE_FILE, /**< Local file sink type */ + MEDIA_STREAMER_NODE_SINK_TYPE_RTSP, /**< Rtsp sink type, Network internet feature is required */ + MEDIA_STREAMER_NODE_SINK_TYPE_HTTP, /**< Http sink type, Network internet feature is required */ + MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO, /**< Audio sink type */ + MEDIA_STREAMER_NODE_SINK_TYPE_SCREEN, /**< Screen 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_e; /** * @brief Enumeration for media streamer state. @@ -167,12 +159,209 @@ typedef enum { * @since_tizen 3.0 */ typedef enum { - MEDIA_STREAMER_CUSTOM_BUFFER_UNDERRUN, /**< buffer underrun of custom src */ - MEDIA_STREAMER_CUSTOM_BUFFER_OVERFLOW, /**< buffer overflow of custom src */ + MEDIA_STREAMER_CUSTOM_BUFFER_UNDERRUN, /**< Buffer underrun of custom src */ + MEDIA_STREAMER_CUSTOM_BUFFER_OVERFLOW, /**< Buffer overflow of custom src */ } media_streamer_custom_buffer_status_e; /** + * @brief Definition for "camera-id" parameter of source node. + * @details Index number of camera to activate. + * Data type is integer and default value is 0. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_CAMERA_ID "camera-id" + +/** + * @brief Definition for capture parameter of source node. + * @details Width for camera size to capture. + * Data type is integer and default value is 1600. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_CAPTURE_WIDTH "capture-width" + +/** + * @brief Definition for capture parameter of source node. + * @details Height for camera size to capture. + * Data type is integer and default value is 1200. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_CAPTURE_HEIGHT "capture-height" + +/** + * @brief Definition for is-live parameter of source node. + * @details Whether to act as a live source. + * Data type is boolean and default value is false. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_IS_LIVE_STREAM "is-live" + +/** + * @brief Definition for uri parameter of source node. + * @details Uri to read from + * Data type is string. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_URI "uri" + +/** + * @brief Definition for user-agent parameter of source node + * @details Value of the User-Agent HTTP request header field. + * Data type is string. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_USER_AGENT "user-agent" + +/** + * @brief Definition for stream type parameter of source node + * @details The type of the push data stream. + * 0:stream, 1:seekable, 2:random-access (default:0) + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_STREAM_TYPE "stream-type" + +/** + * @brief Definition for port parameter of source or sink node + * @details The port to receive the packets from. + * Data type is integer and default value is 5004. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_PORT "port" + +/** + * @brief Definition for video port parameter of source node + * @details The port to receive the video packets from. + * Data type is integer. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_VIDEO_IN_PORT "video_in_port" + +/** + * @brief Definition for audio port parameter of source node + * @details The port to receive the audio packets from. + * Data type is integer. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_AUDIO_IN_PORT "audio_in_port" + +/** + * @brief Definition for video port parameter of sink node + * @details The port to send the video packets to. + * Data type is integer. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_VIDEO_OUT_PORT "video_out_port" + +/** + * @brief Definition for audio port parameter of sink node + * @details The port to send the audio packets to. + * Data type is integer. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_AUDIO_OUT_PORT "audio_out_port" + +/** + * @brief Definition for IP address parameter of source node + * @details IP address to send/receive packets for. + * Data type is string and default value is "0.0.0.0". + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_IP_ADDRESS "address" + +/** + * @brief Definition for audio device name parameter of source or sink node + * @details ALSA device, as defined in an asound configuration file. + * ex) "hw:0,0", "hw:0,1" + * Data type is string and default value is "default". + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_AUDIO_DEVICE "audio_device" + +/** + * @brief Definition for sync parameter of sink node + * @details Synchronize on the clock + * Data type is boolean and default value is true. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_CLOCK_SYNCHRONIZED "sync" + +/** + * @brief Definition for rotate parameter of sink node + * @details Rotate angle of display output. + * 0:none/1:rotate 90 degree/2:rotate 180 degree/3:rotate 270 degree + * Default value is 3(rotate 270 degree). + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_ROTATE "rotate" + +/** + * @brief Definition for flip parameter of sink node + * @details Flip for display. + * 0:none, 1:horizontal, 2:vertical, 3:both + * Default value is 0. + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_FLIP "flip" + +/** + * @brief Definition for display geometry method parameter of sink node + * @details Geometrical method for display. + * 0:Letter box + * 1:Original size + * 2:Full-screen + * 3:Cropped full screen + * 4:Original size if surface size is larger than video size(width/height), + * or Letter box if video size(width/height) is larger than surface size. + * 5:Custom ROI + * Default value is 0(Letter box). + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_DISPLAY_GEOMETRY_METHOD "display-geometry-method" + +/** + * @brief Definition for visible parameter of sink node + * @details Draws screen or blacks out. + * Data type is boolean and default value is true(visible). + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_VISIBLE "visible" + +/** + * @brief Definition for host parameter of sink node + * @details The host/IP/Multicast group to send the packets to. + * Data type is string and default value is "localhost". + * @since_tizen 3.0 + * @see media_streamer_node_get_params + */ +#define MEDIA_STREAMER_PARAM_HOST "host" + + +/** * @brief Called when error occurs in media streamer. + * @details Following error codes can be delivered. + * #MEDIA_STREAMER_ERROR_INVALID_OPERATION, + * #MEDIA_STREAMER_ERROR_FILE_NO_SPACE_ON_DEVICE, + * #MEDIA_STREAMER_ERROR_NOT_SUPPORTED, + * #MEDIA_STREAMER_ERROR_CONNECTION_FAILED, + * #MEDIA_STREAMER_ERROR_RESOURCE_CONFLICT * @since_tizen 3.0 * @param [in] streamer Media streamer handle * @param [in] error The error that occurred in media steamer @@ -188,10 +377,10 @@ typedef void (*media_streamer_error_cb)(media_streamer_h streamer, void *user_data); /** - * @brief Called when media streamer state was changed. + * @brief Called when media streamer state is changed. * @since_tizen 3.0 * @param [in] streamer Media streamer handle - * @param [in] previous_state The previous state of the media steamer + * @param [in] previous_state The previous state of the media streamer * @param [in] current_state The current state of media streamer * @param [in] user_data The user data passed from the code where * media_streamer_set_state_changed_cb() was invoked @@ -210,12 +399,12 @@ typedef void (*media_streamer_state_changed_cb)(media_streamer_h streamer, * @details This callback will be invoked when the buffer level drops below the threshold of max size * or no free space in custom source buffer. * @since_tizen 3.0 - * @remarks Callback can be applied only for MEDIA_STREAMER_SRC_TYPE_CUSTOM source type + * @remarks Callback can be applied only for MEDIA_STREAMER_NODE_SRC_TYPE_CUSTOM source type * @param [in] node Media streamer source node handle * @param [in] user_data The user data passed from the callback registration function * @see media_streamer_src_set_buffer_status_cb() - * @see media_streamer_node_get_param_list() - * @see media_streamer_node_set_params() + * @see media_streamer_node_get_param() + * @see media_streamer_node_set_param() */ typedef void (*media_streamer_custom_buffer_status_cb)(media_streamer_node_h node, media_streamer_custom_buffer_status_e status, @@ -223,14 +412,14 @@ typedef void (*media_streamer_custom_buffer_status_cb)(media_streamer_node_h nod /** * @brief Called when new data is available from custom sink. - * @details This callback can be applied only to MEDIA_STREAMER_SINK_TYPE_CUSTOM sink type + * @details This callback can be applied only to MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM sink type * @since_tizen 3.0 * @param [in] node Media streamer sink node handle * @param [in] user_data The user data passed from the code where * media_streamer_sink_set_data_ready_cb() was invoked * This data will be accessible from @a media_streamer_sink_data_ready_cb * @pre media_streamer_sink_set_data_ready_cb() - * @see MEDIA_STREAMER_SINK_TYPE_CUSTOM + * @see MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM * @see media_streamer_sink_set_data_ready_cb() * @see media_streamer_sink_unset_data_ready_cb() */ @@ -239,14 +428,14 @@ typedef void (*media_streamer_sink_data_ready_cb)(media_streamer_node_h node, /** * @brief Called when the end-of-stream has been reached. - * @details This callback can be applied only to MEDIA_STREAMER_SINK_TYPE_CUSTOM sink type + * @details This callback can be applied only to MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM sink type * @since_tizen 3.0 * @param [in] node Media streamer sink node handle * @param [in] user_data The user data passed from the code where * media_streamer_sink_set_eos_cb() was invoked * This data will be accessible from @a media_streamer_sink_eos_cb * @pre media_streamer_sink_set_eos_cb() - * @see MEDIA_STREAMER_SINK_TYPE_CUSTOM + * @see MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM * @see media_streamer_sink_set_eos_cb() * @see media_streamer_sink_unset_eos_cb() */ @@ -254,7 +443,13 @@ typedef void (*media_streamer_sink_eos_cb)(media_streamer_node_h node, void *user_data); /** - * @brief Register a error callback function to be invoked when an error occurs. + * @brief Registers a error callback function to be invoked when an error occurs. + * @details Following error codes can be delivered by error callback. + * #MEDIA_STREAMER_ERROR_INVALID_OPERATION, + * #MEDIA_STREAMER_ERROR_FILE_NO_SPACE_ON_DEVICE, + * #MEDIA_STREAMER_ERROR_NOT_SUPPORTED, + * #MEDIA_STREAMER_ERROR_CONNECTION_FAILED, + * #MEDIA_STREAMER_ERROR_RESOURCE_CONFLICT * @since_tizen 3.0 * @param [in] streamer Media streamer handle * @param [in] callback Callback function pointer @@ -264,7 +459,6 @@ typedef void (*media_streamer_sink_eos_cb)(media_streamer_node_h node, * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful - * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation * @pre Create a media streamer handle by calling media_streamer_create() function @@ -290,7 +484,7 @@ int media_streamer_set_error_cb(media_streamer_h streamer, int media_streamer_unset_error_cb(media_streamer_h streamer); /** - * @brief Register a callback that will be triggered after media streamer state was changed. + * @brief Registers a callback that will be triggered after media streamer state is changed. * @since_tizen 3.0 * @param [in] streamer Media streamer handle * @param [in] callback Callback function pointer @@ -300,7 +494,6 @@ int media_streamer_unset_error_cb(media_streamer_h streamer); * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful - * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation * @pre Create a media streamer handle by calling media_streamer_create() function @@ -327,7 +520,7 @@ int media_streamer_unset_state_change_cb(media_streamer_h streamer); /** * @brief Registers a callback function to be invoked when buffer underrun or overflow is occurred. - * @details This function can be called only for MEDIA_STREAMER_SRC_TYPE_CUSTOM source type + * @details This function can be called only for MEDIA_STREAMER_NODE_SRC_TYPE_CUSTOM source type * @since_tizen 3.0 * @remarks This API is used for media stream playback only. * @param [in] source Media streamer source node handle @@ -338,10 +531,9 @@ int media_streamer_unset_state_change_cb(media_streamer_h streamer); * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful - * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation - * @pre Create a media streamer source node handle by calling media_streamer_src_create() function + * @pre Create a media streamer source node handle by calling media_streamer_node_create_src() function * @pre Add created media streamer source node to media streamer by calling media_streamer_node_add() function * @post media_streamer_custom_buffer_status_cb() will be invoked. * @see media_streamer_src_unset_buffer_status_cb() @@ -365,8 +557,8 @@ int media_streamer_src_set_buffer_status_cb(media_streamer_node_h source, int media_streamer_src_unset_buffer_status_cb(media_streamer_node_h source); /** - * @brief Register 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_SINK_TYPE_CUSTOM sink type + * @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] callback Callback function pointer @@ -376,10 +568,9 @@ int media_streamer_src_unset_buffer_status_cb(media_streamer_node_h source); * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful - * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation - * @pre Create a media streamer sink handle by calling media_streamer_sink_create() function + * @pre Create a media streamer sink handle by calling media_streamer_node_create_sink() function * @pre Add created media streamer sink node to media streamer by calling media_streamer_node_add() function * @post media_streamer_sink_data_ready_cb() will be invoked. * @see media_streamer_sink_unset_data_ready_cb() @@ -400,7 +591,7 @@ int media_streamer_sink_set_data_ready_cb(media_streamer_node_h sink, * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation * @see media_streamer_sink_set_data_ready_cb() */ -int media_streamer_sink_unset_data_ready_cb(media_streamer_h streamer); +int media_streamer_sink_unset_data_ready_cb(media_streamer_node_h sink); /** * @brief Registers a callback function to be called when custom sink detect the end-of-stream. @@ -413,10 +604,9 @@ int media_streamer_sink_unset_data_ready_cb(media_streamer_h streamer); * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful - * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation - * @pre Create a media streamer sink handle by calling media_streamer_sink_create() function + * @pre Create a media streamer sink handle by calling media_streamer_node_create_sink() function * @pre Add created media streamer sink node to media streamer by calling media_streamer_node_add() function * @post media_streamer_sink_eos_cb() will be invoked. * @see media_streamer_sink_unset_eos_cb() @@ -437,7 +627,7 @@ int media_streamer_sink_set_eos_cb(media_streamer_node_h sink, * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation * @see media_streamer_sink_set_eos_cb() */ -int media_streamer_sink_unset_eos_cb(media_streamer_h streamer); +int media_streamer_sink_unset_eos_cb(media_streamer_node_h sink); /** * @brief Creates an instance of media streamer and @@ -468,7 +658,7 @@ int media_streamer_create(media_streamer_h *streamer); * @pre The media streamer state must be set to #MEDIA_STREAMER_STATE_IDLE * 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_src_create(), media_streamer_sink_create() and media_streamer_node_link(). + * 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. * @see media_streamer_unprepare() * @see media_streamer_create() @@ -494,7 +684,7 @@ int media_streamer_unprepare(media_streamer_h streamer); /** * @brief Sets media streamer state to MEDIA_STREAMER_STATE_PLAYING. - * @details start running the current streamer, or resumes it if paused. + * @details Start running the current streamer, or resumes it if paused. * @since_tizen 3.0 * @param [in] streamer Media streamer handle * @return @c 0 on success, @@ -513,7 +703,7 @@ int media_streamer_unprepare(media_streamer_h streamer); int media_streamer_play(media_streamer_h streamer); /** - * @brief Pause the media streamer. + * @brief Pauses the media streamer. * @since_tizen 3.0 * @param [in] streamer Media streamer handle * @return @c 0 on success, @@ -539,11 +729,11 @@ int media_streamer_pause(media_streamer_h streamer); * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation - * @pre The media streamer state must be set to #MEDIA_STREAMER_STATE_PLAYING by calling media_streamer_start() or + * @pre The media streamer state must be set to #MEDIA_STREAMER_STATE_PLAYING by calling media_streamer_play() or * set to #MEDIA_STREAMER_STATE_PAUSED by calling media_streamer_pause(). * @post The media streamer state will be #MEDIA_STREAMER_STATE_READY. * @see media_streamer_create() - * @see media_streamer_start() + * @see media_streamer_play() * @see media_streamer_pause() */ int media_streamer_stop(media_streamer_h streamer); @@ -551,6 +741,11 @@ int media_streamer_stop(media_streamer_h streamer); /** * @brief Destroys media streamer. * @since_tizen 3.0 + * @remark Nodes in streamer will be removed automatically. + * Don't need to remove nodes by calling media_streamer_node_remove(). + * If you want to change the node without destroying streamer handle, + * you can call the media_streamer_node_remove() function + * after setting the streamer state to MEDIA_STREAMER_STATE_IDLE state. * @param [in] streamer Media streamer handle * @return @c 0 on success, * otherwise a negative error value @@ -572,7 +767,6 @@ int media_streamer_destroy(media_streamer_h streamer); * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful - * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation * @pre Create a media streamer handle by calling media_streamer_create() function @@ -584,18 +778,12 @@ int media_streamer_get_state(media_streamer_h streamer, /** * @brief Creates media streamer source node. * @since_tizen 3.0 - * @privlevel public - * @privilege http://tizen.org/privilege/mediastorage - * http://tizen.org/privilege/externalstorage - * http://tizen.org/privilege/internet - * http://tizen.org/privilege/camera - * http://tizen.org/privilege/recorder * @remarks The mediastorage privilege(http://tizen.org/privilege/mediastorage) should be added if any video/audio files are used to play located in the internal storage. - * @remarks The externalstorage privilege(http://tizen.org/privilege/externalstorage) should be added if any video/audio files are used to play located in the external storage. - * @remarks The internet privilege(http://tizen.org/privilege/internet) should be added if any URIs are used to play from network. - * @remarks The camera privilege(http://tizen.org/privilege/camera) should be added if the src node handle the camera device. - * @remarks The recorder privilege(http://tizen.org/privilege/recorder) should be added if the src node handle the recorder device. - * @remarks You can release @a source node using media_streamer_node_destroy() function + * The externalstorage privilege(http://tizen.org/privilege/externalstorage) should be added if any video/audio files are used to play located in the external storage. + * The internet privilege(http://tizen.org/privilege/internet) should be added if any URIs are used to play from network. + * The camera privilege(http://tizen.org/privilege/camera) should be added if the src node handle the camera device. + * The recorder privilege(http://tizen.org/privilege/recorder) should be added if the src node handle the recorder device. + * You can release @a source node using media_streamer_node_destroy() function. * @param [in] type Media streamer source node type * @param [out] src Media streamer source node handle * @return @c 0 on success, @@ -604,16 +792,16 @@ int media_streamer_get_state(media_streamer_h streamer, * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation * @retval #MEDIA_STREAMER_ERROR_PERMISSION_DENIED Permission denied - * @retval #MEDIA_STREAMER_ERROR_FEATURE_NOT_SUPPORTED_ON_DEVICE Not support on device - * @see #media_streamer_src_type_e + * @retval #MEDIA_STREAMER_ERROR_NOT_SUPPORTED Not supported + * @see #media_streamer_node_src_type_e * @see media_streamer_node_destroy() */ -int media_streamer_src_create(media_streamer_src_type_e type, +int media_streamer_node_create_src(media_streamer_node_src_type_e type, media_streamer_node_h *src); /** * @brief Pushes packet into custom source node. - * @details This function can be called only for MEDIA_STREAMER_SRC_TYPE_CUSTOM. + * @details This function can be called only for MEDIA_STREAMER_NODE_SRC_TYPE_CUSTOM. * @since_tizen 3.0 * @param [in] src Media streamer source node handle * @param [in] packet Media packet handle @@ -624,25 +812,20 @@ int media_streamer_src_create(media_streamer_src_type_e type, * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation * @retval #MEDIA_STREAMER_ERROR_PERMISSION_DENIED Permission denied - * @pre Create a source node handle by calling media_streamer_src_create() function + * @pre Create a source node handle by calling media_streamer_node_create_src() function * @pre The media streamer state must be set to #MEDIA_STREAMER_STATE_IDLE at least. * @see #media_packet_h */ -int media_streamer_push_packet(media_streamer_node_h src, +int media_streamer_node_push_packet(media_streamer_node_h src, media_packet_h packet); /** * @brief Creates media streamer sink node. - * @details This function can be called only for MEDIA_STREAMER_SINK_TYPE_CUSTOM * @since_tizen 3.0 - * @privlevel public - * @privilege http://tizen.org/privilege/mediastorage - * http://tizen.org/privilege/externalstorage - * http://tizen.org/privilege/internet * @remarks The mediastorage privilege(http://tizen.org/privilege/mediastorage) should be added if any video/audio files are written in the internal storage devices. - * @remarks The externalstorage privilege(http://tizen.org/privilege/externalstorage) should be added if any video/audio files are written in the external storage devices. - * @remarks The internet privilege(http://tizen.org/privilege/internet) should be added if any URIs are used to transmit the output data. - * @remarks You can release @a sink node using media_streamer_node_destroy() + * The externalstorage privilege(http://tizen.org/privilege/externalstorage) should be added if any video/audio files are written in the external storage devices. + * The internet privilege(http://tizen.org/privilege/internet) should be added if any URIs are used to transmit the output data. + * You can release @a sink node using media_streamer_node_destroy() * @param [in] type Type of sink node to be created * @param [out] sink Media streamer sink node handle * @return @c 0 on success, @@ -651,16 +834,16 @@ int media_streamer_push_packet(media_streamer_node_h src, * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation * @retval #MEDIA_STREAMER_ERROR_PERMISSION_DENIED Permission denied - * @retval #MEDIA_STREAMER_ERROR_FEATURE_NOT_SUPPORTED_ON_DEVICE Not support on device - * @see #media_streamer_sink_type_e + * @retval #MEDIA_STREAMER_ERROR_NOT_SUPPORTED Not supported + * @see #media_streamer_node_sink_type_e * @see media_streamer_node_destroy() */ -int media_streamer_sink_create(media_streamer_sink_type_e type, +int media_streamer_node_create_sink(media_streamer_node_sink_type_e type, media_streamer_node_h *sink); /** * @brief Pulls packet from custom sink node. - * @details This function can be called only for MEDIA_STREAMER_SINK_TYPE_CUSTOM + * @details This function can be called only for MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM * @since_tizen 3.0 * @param [in] sink Media streamer sink node handle * @param [out] packet Media packet handle @@ -670,20 +853,22 @@ int media_streamer_sink_create(media_streamer_sink_type_e type, * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation - * @pre Create a sink node handle by calling media_streamer_sink_create() function + * @pre Create a sink node handle by calling media_streamer_node_create_sink() function * @pre Set media_streamer_data_ready_cb by calling media_streamer_set_data_ready_cb() function. * @see #media_packet_h - * @see media_streamer_sink_create() + * @see media_streamer_node_create_sink() */ -int media_streamer_pull_packet(media_streamer_node_h sink, +int media_streamer_node_pull_packet(media_streamer_node_h sink, media_packet_h *packet); /** - * @brief Creates media streamer node except src and sink. + * @brief Creates media streamer node except MEDIA_STREAMER_NODE_TYPE_SRC and MEDIA_STREAMER_NODE_TYPE_SINK. * @details Creates node specific @a type with specific format of input * and output data. * @since_tizen 3.0 - * @remarks You can release @a node using media_streamer_node_destroy() function + * @remarks The node type should not be MEDIA_STREAMER_NODE_TYPE_SRC and MEDIA_STREAMER_NODE_TYPE_SINK. + * To create src/sink type node, media_streamer_node_create_src()/media_streamer_node_create_sink() should be called. + * You can release @a node using media_streamer_node_destroy() function * @param [in] type Created node type * @param [in] in_fmt Media format handle for input data * @param [in] out_fmt Media format handle for output data @@ -717,8 +902,8 @@ int media_streamer_node_create(media_streamer_node_type_e type, * @pre Create node handle by calling media_streamer_node_create() function * @see media_streamer_create() * @see media_streamer_node_create() - * @see media_streamer_src_create() - * @see media_streamer_sink_create() + * @see media_streamer_node_create_src() + * @see media_streamer_node_create_sink() */ int media_streamer_node_add(media_streamer_h streamer, media_streamer_node_h node); @@ -736,16 +921,17 @@ int media_streamer_node_add(media_streamer_h streamer, * @pre Create node handle by calling media_streamer_node_create() function * @pre If the node was added to media streamer, it have to be removed by calling media_streamer_node_remove() function * @see media_streamer_node_create() - * @see media_streamer_src_create() - * @see media_streamer_sink_create() + * @see media_streamer_node_create_src() + * @see media_streamer_node_create_sink() * @see media_streamer_node_remove() */ int media_streamer_node_destroy(media_streamer_node_h node); /** - * @brief Remove media streamer node from streamer. + * @brief Removes media streamer node from streamer. * @since_tizen 3.0 - * @remarks If the node is linked, it will be unlinked before removing. + * @remarks To remove node without error posting, the state of streamer should be MEDIA_STREAMER_STATE_IDLE. + * If the node is linked, it will be unlinked before removing. * @param [in] streamer Media streamer handle * @param [in] node Media streamer node handle * @return @c 0 on success, @@ -761,9 +947,42 @@ int media_streamer_node_remove(media_streamer_h streamer, media_streamer_node_h node); /** - * @brief Sets media format for media streamer node. + * @brief Links two media streamer nodes. + * @since_tizen 3.0 + * @remark Pads are node's input and output, where you can connect other nodes. + * (src_node) - (sink_node) + * src_node and sink_node is determined relatively. + * In case of (A)-(B)-(C), + * (B) can be sink_node with (A) or (B) can be src_node with (C). + * However, src type node is always src node and sink type node is always sink node. + * (A) is src node and can not be sink node at all. + * (C) is sink node and can not be src node at all. + * @param [in] src_node Media streamer node handle + * @param [in] src_pad_name The name of the source pad of the source node + * @param [in] dest_node The destination media streamer node handle + * @param [in] sink_pad_name The name of the sink pad of the destination node + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MEDIA_STREAMER_ERROR_NONE Successful + * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state + * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation + * @pre Create a source node and a destination node handles + * by calling media_streamer_node_create() function + * and add the nodes into streamer by calling media_streamer_node_add() function. + * @see media_streamer_node_create() + * @see media_streamer_node_add() + */ +int media_streamer_node_link(media_streamer_node_h src_node, + const char *src_pad_name, + media_streamer_node_h dest_node, + const char *sink_pad_name); + +/** + * @brief Sets media format for pad of media streamer node. * @since_tizen 3.0 * @param [in] node Media streamer node handle + * @param [in] pad_name Pad name * @param [in] fmt Media format handle * @return @c 0 on success, * otherwise a negative error value @@ -771,16 +990,19 @@ int media_streamer_node_remove(media_streamer_h streamer, * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation - * @pre Create node handle by calling media_streamer_node_create() function + * @pre Create a node handle by calling media_streamer_node_createxxx() function + * @pre Get pad name by calling media_streamer_node_get_pad_name() function * @see #media_format_h */ -int media_streamer_node_set_format(media_streamer_node_h node, +int media_streamer_node_set_pad_format(media_streamer_node_h node, + const char *pad_name, media_format_h fmt); /** - * @brief Gets media format for media streamer node. + * @brief Gets media format for pad of media streamer node. * @since_tizen 3.0 * @param [in] node Media streamer node handle + * @param [in] pad_name Pad name * @param [out] fmt Media format handle * @return @c 0 on success, * otherwise a negative error value @@ -788,80 +1010,87 @@ int media_streamer_node_set_format(media_streamer_node_h node, * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation - * @pre Create a source node handle by calling media_streamer_node_create() function + * @pre Create a node handle by calling media_streamer_node_createxxx() function + * @pre Get pad name by calling media_streamer_node_get_pad_name() function * @see #media_format_h */ -int media_streamer_node_get_format(media_streamer_node_h node, +int media_streamer_node_get_pad_format(media_streamer_node_h node, + const char *pad_name, media_format_h *fmt); /** - * @brief Links two media streamer nodes. + * @brief Gets name of node pads. * @since_tizen 3.0 - * @param [in] src_node Media streamer node handle - * @param [in] src_pad The name of the source pad of the source node - * @param [in] dest_node The destination media streamer node handle - * @param [in] sink_pad The name of the sink pad of the destination node + * @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. + * 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 + * @param [out] src_pad_name Array of source pad name + * @param [out] src_pad_num The number of source pads + * @param [out] sink_pad_name Array of sink pad name + * @param [out] sink_pad_num The number of sink pads * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful - * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation - * @pre Create a source node and a destination node handles - * by calling media_streamer_node_create() function - * and add the nodes into streamer by calling media_streamer_node_add() function. + * @pre Create a node handle by calling media_streamer_node_createxxx() function * @see media_streamer_node_create() - * @see media_streamer_node_add() + * @see media_streamer_node_create_src() + * @see media_streamer_node_create_sink() */ -int media_streamer_node_link(media_streamer_node_h src_node, - const char *src_pad, - media_streamer_node_h dest_node, - const char *sink_pad); +int media_streamer_node_get_pad_name(media_streamer_node_h node, + char ***src_pad_name, + int *src_pad_num, + char ***sink_pad_name, + int *sink_pad_num); + /** - * @brief Gets formats of node pads. + * @brief Sets parameters of node. + * @details Many parameters can be set at one time all together by using bundle. * @since_tizen 3.0 - * @remark After using the src_fmt and sink_fmt, it have to be free - * @param [in] node Media streamer node handle - * @param [out] src_fmt Array of source pad formats - * @param [out] sink_fmt Array of sink pad formats + * @param [in] node Media streamer node handle + * @param [in] param_list Key value array of media streamer node parameters * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation - * @pre Create a node handle by calling media_streamer_node_create() function + * @pre Create a node handle by calling media_streamer_node_createXXX() function. + * @pre Get param list to set by calling media_streamer_node_get_params() function. * @see media_streamer_node_create() - * @see media_streamer_src_create() - * @see media_streamer_sink_create() + * @see media_streamer_node_create_src() + * @see media_streamer_node_create_sink() + * @see media_streamer_node_get_params() */ -int media_streamer_node_get_pad_format(media_streamer_node_h node, - char **src_fmt, - char **sink_fmt); - +int media_streamer_node_set_params(media_streamer_node_h node, + bundle *param_list); /** - * @brief Sets parameters of node. - * @details Many parameters can be set at one time all together by using bundle. + * @brief Gets node parameter list. * @since_tizen 3.0 - * @param [in] node Media streamer node handle - * @param [in] param_list Key value array of media streamer node parameters + * @remark After using param_list, it have to be free by calling bundle_free() in bundle.h + * Refer to the "Parameter information of node" in this file to get info. + * @param [in] node Media streamer node handle + * @param [out] param_list Key value array of media streamer node parameters * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation - * @pre Create a node handle by calling media_streamer_node_create() function. - * @pre Get param list to set by calling media_streamer_node_get_param_list() function. + * @pre Create a node handle by calling media_streamer_node_createXXX() function + * @post Set params which are needed to set by calling media_streamer_node_set_params() or media_streamer_node_set_param() function. * @see media_streamer_node_create() * @see media_streamer_src_create() * @see media_streamer_sink_create() - * @see media_streamer_node_get_param_list() - * @see media_streamer_node_set_single_param() + * @see media_streamer_node_set_params() + * @see media_streamer_node_set_param() */ -int media_streamer_node_set_params(media_streamer_node_h node, - bundle *param_list); +int media_streamer_node_get_params(media_streamer_node_h node, + bundle **param_list); /** * @brief Sets single parameter of node. @@ -876,38 +1105,41 @@ int media_streamer_node_set_params(media_streamer_node_h node, * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation - * @pre Create a node handle by calling media_streamer_node_create() function. - * @pre Get param list to set by calling media_streamer_node_get_param_list() function. + * @pre Create a node handle by calling media_streamer_node_createXXX() function. + * @pre Get param list to set by calling media_streamer_node_get_params() function. * @see media_streamer_node_create() * @see media_streamer_src_create() * @see media_streamer_sink_create() - * @see media_streamer_node_get_param_list() - * @see media_streamer_node_set_params() + * @see media_streamer_node_get_params() + * @see media_streamer_node_get_param() */ -int media_streamer_node_set_single_param(media_streamer_node_h node, - const char *param_name, const char *param_value); +int media_streamer_node_set_param(media_streamer_node_h node, + const char *param_name, const char *param_value); + /** - * @brief Gets node parameter list. + * @brief Gets value of parameter. + * @details Gets parameter one by one without creating param bundle. * @since_tizen 3.0 - * @remark After using param_list, it have to be free by calling bundle_free() in bundle.h - * @param [in] node Media streamer node handle - * @param [out] param_list Key value array of media streamer node parameters + * @param [in] node Media streamer node handle + * @param [in] param_name Param name of node + * @param [out] param_value Parm value of node * @return @c 0 on success, * otherwise a negative error value * @retval #MEDIA_STREAMER_ERROR_NONE Successful * @retval #MEDIA_STREAMER_ERROR_INVALID_STATE Invalid state * @retval #MEDIA_STREAMER_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MEDIA_STREAMER_ERROR_INVALID_OPERATION Invalid operation - * @pre Create a node handle by calling media_streamer_node_create() function - * @post Set params which are needed to set by calling media_streamer_node_set_params() function. + * @pre Create a node handle by calling media_streamer_node_createXXX() function. + * @pre Get param list to know the param name by calling media_streamer_node_get_params() function. * @see media_streamer_node_create() * @see media_streamer_src_create() * @see media_streamer_sink_create() - * @see media_streamer_node_set_params() + * @see media_streamer_node_get_params() + * @see media_streamer_node_set_param() */ -int media_streamer_node_get_param_list(media_streamer_node_h node, - bundle **param_list); +int media_streamer_node_get_param(media_streamer_node_h node, + const char *param_name, char **param_value); /** * @} diff --git a/include/media_streamer_gst.h b/include/media_streamer_gst.h index 939fd4f..6df2fcd 100755 --- a/include/media_streamer_gst.h +++ b/include/media_streamer_gst.h @@ -52,7 +52,7 @@ GstElement *__ms_element_create(const char *plugin_name, const char *name); * * @since_tizen 3.0 */ -GstElement *__ms_camera_element_create(const char *microphone_plugin_name); +GstElement *__ms_camera_element_create(const char *camera_plugin_name); /** * @brief Creates encoder GstElement by mime type. @@ -83,14 +83,28 @@ GstElement *__ms_audio_encoder_element_create(void); GstElement *__ms_rtp_element_create(media_streamer_node_s *ms_node); /** - * @brief Parse param for RTP node type. + * @brief Find Udp elements into rtp container by name. * * @since_tizen 3.0 */ -int __ms_rtp_set_param( - media_streamer_node_s *node, - const gchar *param_key, - const gchar *param_value); +gboolean __ms_get_rtp_elements(media_streamer_node_s *ms_node, + GstElement **rtp_elem, GstElement **rtcp_elem, const gchar *elem_name); + +/** + * @brief Converts key-value property into needed GType + * and sets this property into GstElement. + * + * @since_tizen 3.0 + */ +gboolean __ms_element_set_property(GstElement *src_element, + const gchar *key, const gchar *param_value); + +/** + * @brief Unlink all pads into GstElement. + * + * @since_tizen 3.0 + */ +gboolean __ms_element_unlink(GstElement *src_element); /** * @brief Creates pipeline, bus and src/sink/topology bins. @@ -104,7 +118,7 @@ int __ms_pipeline_create(media_streamer_s *ms_streamer); * * @since_tizen 3.0 */ -int __ms_add_node_into_bin(media_streamer_s *ms_streamer,media_streamer_node_s *ms_node); +int __ms_add_node_into_bin(media_streamer_s *ms_streamer, media_streamer_node_s *ms_node); /** * @brief Sets GstElement into state. @@ -114,8 +128,29 @@ int __ms_add_node_into_bin(media_streamer_s *ms_streamer,media_streamer_node_s * int __ms_element_set_state(GstElement *gst_element, GstState gst_state); /** + * @brief Gets mediaformat from the GstElement's pad by pad name. + * + * @since_tizen 3.0 + */ +media_format_h __ms_element_get_pad_fmt(GstElement *gst_element, const char* pad_name); + +/** * @brief Sets mediaformat into GstElement. * * @since_tizen 3.0 */ int __ms_element_set_fmt(media_streamer_node_s *node, media_format_h fmt); + +/** + * @brief Push the media packet buffer to the source element. + * + * @since_tizen 3.0 + */ +int __ms_element_push_packet(GstElement *src_element, media_packet_h packet); + +/** + * @brief Pull the media packet buffer from sink element. + * + * @since_tizen 3.0 + */ +int __ms_element_pull_packet(GstElement *sink_element, media_packet_h *packet); diff --git a/include/media_streamer_node.h b/include/media_streamer_node.h index 8843ccf..c3143f7 100755 --- a/include/media_streamer_node.h +++ b/include/media_streamer_node.h @@ -22,8 +22,8 @@ * @since_tizen 3.0 */ int __ms_node_create(media_streamer_node_s *node, - media_format_h in_fmt, - media_format_h out_fmt); + media_format_h in_fmt, + media_format_h out_fmt); /** * @brief Creates media streamer source node. @@ -52,7 +52,7 @@ void __ms_node_destroy(void *data); * @since_tizen 3.0 */ void __ms_node_insert_into_table(GHashTable *nodes_table, - media_streamer_node_s *ms_node); + media_streamer_node_s *ms_node); /** * @brief Remove media streamer node from nodes table. @@ -60,20 +60,27 @@ void __ms_node_insert_into_table(GHashTable *nodes_table, * @since_tizen 3.0 */ int __ms_node_remove_from_table(GHashTable *nodes_table, - media_streamer_node_s *ms_node); + media_streamer_node_s *ms_node); + +/** + * @brief Auto link nodes if needed. + * + * @since_tizen 3.0 + */ +int __ms_autoplug_prepare(media_streamer_s *ms_streamer); /** * @brief Reads node parameters from user's bundle object. * * @since_tizen 3.0 */ -int __ms_node_read_params_from_bundle (media_streamer_node_s *node, - bundle *param_list); +int __ms_node_read_params_from_bundle(media_streamer_node_s *node, + bundle *param_list); /** * @brief Writes GstElement properties into user's bundle object. * * @since_tizen 3.0 */ -int __ms_node_write_params_into_bundle (media_streamer_node_s *node, - bundle *param_list); +int __ms_node_write_params_into_bundle(media_streamer_node_s *node, + bundle *param_list); diff --git a/include/media_streamer_priv.h b/include/media_streamer_priv.h index 67ecfc5..abd567e 100755 --- a/include/media_streamer_priv.h +++ b/include/media_streamer_priv.h @@ -39,16 +39,6 @@ typedef struct { } media_streamer_callback_s; /** - * @brief Media Streamer source callbacks structure. - * - * @since_tizen 3.0 - */ -typedef struct { - media_streamer_callback_s enough_data_cb; - media_streamer_callback_s need_data_cb; -} media_streamer_src_callbacks_s; - -/** * @brief Media Streamer sink callbacks structure. * * @since_tizen 3.0 @@ -89,10 +79,10 @@ typedef struct { * * @since_tizen 3.0 */ -typedef int (*media_streamer_node_set_param)( +typedef int (*ms_node_set_param)( struct media_streamer_node_s *node, - const gchar *param_key, - const gchar *param_value); + const char *param_key, + const char *param_value); /** * @brief Media Streamer node type handle. @@ -105,7 +95,7 @@ typedef struct { media_streamer_s *parent_streamer; media_streamer_node_type_e type; int subtype; - media_streamer_node_set_param set_param; + ms_node_set_param set_param; void *callbacks_structure; } media_streamer_node_s; diff --git a/include/media_streamer_util.h b/include/media_streamer_util.h index e0018c5..866e2ef 100755 --- a/include/media_streamer_util.h +++ b/include/media_streamer_util.h @@ -98,19 +98,24 @@ typedef struct __media_streamer_ini { } media_streamer_ini_t; /*Test elements*/ -#define DEFAULT_VIDEO_TEST_SOURCE "videotestsrc" -#define DEFAULT_AUDIO_TEST_SOURCE "audiotestsrc" +#define DEFAULT_VIDEO_TEST_SOURCE "videotestsrc" +#define DEFAULT_AUDIO_TEST_SOURCE "audiotestsrc" #define DEFAULT_FAKE_SINK "fakesink" #define DEFAULT_QUEUE "queue" /* setting default values if each value is not specified in .ini file */ /* general */ -#define DEFAULT_GENERATE_DOT FALSE -#define DEFAULT_AUDIO_SOURCE "alsasrc" -#define DEFAULT_CAMERA_SOURCE "camerasrc" -#define DEFAULT_VIDEO_SOURCE "ximagesrc" +#define DEFAULT_GENERATE_DOT FALSE +#define DEFAULT_AUDIO_SOURCE "alsasrc" +#define DEFAULT_CAMERA_SOURCE "camerasrc" +#define DEFAULT_VIDEO_SOURCE "ximagesrc" +#define DEFAULT_APP_SOURCE "appsrc" #define DEFAULT_AUDIO_SINK "pulsesink" #define DEFAULT_VIDEO_SINK "autovideosink" +#define DEFAULT_VIDEO_CONVERT "videoconvert" +#define DEFAULT_AUDIO_CONVERT "audioconvert" +#define DEFAULT_AUDIO_RESAMPLE "audioresample" +#define DEFAULT_APP_SINK "appsink" /* udp streaming */ #define DEFAULT_UDP_SOURCE "udpsrc" @@ -120,20 +125,22 @@ typedef struct __media_streamer_ini { /* video format defaults */ #define DEFAULT_VIDEO_ENCODER "omxh264enc" #define DEFAULT_VIDEO_DECODER "omxh264dec" -#define DEFAULT_VIDEO_PARSER "h264parse" -#define DEFAULT_VIDEO_RTPPAY "rtph264pay" -#define DEFAULT_VIDEO_RTPDEPAY "rtph264depay" +#define DEFAULT_VIDEO_PARSER "h263parse" +#define DEFAULT_VIDEO_RTPPAY "rtph263pay" +#define DEFAULT_VIDEO_RTPDEPAY "rtph263depay" /* audio format defaults */ -#define DEFAULT_AUDIO_ENCODER "omxh264enc" -#define DEFAULT_AUDIO_DECODER "omxh264dec" -#define DEFAULT_AUDIO_PARSER "h264parse" -#define DEFAULT_AUDIO_RTPPAY "rtph264pay" -#define DEFAULT_AUDIO_RTPDEPAY "rtph264depay" +#define DEFAULT_AUDIO_RTPPAY "rtpL16pay" +#define DEFAULT_AUDIO_RTPDEPAY "rtpL16depay" #define MEDIA_STREAMER_DEFAULT_CAMERA_FORMAT "video/x-raw,width=320,height=240" #define MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT "audio/x-raw,channels=1,rate=44100,format=S16BE" -#define MEDIA_STREAMER_DEFAULT_ENCODER_FORMAT "video/x-h264,stream-format=byte-stream,profile=high" +#define MEDIA_STREAMER_DEFAULT_ENCODER_FORMAT "video/x-h263,stream-format=byte-stream,profile=high" + +#define MS_ELEMENT_IS_SINK(el) g_str_has_suffix(el, "sink") +#define MS_ELEMENT_IS_SOURCE(el) g_str_has_suffix(el, "source") +#define MS_ELEMENT_IS_AUDIO(el) g_str_has_prefix(el, "audio") +#define MS_ELEMENT_IS_VIDEO(el) g_str_has_prefix(el, "video") #define MEDIA_STREAMER_DEFAULT_DOT_DIR "/tmp" #define MEDIA_STREAMER_DEFAULT_INI \ @@ -216,12 +223,19 @@ gchar *__ms_ini_get_string(dictionary *dict, const char *ini_path, char *default_str); /** - * @brief Converts Media Format mime type into string. + * @brief Converts Media Format mime type into Caps media format string. * * @since_tizen 3.0 */ const gchar *__ms_convert_mime_to_string(media_format_mimetype_e mime); +/** + * @brief Converts Caps stream format into Media Format mime type. + * + * @since_tizen 3.0 + */ +media_format_mimetype_e __ms_convert_string_format_to_mime(const char *format_type); + #ifdef __cplusplus } #endif diff --git a/src/media_streamer.c b/src/media_streamer.c index 459ff70..5e3099b 100755 --- a/src/media_streamer.c +++ b/src/media_streamer.c @@ -29,7 +29,7 @@ * Public Implementation */ -int media_streamer_src_create(media_streamer_src_type_e type, +int media_streamer_node_create_src(media_streamer_node_src_type_e type, media_streamer_node_h *src) { int ret = MEDIA_STREAMER_ERROR_NONE; @@ -41,7 +41,8 @@ int media_streamer_src_create(media_streamer_src_type_e type, ms_retvm_if(ms_src == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error allocation memory"); ms_src->type = MEDIA_STREAMER_NODE_TYPE_SRC; - ms_src->subtype = (media_streamer_src_type_e)type; + ms_src->subtype = (media_streamer_node_src_type_e)type; + ret = __ms_src_node_create(ms_src); if (ret != MEDIA_STREAMER_ERROR_NONE) { MS_SAFE_FREE(ms_src); @@ -55,7 +56,7 @@ int media_streamer_src_create(media_streamer_src_type_e type, return ret; } -int media_streamer_sink_create(media_streamer_sink_type_e type, +int media_streamer_node_create_sink(media_streamer_node_sink_type_e type, media_streamer_node_h *sink) { int ret = MEDIA_STREAMER_ERROR_NONE; @@ -67,7 +68,8 @@ int media_streamer_sink_create(media_streamer_sink_type_e type, ms_retvm_if(ms_sink == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error allocation memory"); ms_sink->type = MEDIA_STREAMER_NODE_TYPE_SINK; - ms_sink->subtype = (media_streamer_sink_type_e)type; + ms_sink->subtype = (media_streamer_node_sink_type_e)type; + ret = __ms_sink_node_create(ms_sink); if (ret != MEDIA_STREAMER_ERROR_NONE) { MS_SAFE_FREE(ms_sink); @@ -119,15 +121,42 @@ int media_streamer_node_destroy(media_streamer_node_h node) /* This node was not added into any media streamer */ __ms_node_destroy(ms_node); } else { - int ret = __ms_node_remove_from_table(ms_node->parent_streamer->nodes_table, ms_node); - ms_retvm_if(ret != MEDIA_STREAMER_ERROR_NONE, MEDIA_STREAMER_ERROR_INVALID_OPERATION, - "Current key was not removed from nodes_table"); + ms_error("Node destroy error: needed to unlink node and remove it from media streamer before destroying."); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } ms_info("Node destroyed successfully"); return MEDIA_STREAMER_ERROR_NONE; } +int media_streamer_node_remove(media_streamer_h streamer, + media_streamer_node_h node) +{ + media_streamer_node_s *ms_node = (media_streamer_node_s *)node; + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; + + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(ms_streamer->nodes_table == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + ms_retvm_if(ms_streamer != ms_node->parent_streamer, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, + "Node [%s] added into another Media Streamer object", ms_node->name); + + g_mutex_lock(&ms_streamer->mutex_lock); + + if (g_hash_table_steal(ms_streamer->nodes_table, (gpointer)ms_node->name) && + __ms_element_unlink(ms_node->gst_element)) { + ms_node->parent_streamer = NULL; + ms_info("Node removed from Media Streamer"); + } else { + ms_error("Error: Node [%s] remove failed", ms_node->name); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + g_mutex_unlock(&ms_streamer->mutex_lock); + + return MEDIA_STREAMER_ERROR_NONE; +} + int media_streamer_node_add(media_streamer_h streamer, media_streamer_node_h node) { @@ -236,8 +265,6 @@ int media_streamer_create(media_streamer_h *streamer) ms_error("Error creating Media Streamer"); __ms_streamer_destroy(ms_streamer); - g_mutex_clear(&ms_streamer->mutex_lock); - return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -260,9 +287,6 @@ int media_streamer_destroy(media_streamer_h streamer) __ms_streamer_destroy(ms_streamer); - g_mutex_unlock(&ms_streamer->mutex_lock); - g_mutex_clear(&ms_streamer->mutex_lock); - ms_info("Media Streamer destroyed successfully"); return MEDIA_STREAMER_ERROR_NONE; @@ -272,11 +296,32 @@ int media_streamer_set_error_cb(media_streamer_h streamer, media_streamer_error_cb callback, void *data) { + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(callback == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Callback is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + ms_streamer->error_cb.callback = callback; + ms_streamer->error_cb.user_data = data; + + g_mutex_unlock(&ms_streamer->mutex_lock); + return MEDIA_STREAMER_ERROR_NONE; } int media_streamer_unset_error_cb(media_streamer_h streamer) { + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + ms_streamer->error_cb.callback = NULL; + ms_streamer->error_cb.user_data = NULL; + + g_mutex_unlock(&ms_streamer->mutex_lock); + return MEDIA_STREAMER_ERROR_NONE; } @@ -284,11 +329,32 @@ int media_streamer_set_state_change_cb(media_streamer_h streamer, media_streamer_state_changed_cb callback, void *data) { + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(callback == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Callback is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + ms_streamer->state_changed_cb.callback = callback; + ms_streamer->state_changed_cb.user_data = data; + + g_mutex_unlock(&ms_streamer->mutex_lock); + return MEDIA_STREAMER_ERROR_NONE; } int media_streamer_unset_state_change_cb(media_streamer_h streamer) { + media_streamer_s *ms_streamer = (media_streamer_s *)streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + ms_streamer->state_changed_cb.callback = NULL; + ms_streamer->state_changed_cb.user_data = NULL; + + g_mutex_unlock(&ms_streamer->mutex_lock); + return MEDIA_STREAMER_ERROR_NONE; } @@ -296,11 +362,33 @@ int media_streamer_src_set_buffer_status_cb(media_streamer_node_h source, media_streamer_custom_buffer_status_cb callback, void *user_data) { + media_streamer_node_s *ms_src = (media_streamer_node_s *)source; + media_streamer_callback_s *src_callback = NULL; + ms_retvm_if(ms_src == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + if (!ms_src->callbacks_structure) { + src_callback = (media_streamer_callback_s *) calloc(1, sizeof(media_streamer_callback_s)); + ms_retvm_if(src_callback == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error allocation memory"); + } else { + src_callback = (media_streamer_callback_s *)ms_src->callbacks_structure; + } + + src_callback->callback = callback; + src_callback->user_data = user_data; + + ms_src->callbacks_structure = (void *)src_callback; return MEDIA_STREAMER_ERROR_NONE; } int media_streamer_src_unset_buffer_status_cb(media_streamer_node_h source) { + media_streamer_node_s *ms_src = (media_streamer_node_s *)source; + ms_retvm_if(ms_src == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + media_streamer_callback_s *src_callback = (media_streamer_callback_s *) ms_src->callbacks_structure; + src_callback->callback = NULL; + src_callback->user_data = NULL; + return MEDIA_STREAMER_ERROR_NONE; } @@ -308,11 +396,34 @@ int media_streamer_sink_set_data_ready_cb(media_streamer_node_h sink, media_streamer_sink_data_ready_cb callback, void *data) { + media_streamer_node_s *ms_sink = (media_streamer_node_s *)sink; + ms_retvm_if(ms_sink == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + media_streamer_sink_callbacks_s *sink_callbacks = ms_sink->callbacks_structure; + if (!sink_callbacks) { + sink_callbacks = (media_streamer_sink_callbacks_s *) calloc(1, sizeof(media_streamer_sink_callbacks_s)); + ms_retvm_if(sink_callbacks == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error allocation memory"); + } + + sink_callbacks->data_ready_cb.callback = callback; + sink_callbacks->data_ready_cb.user_data = data; + + ms_sink->callbacks_structure = (void *)sink_callbacks; return MEDIA_STREAMER_ERROR_NONE; } -int media_streamer_sink_unset_data_ready_cb(media_streamer_node_h source) +int media_streamer_sink_unset_data_ready_cb(media_streamer_node_h sink) { + media_streamer_node_s *ms_sink = (media_streamer_node_s *)sink; + ms_retvm_if(ms_sink == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + media_streamer_sink_callbacks_s *sink_callbacks = ms_sink->callbacks_structure; + ms_retvm_if(sink_callbacks == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Callback didn't set yet"); + + sink_callbacks->data_ready_cb.callback = NULL; + sink_callbacks->data_ready_cb.user_data = NULL; + + ms_sink->callbacks_structure = (void *)sink_callbacks; return MEDIA_STREAMER_ERROR_NONE; } @@ -320,11 +431,34 @@ int media_streamer_sink_set_eos_cb(media_streamer_node_h sink, media_streamer_sink_eos_cb callback, void *data) { + media_streamer_node_s *ms_sink = (media_streamer_node_s *)sink; + ms_retvm_if(ms_sink == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + media_streamer_sink_callbacks_s *sink_callbacks = ms_sink->callbacks_structure; + if (!sink_callbacks) { + sink_callbacks = (media_streamer_sink_callbacks_s *) calloc(1, sizeof(media_streamer_sink_callbacks_s)); + ms_retvm_if(sink_callbacks == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error allocation memory"); + } + + sink_callbacks->eos_cb.callback = callback; + sink_callbacks->eos_cb.user_data = data; + + ms_sink->callbacks_structure = (void *)sink_callbacks; return MEDIA_STREAMER_ERROR_NONE; } -int media_streamer_sink_unset_eos_cb(media_streamer_node_h source) +int media_streamer_sink_unset_eos_cb(media_streamer_node_h sink) { + media_streamer_node_s *ms_sink = (media_streamer_node_s *)sink; + ms_retvm_if(ms_sink == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + media_streamer_sink_callbacks_s *sink_callbacks = ms_sink->callbacks_structure; + ms_retvm_if(sink_callbacks == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Callback didn't set yet"); + + sink_callbacks->data_ready_cb.callback = NULL; + sink_callbacks->data_ready_cb.user_data = NULL; + + ms_sink->callbacks_structure = (void *)sink_callbacks; return MEDIA_STREAMER_ERROR_NONE; } @@ -379,52 +513,40 @@ int media_streamer_get_state(media_streamer_h streamer, return MEDIA_STREAMER_ERROR_NONE; } -int media_streamer_seek(media_streamer_h streamer, - media_streamer_time_value time) -{ - return MEDIA_STREAMER_ERROR_NONE; -} - -int media_streamer_push_packet(media_streamer_node_h src, +int media_streamer_node_push_packet(media_streamer_node_h src, media_packet_h packet) { - return MEDIA_STREAMER_ERROR_NONE; -} - -int media_streamer_pull_packet(media_streamer_node_h sink, - media_packet_h *packet) -{ - return MEDIA_STREAMER_ERROR_NONE; -} - -int media_streamer_node_set_format(media_streamer_node_h node, - media_format_h fmt) -{ - int ret = MEDIA_STREAMER_ERROR_NONE; - media_streamer_node_s *ms_node = (media_streamer_node_s *)node; + media_streamer_node_s *ms_node = (media_streamer_node_s *)src; ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); - ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Format is NULL"); - ret = __ms_element_set_fmt(node, fmt); - return ret; + ms_retvm_if(ms_node->type != MEDIA_STREAMER_NODE_TYPE_SRC, + MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Node type must be Src type for pushing packets."); + ms_retvm_if(ms_node->subtype != MEDIA_STREAMER_NODE_SRC_TYPE_CUSTOM, + MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Source Node must be a custom type for pushing packets."); + + return __ms_element_push_packet(ms_node->gst_element, packet); } -int media_streamer_node_get_format(media_streamer_node_h node, - media_format_h *fmt) +int media_streamer_node_pull_packet(media_streamer_node_h sink, + media_packet_h *packet) { - int ret = MEDIA_STREAMER_ERROR_NONE; - media_streamer_node_s *ms_node = (media_streamer_node_s *)node; + media_streamer_node_s *ms_node = (media_streamer_node_s *)sink; ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); - ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Format is NULL"); + ms_retvm_if(packet == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Media packet is NULL"); + ms_retvm_if(ms_node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(ms_node->type != MEDIA_STREAMER_NODE_TYPE_SINK, + MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Node type must be Sink type for pulling packets."); + ms_retvm_if(ms_node->subtype != MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM, + MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Sink Node must be a custom type for pulling packets."); - return ret; + return __ms_element_pull_packet(ms_node->gst_element, packet); } int media_streamer_node_link(media_streamer_node_h src_node, - const char *src_pad, + const char *src_pad_name, media_streamer_node_h dest_node, - const char *sink_pad) + const char *sink_pad_name) { int ret = MEDIA_STREAMER_ERROR_NONE; media_streamer_node_s *ms_src_node = (media_streamer_node_s *)src_node; @@ -435,14 +557,14 @@ int media_streamer_node_link(media_streamer_node_h src_node, gchar *src_element_name = gst_element_get_name(ms_src_node->gst_element); gchar *sink_element_name = gst_element_get_name(ms_dest_node->gst_element); - ms_retvm_if(src_pad == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Pad is NULL"); - ms_retvm_if(sink_pad == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Pad is NULL"); + ms_retvm_if(src_pad_name == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Pad is NULL"); + ms_retvm_if(sink_pad_name == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Pad is NULL"); gboolean link_ret; - link_ret = gst_element_link_pads(ms_src_node->gst_element, src_pad, ms_dest_node->gst_element, sink_pad); + link_ret = gst_element_link_pads(ms_src_node->gst_element, src_pad_name, ms_dest_node->gst_element, sink_pad_name); if (!link_ret) { - ms_error("Can not link [%s]->%s pad to [%s]->%s pad, ret code [%d] ", src_pad, sink_pad, src_element_name, sink_element_name, link_ret); + ms_error("Can not link [%s]->%s pad to [%s]->%s pad, ret code [%d] ", src_pad_name, sink_pad_name, src_element_name, sink_element_name, link_ret); ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; } @@ -451,10 +573,31 @@ int media_streamer_node_link(media_streamer_node_h src_node, return ret; } +int media_streamer_node_set_pad_format(media_streamer_node_h node, + const char *pad_name, + media_format_h fmt) +{ + media_streamer_node_s *ms_node = (media_streamer_node_s *)node; + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Format is NULL"); + + /* By default it sets format to object's property 'caps'*/ + return __ms_element_set_fmt(node, fmt); +} + int media_streamer_node_get_pad_format(media_streamer_node_h node, - char **in_fmt, - char **out_fmt) + const char *pad_name, + media_format_h *fmt) { + media_streamer_node_s *ms_node = (media_streamer_node_s *)node; + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(pad_name == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Empty pad name"); + ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Format is NULL"); + + *fmt = __ms_element_get_pad_fmt(ms_node->gst_element, pad_name); + + ms_retvm_if(*fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error while getting node fmt"); + return MEDIA_STREAMER_ERROR_NONE; } @@ -475,8 +618,8 @@ int media_streamer_node_set_params(media_streamer_node_h node, return ret; } -int media_streamer_node_get_param_list(media_streamer_node_h node, - bundle **param_list) +int media_streamer_node_get_params(media_streamer_node_h node, + bundle **param_list) { media_streamer_node_s *ms_node = (media_streamer_node_s *)node; ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); @@ -497,3 +640,29 @@ int media_streamer_node_get_param_list(media_streamer_node_h node, *param_list = ms_params; return MEDIA_STREAMER_ERROR_NONE; } + +int media_streamer_node_set_param(media_streamer_node_h node, + const char *param_name, const char *param_value) +{ + media_streamer_node_s *ms_node = (media_streamer_node_s *)node; + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(ms_node->gst_element == NULL && ms_node->set_param, + MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(param_name == NULL || param_value == NULL, + MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Parameters name or value is NULL"); + + return ms_node->set_param(ms_node, param_name, param_value); +} + +int media_streamer_node_get_param(media_streamer_node_h node, + const char *param_name, char **param_value) +{ + media_streamer_node_s *ms_node = (media_streamer_node_s *)node; + ms_retvm_if(ms_node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(param_name == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Param name is NULL"); + + // TBD + + return MEDIA_STREAMER_ERROR_NONE; +} + diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index b63ce9a..290539e 100755 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -17,11 +17,6 @@ #include #include -#define MS_ELEMENT_IS_SINK(el) g_str_has_suffix(el, "sink") -#define MS_ELEMENT_IS_SOURCE(el) g_str_has_suffix(el, "source") -#define MS_ELEMENT_IS_AUDIO(el) g_str_has_prefix(el, "audio") -#define MS_ELEMENT_IS_VIDEO(el) g_str_has_prefix(el, "video") - void __ms_generate_dots(GstElement *bin, gchar *name_tag) { gchar *dot_name; @@ -83,7 +78,7 @@ static int __ms_add_ghostpad(GstElement *gst_element, if (!gst_element || !pad_name) { ghost_pad = gst_ghost_pad_new_no_target(ghost_pad_name, GST_PAD_SRC); gst_element_add_pad(GST_ELEMENT(gst_bin), ghost_pad); - ms_info("Added %s empty ghostpad into [%s]", bin_name); + ms_info("Added [%s] empty ghostpad into [%s]", ghost_pad_name, bin_name); ret = MEDIA_STREAMER_ERROR_NONE; } else { gchar *element_name = gst_element_get_name(gst_element); @@ -149,7 +144,7 @@ static GObject *__ms_get_property_owner(GstElement *element, const gchar *key, G return obj; } -static void __ms_element_set_property(GstElement *element, const gchar *key, const gchar *param_value) +gboolean __ms_element_set_property(GstElement *element, const gchar *key, const gchar *param_value) { gchar *element_name = gst_element_get_name(element); GValue value = G_VALUE_INIT; @@ -158,7 +153,7 @@ static void __ms_element_set_property(GstElement *element, const gchar *key, con if (obj == NULL) { ms_debug("Element [%s] does not have property [%s].", element_name, key); MS_SAFE_GFREE(element_name); - return; + return FALSE; } switch (G_VALUE_TYPE(&value)) { @@ -233,15 +228,16 @@ static void __ms_element_set_property(GstElement *element, const gchar *key, con if (!caps) { ms_error("Can not create caps from param value."); + return FALSE; } else { ms_info("Create Caps from params and set to the object."); g_object_set(obj, key, caps, NULL); gst_caps_unref(caps); } - return; + return TRUE; } else { ms_info("Got unknown type with param->value_type [%d]", G_VALUE_TYPE(&value)); - return; + return FALSE; } break; } @@ -249,6 +245,57 @@ static void __ms_element_set_property(GstElement *element, const gchar *key, con MS_SAFE_GFREE(element_name); } +gboolean __ms_element_unlink(GstElement *element) +{ + gboolean ret = TRUE; + GstPad *pad = NULL; + gchar *pad_name = NULL; + + gchar *peer_pad_name = NULL; + GstPad *peer_pad = NULL; + GstElement *parent = NULL; + + GValue elem = G_VALUE_INIT; + GstIterator *pad_iterator = gst_element_iterate_pads(element); + + while (GST_ITERATOR_OK == gst_iterator_next(pad_iterator, &elem)) { + pad = (GstPad *)g_value_get_object(&elem); + pad_name = gst_pad_get_name(pad); + + if (gst_pad_is_linked(pad)) { + peer_pad = gst_pad_get_peer(pad); + peer_pad_name = gst_pad_get_name(peer_pad); + + gboolean gst_ret = GST_PAD_IS_SRC(pad) ? + gst_pad_unlink(pad, peer_pad) : + gst_pad_unlink(peer_pad, pad); + + if (!gst_ret) { + ms_error("Filed to unlink pad [%s] from peer pad \n", pad_name); + ret = ret && FALSE; + } + + MS_SAFE_GFREE(peer_pad_name); + MS_SAFE_UNREF(peer_pad); + } + + MS_SAFE_GFREE(pad_name); + g_value_reset(&elem); + } + g_value_unset(&elem); + gst_iterator_free(pad_iterator); + + /*Remove node's element from bin and reference saving*/ + parent = gst_element_get_parent(element); + + if (parent != NULL) { + gst_object_ref(element); + ret = ret && gst_bin_remove(GST_BIN(parent), element); + } + + return ret; +} + #if 0 static void __ms_link_elements_on_pad_added_cb(GstPad *new_pad, GstElement *sink_element) { @@ -299,66 +346,102 @@ static void __ms_link_elements_on_pad_added_cb(GstPad *new_pad, GstElement *sink MS_SAFE_GFREE(new_pad_name); MS_SAFE_GFREE(peer_pad_name); } +#endif -static void __ms_got_rtpstream_on_pad_added_cb(media_streamer_node_s *ms_node, GstPad *new_pad, const gchar *compared_type) +static GstElement *__ms_bin_find_element_by_klass(GstElement *sink_bin, const gchar *klass_name) { - GstPad *src_pad; - GstCaps *src_pad_caps = NULL; - GstStructure *src_pad_struct = NULL; - - gchar *sink_element_name = NULL; - GstElement *sink_element; - GValue elem = G_VALUE_INIT; - const gchar *depay_klass_name = "Codec/Depayloader/Network/RTP"; - GstIterator *bin_iterator; + GstIterator *bin_iterator = gst_bin_iterate_sorted(GST_BIN(sink_bin)); + GstElement *found_element; + gboolean found = FALSE; - gchar *new_pad_name = gst_pad_get_name(new_pad); - gchar *source_pad_name = g_strdup_printf("%s_source", compared_type); - - bin_iterator = gst_bin_iterate_elements(GST_BIN(ms_node->parent_streamer->topology_bin)); while (GST_ITERATOR_OK == gst_iterator_next(bin_iterator, &elem)) { - sink_element = (GstElement *)g_value_get_object(&elem); - sink_element_name = gst_element_get_name(sink_element); + found_element = (GstElement *)g_value_get_object(&elem); + const gchar *found_klass = gst_element_factory_get_klass(gst_element_get_factory(found_element)); - const gchar *klass_name = gst_element_factory_get_klass(gst_element_get_factory(sink_element)); + if (g_strrstr(found_klass, klass_name)) { + found = TRUE; + break; + } - if (g_strrstr(klass_name, depay_klass_name)) { - src_pad = gst_element_get_static_pad(sink_element, "src"); - ms_retm_if(src_pad == NULL, "Src pad is NULL"); + g_value_reset(&elem); + } - src_pad_caps = gst_pad_query_caps(src_pad, NULL); - src_pad_struct = gst_caps_get_structure(src_pad_caps, 0); - const gchar *src_pad_type = gst_structure_get_name(src_pad_struct); + g_value_unset(&elem); + gst_iterator_free(bin_iterator); + return found ? found_element : NULL; +} - if (g_strrstr(src_pad_type, compared_type)) { - ms_debug("Element to connect [%s] has type [%s] \n", sink_element_name, src_pad_type); - GstPad *video_source_pad = gst_element_get_static_pad(ms_node->gst_element, source_pad_name); +static gboolean __ms_sink_bin_prepare(GstElement *sink_bin, GstPad *source_pad) +{ + gboolean ret = FALSE; + GstPad *src_pad = NULL; //pad of unlinked inner element - gst_ghost_pad_set_target(GST_GHOST_PAD(video_source_pad), new_pad); - gst_pad_set_active(video_source_pad, TRUE); - __ms_generate_dots(ms_node->parent_streamer->pipeline); - } + GValue elem = G_VALUE_INIT; + GstIterator *bin_iterator; - gst_caps_unref(src_pad_caps); + gchar *source_pad_name = gst_pad_get_name(source_pad); - MS_SAFE_UNREF(src_pad); + GstElement *found_element = __ms_bin_find_element_by_klass(sink_bin, "Depayloader/Network/RTP"); + if (!found_element) { + if (MS_ELEMENT_IS_AUDIO(source_pad_name)) { + found_element = __ms_element_create(DEFAULT_AUDIO_RTPDEPAY, NULL); + } else { + found_element = __ms_element_create("rtph263depay", NULL); } - g_value_reset(&elem); + gst_bin_add(GST_BIN(sink_bin), found_element); } - g_value_unset(&elem); - gst_iterator_free(bin_iterator); - MS_SAFE_GFREE(sink_element_name); - MS_SAFE_GFREE(source_pad_name); - MS_SAFE_FREE(new_pad_name); + __ms_add_ghostpad(found_element, "sink", sink_bin, "sink"); + src_pad = gst_element_get_static_pad(found_element, "src"); + + if (MS_ELEMENT_IS_AUDIO(source_pad_name)) { + found_element = __ms_bin_find_element_by_klass(sink_bin, "Converter/Audio"); + if (!found_element) { + found_element = __ms_element_create(DEFAULT_AUDIO_CONVERT, NULL); + gst_bin_add(GST_BIN(sink_bin), found_element); + } +// GstElement *resample = __ms_element_create(DEFAULT_AUDIO_RESAMPLE, NULL); +// gst_bin_add(GST_BIN(sink_bin), resample); +// g_assert(gst_element_link(found_element, resample)); + } else if (MS_ELEMENT_IS_VIDEO(source_pad_name)) { + found_element = __ms_bin_find_element_by_klass(sink_bin, "Generic/Bin"); + if (!found_element) { + dictionary *dict = NULL; + __ms_load_ini_dictionary(&dict); + found_element = __ms_video_decoder_element_create(dict, MEDIA_FORMAT_H263); + gst_bin_add(GST_BIN(sink_bin), found_element); + __ms_destroy_ini_dictionary(dict); + } + } else { + return FALSE; + } + + if (!gst_pad_is_linked(src_pad)) + { + GstPad *sink_pad = gst_element_get_static_pad(found_element, "sink"); + g_assert(!gst_pad_link(src_pad, sink_pad)); + MS_SAFE_UNREF(sink_pad); + } + MS_SAFE_UNREF(src_pad); + + src_pad = gst_element_get_static_pad(found_element, "src"); + found_element = __ms_bin_find_element_by_klass(sink_bin, "Sink/"); + if (!gst_pad_is_linked(src_pad)) + { + GstPad *sink_pad = gst_element_get_static_pad(found_element, "sink"); + g_assert(!gst_pad_link(src_pad, sink_pad)); + MS_SAFE_UNREF(sink_pad); + } + MS_SAFE_UNREF(src_pad); + ret = TRUE; + + return ret; } -#endif static void __ms_rtpbin_pad_added_cb(GstElement *src, GstPad *new_pad, gpointer user_data) { GstCaps *src_pad_caps = NULL; - GstStructure *src_pad_struct = NULL; GstPad *target_pad = NULL; gchar *new_pad_name = NULL; @@ -373,49 +456,55 @@ static void __ms_rtpbin_pad_added_cb(GstElement *src, GstPad *new_pad, gpointer target_pad = gst_ghost_pad_get_target(GST_GHOST_PAD(new_pad)); src_pad_caps = gst_pad_query_caps(target_pad, NULL); - src_pad_struct = gst_caps_get_structure(src_pad_caps, 0); - const gchar *src_pad_type = gst_structure_get_string(src_pad_struct, "media"); - ms_debug("type is [%s]", src_pad_type); - - if (ms_node->parent_streamer == NULL) { - ms_error("Node doesn`t have parent streamer:\n"); - } else { + if (ms_node->parent_streamer && !gst_caps_is_any(src_pad_caps)) { gchar *source_pad_name = NULL; GstElement *sink_bin = NULL; - if (g_strrstr(src_pad_type, "video")) { + GstStructure *src_pad_struct = NULL; + src_pad_struct = gst_caps_get_structure(src_pad_caps, 0); + + const gchar *src_pad_type = gst_structure_get_string(src_pad_struct, "media"); + ms_debug("type is [%s]", src_pad_type); + if (MS_ELEMENT_IS_VIDEO(src_pad_type)) { source_pad_name = g_strdup_printf("%s_source", "video"); sink_bin = ms_node->parent_streamer->sink_video_bin; - } else if (g_strrstr(src_pad_type, "audio")) { + } else if (MS_ELEMENT_IS_AUDIO(src_pad_type)) { source_pad_name = g_strdup_printf("%s_source", "audio"); sink_bin = ms_node->parent_streamer->sink_audio_bin; } if (source_pad_name != NULL) { - if (gst_object_get_parent(GST_OBJECT(sink_bin)) == NULL) { - gst_bin_add(GST_BIN(ms_node->parent_streamer->pipeline), sink_bin); - } - gst_element_sync_state_with_parent(sink_bin); - 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); gst_pad_set_active(source_pad, TRUE); - GstPad *sink_pad = gst_bin_find_unlinked_pad(GST_BIN(sink_bin), GST_PAD_SINK); - if (sink_pad != NULL) { - __ms_add_ghostpad(gst_pad_get_parent(sink_pad), "sink", sink_bin, "sink"); + g_mutex_lock(&ms_node->parent_streamer->mutex_lock); + if (__ms_sink_bin_prepare(sink_bin, source_pad)) { + + if (gst_object_get_parent(GST_OBJECT(sink_bin)) == NULL) { + gst_bin_add(GST_BIN(ms_node->parent_streamer->pipeline), sink_bin); + } + + gst_element_sync_state_with_parent(sink_bin); + if (gst_element_link_pads(ms_node->gst_element, source_pad_name, sink_bin, "sink")) { __ms_element_set_state(ms_node->gst_element, GST_STATE_PLAYING); __ms_generate_dots(ms_node->parent_streamer->pipeline, "playing"); } else { ms_error("Failed to link [rtp_containeer].[%s] and [sink_bin].[sink]\n", source_pad_name); } - MS_SAFE_UNREF(sink_pad); + } else { + ms_error("Failed to prepare sink_bin for pad type [%s]\n", src_pad_type); } + + g_mutex_unlock(&ms_node->parent_streamer->mutex_lock); + MS_SAFE_UNREF(source_pad); MS_SAFE_GFREE(source_pad_name); } + } else { + ms_debug("Node doesn`t have parent streamer or caps media type\n"); } gst_caps_unref(src_pad_caps); @@ -444,9 +533,12 @@ int __ms_element_set_state(GstElement *gst_element, GstState gst_state) GstElement *__ms_element_create(const char *plugin_name, const char *name) { + GstElement *plugin_elem = NULL; ms_retvm_if(plugin_name == NULL, (GstElement *)NULL, "Error empty plugin name"); ms_info("Creating [%s] element", plugin_name); - return gst_element_factory_make(plugin_name, name); + plugin_elem = gst_element_factory_make(plugin_name, name); + ms_retvm_if(plugin_elem == NULL, (GstElement *)NULL, "Error creating element [%s]", plugin_name); + return plugin_elem; } GstElement *__ms_camera_element_create(const char *camera_plugin_name) @@ -484,7 +576,7 @@ GstElement *__ms_video_encoder_element_create(dictionary *dict , media_format_mi char *format_prefix = NULL; format_prefix = g_strdup_printf("%s:encoder", __ms_convert_mime_to_string(mime)); - plugin_name = __ms_ini_get_string(dict, format_prefix, DEFAULT_VIDEO_DECODER); + plugin_name = __ms_ini_get_string(dict, format_prefix, DEFAULT_VIDEO_ENCODER); GstElement *encoder_elem = __ms_element_create(plugin_name, NULL); MS_SAFE_FREE(format_prefix); MS_SAFE_FREE(plugin_name); @@ -501,7 +593,7 @@ GstElement *__ms_video_encoder_element_create(dictionary *dict , media_format_mi ms_retvm_if(!filter || !encoder_elem || !encoder_bin || !encoder_parser, (GstElement *)NULL, "Error: creating elements for video encoder bin"); - format_prefix = g_strdup_printf("video/x-%s,stream-format=byte-stream,profile=high", + format_prefix = g_strdup_printf("video/x-%s,stream-format=byte-stream,profile=main", __ms_convert_mime_to_string(mime)); GstCaps *videoCaps = gst_caps_from_string(format_prefix); g_object_set(G_OBJECT(filter), "caps", videoCaps, NULL); @@ -624,8 +716,8 @@ GstElement *__ms_rtp_element_create(media_streamer_node_s *ms_node) return rtp_container; } -static gboolean __ms_get_rtp_elements(media_streamer_node_s *ms_node, - GstElement **rtp_elem, GstElement **rtcp_elem, const gchar *elem_name) +gboolean __ms_get_rtp_elements(media_streamer_node_s *ms_node, + GstElement **rtp_elem, GstElement **rtcp_elem, const gchar *elem_name) { gboolean ret = FALSE; gchar *rtp_elem_name = NULL; @@ -705,52 +797,6 @@ static gboolean __ms_get_rtp_elements(media_streamer_node_s *ms_node, return ret; } -int __ms_rtp_set_param( - media_streamer_node_s *ms_node, - const gchar *param_key, - const gchar *param_value) -{ - ms_retvm_if(!ms_node && !ms_node->gst_element, MEDIA_STREAMER_ERROR_NONE, "Error: empty node"); - - gchar **tokens = NULL; - gchar *elem_name = NULL; - guint i = 0; - GstElement *rtp_elem = NULL; - GstElement *rtcp_elem = NULL; - - tokens = g_strsplit(param_key, ",", 3); - ms_retvm_if(tokens == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Invalid rtp parameter line."); - elem_name = tokens[0]; - - if (FALSE == __ms_get_rtp_elements(ms_node, &rtp_elem, &rtcp_elem, elem_name)) { - ms_error("Error: invalid parameter [%s]", param_key); - return MEDIA_STREAMER_ERROR_INVALID_OPERATION; - } - - for (i = 1; (tokens && tokens[i]); i++) { - ms_retvm_if(!rtp_elem || !rtcp_elem, - MEDIA_STREAMER_ERROR_INVALID_OPERATION, - "Error: [%s] did not found or created into streamer", tokens[i]); - - if (!g_strcmp0(tokens[i], "port")) { - __ms_element_set_property(rtp_elem, tokens[i], param_value); - gchar *next_port = g_strdup(param_value); - next_port[strlen(next_port) - 1] += 1; - __ms_element_set_property(rtcp_elem, tokens[i], next_port); - MS_SAFE_GFREE(next_port); - } else if (!g_strcmp0(tokens[i], "host") && MS_ELEMENT_IS_SINK(elem_name)) { - __ms_element_set_property(rtp_elem, tokens[i], param_value); - __ms_element_set_property(rtcp_elem, tokens[i], param_value); - } else if (!g_strcmp0(tokens[i], "format") && MS_ELEMENT_IS_SOURCE(elem_name)) { - __ms_element_set_property(rtp_elem, "caps", param_value); - } - - } - g_strfreev(tokens); - - return MEDIA_STREAMER_ERROR_NONE; -} - int __ms_add_node_into_bin(media_streamer_s *ms_streamer, media_streamer_node_s *ms_node) { int ret = MEDIA_STREAMER_ERROR_NONE; @@ -770,17 +816,17 @@ int __ms_add_node_into_bin(media_streamer_s *ms_streamer, media_streamer_node_s break; case MEDIA_STREAMER_NODE_TYPE_SINK: switch (ms_node->subtype) { - case MEDIA_STREAMER_SINK_TYPE_SCREEN: + case MEDIA_STREAMER_NODE_SINK_TYPE_SCREEN: gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); break; - case MEDIA_STREAMER_SINK_TYPE_AUDIO: + case MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO: gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_audio_bin), ms_node->gst_element); bin_name = g_strdup(MEDIA_STREAMER_AUDIO_SINK_BIN_NAME); break; default: - gst_ret = gst_bin_add(GST_BIN(ms_streamer->sink_video_bin), ms_node->gst_element); - bin_name = g_strdup(MEDIA_STREAMER_VIDEO_SINK_BIN_NAME); + gst_ret = gst_bin_add(GST_BIN(ms_streamer->topology_bin), ms_node->gst_element); + bin_name = g_strdup(MEDIA_STREAMER_TOPOLOGY_BIN_NAME); break; } break; @@ -1007,6 +1053,82 @@ static GstCaps *__ms_create_caps_from_fmt(media_format_h fmt) return caps; } +static media_format_h __ms_create_fmt_from_caps(GstCaps *caps) +{ + media_format_h fmt; + GstStructure *pad_struct; + ms_retvm_if(caps == NULL, NULL, "Error: empty caps!"); + + if (gst_caps_is_any(caps)) { + ms_debug("Can not get format info from any caps!"); + return NULL; + } + + int fmt_ret = MEDIA_FORMAT_ERROR_NONE; + + fmt_ret = media_format_create(&fmt); + ms_retvm_if(fmt_ret != MEDIA_FORMAT_ERROR_NONE, NULL, + "Error: while creating media format object, err[%d]!", fmt_ret); + + pad_struct = gst_caps_get_structure(caps, 0); + const gchar *pad_type = gst_structure_get_name(pad_struct); + const gchar *pad_format = pad_type; + + /* Got raw format type if needed */ + if (g_strrstr(pad_type, "/x-raw")) { + pad_format = gst_structure_get_string(pad_struct, "format"); + } + + ms_debug("Pad type is [%s], format: [%s]", pad_type, pad_format); + if (MS_ELEMENT_IS_VIDEO(pad_type)) { + int width, height; + media_format_set_video_mime(fmt, __ms_convert_string_format_to_mime(pad_format)); + gst_structure_get_int(pad_struct, "width", &width); + media_format_set_video_width(fmt, width); + + gst_structure_get_int(pad_struct, "height", &height); + media_format_set_video_height(fmt, height); + } else if (MS_ELEMENT_IS_AUDIO(pad_type)) { + int channels, bps; + media_format_set_audio_mime(fmt, __ms_convert_string_format_to_mime(pad_format)); + gst_structure_get_int(pad_struct, "channels", &channels); + media_format_set_audio_channel(fmt, channels); + gst_structure_get_int(pad_struct, "rate", &bps); + media_format_set_audio_avg_bps(fmt, bps); + } + + return fmt; +} + +media_format_h __ms_element_get_pad_fmt(GstElement *gst_element, const char *pad_name) +{ + media_format_h fmt; + GstCaps *caps = NULL; + + GstPad *pad = gst_element_get_static_pad(gst_element, pad_name); + gchar *element_name = gst_element_get_name(gst_element); + + if (pad == NULL) { + ms_error("Fail to get pad [%s] from element [%s].", pad_name, element_name); + MS_SAFE_FREE(element_name); + return NULL; + } + + caps = gst_pad_get_allowed_caps(pad); + if (caps == NULL) { + ms_error("Fail to get caps from element [%s] and pad [%s].", element_name, pad_name); + MS_SAFE_FREE(element_name); + MS_SAFE_UNREF(pad); + return NULL; + } + + fmt = __ms_create_fmt_from_caps(caps); + + MS_SAFE_FREE(element_name); + MS_SAFE_UNREF(pad); + return fmt; +} + int __ms_element_set_fmt(media_streamer_node_s *node, media_format_h fmt) { GstCaps *caps = NULL; @@ -1022,3 +1144,72 @@ int __ms_element_set_fmt(media_streamer_node_s *node, media_format_h fmt) return MEDIA_STREAMER_ERROR_NONE; } + +int __ms_element_push_packet(GstElement *src_element, media_packet_h packet) +{ + GstBuffer *buffer; + GstFlowReturn gst_ret = GST_FLOW_OK; + guint64 pts = 0; + guint64 duration = 0; + guchar *buffer_data = NULL; + guint64 size = 0; + + ms_retvm_if(src_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + if (packet == NULL) { + g_signal_emit_by_name(G_OBJECT(src_element), "end-of-stream", &gst_ret, NULL); + return MEDIA_STREAMER_ERROR_NONE; + } + + media_packet_get_buffer_size(packet, &size); + media_packet_get_buffer_data_ptr(packet, &buffer_data); + media_packet_get_pts(packet, &pts); + media_packet_get_duration(packet, &duration); + + buffer = gst_buffer_new_wrapped(buffer_data, size); + + GST_BUFFER_PTS(buffer) = pts; + GST_BUFFER_DURATION(buffer) = duration; + + g_signal_emit_by_name(G_OBJECT(src_element), "push-buffer", buffer, &gst_ret, NULL); + + gst_buffer_unref(buffer); + + if (gst_ret != GST_FLOW_OK) { + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_element_pull_packet(GstElement *sink_element, media_packet_h *packet) +{ + GstBuffer *buffer = NULL; + GstFlowReturn gst_ret = GST_FLOW_OK; + GstSample *sample = NULL; + GstMapInfo map; + + ms_retvm_if(sink_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + /* Retrieve the buffer */ + g_signal_emit_by_name(sink_element, "pull-sample", &sample, NULL); + ms_retvm_if(sample == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Pull sample failed!"); + + buffer = gst_sample_get_buffer(sample); + gst_buffer_map(buffer, &map, GST_MAP_READ); + + media_format_h fmt = __ms_element_get_pad_fmt(sink_element, "sink"); + ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, + "Error while getting media format from sink pad"); + + media_packet_create_from_external_memory(&fmt, (void *)map.data, map.size, NULL, NULL, 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); + gst_buffer_unmap(buffer, &map); + gst_sample_unref(sample); + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 7077070..0c22ee4 100755 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -18,6 +18,64 @@ #include #include +static int __ms_node_set_property(media_streamer_node_s *ms_node, + const gchar *param_key, + const gchar *param_value) +{ + ms_retvm_if(!ms_node && !ms_node->gst_element, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error: empty node"); + ms_retvm_if(!param_key && !param_value, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Error: invalid property parameter"); + + __ms_element_set_property(ms_node->gst_element, param_key, param_value); + + return MEDIA_STREAMER_ERROR_NONE; +} + +static int __ms_rtp_node_set_property(media_streamer_node_s *ms_node, + const char *param_key, + const char *param_value) +{ + ms_retvm_if(!ms_node && !ms_node->gst_element, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error: empty node"); + + gchar **tokens = NULL; + gchar *elem_name = NULL; + guint i = 0; + GstElement *rtp_elem = NULL; + GstElement *rtcp_elem = NULL; + + tokens = g_strsplit(param_key, ",", 3); + ms_retvm_if(tokens == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Invalid rtp parameter line."); + elem_name = tokens[0]; + + if (FALSE == __ms_get_rtp_elements(ms_node, &rtp_elem, &rtcp_elem, elem_name)) { + ms_error("Error: invalid parameter [%s]", param_key); + g_strfreev(tokens); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + for (i = 1; (tokens && tokens[i]); i++) { + ms_retvm_if(!rtp_elem || !rtcp_elem, + MEDIA_STREAMER_ERROR_INVALID_OPERATION, + "Error: [%s] did not found or created into streamer", tokens[i]); + + if (!g_strcmp0(tokens[i], "port")) { + __ms_element_set_property(rtp_elem, tokens[i], param_value); + gchar *next_port = g_strdup(param_value); + next_port[strlen(next_port) - 1] += 1; + __ms_element_set_property(rtcp_elem, tokens[i], next_port); + MS_SAFE_GFREE(next_port); + } else if (!g_strcmp0(tokens[i], "host") && MS_ELEMENT_IS_SINK(elem_name)) { + __ms_element_set_property(rtp_elem, tokens[i], param_value); + __ms_element_set_property(rtcp_elem, tokens[i], param_value); + } else if (!g_strcmp0(tokens[i], "format") && MS_ELEMENT_IS_SOURCE(elem_name)) { + __ms_element_set_property(rtp_elem, "caps", param_value); + } + + } + g_strfreev(tokens); + + return MEDIA_STREAMER_ERROR_NONE; +} + int __ms_node_create(media_streamer_node_s *node, media_format_h in_fmt, media_format_h out_fmt) @@ -35,6 +93,8 @@ int __ms_node_create(media_streamer_node_s *node, __ms_load_ini_dictionary(&dict); + node->set_param = (ms_node_set_param)__ms_node_set_property; + switch (node->type) { case MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER: format_prefix = g_strdup_printf("%s:encoder", __ms_convert_mime_to_string(mime)); @@ -81,7 +141,7 @@ int __ms_node_create(media_streamer_node_s *node, break; case MEDIA_STREAMER_NODE_TYPE_RTP: node->gst_element = __ms_rtp_element_create(node); - node->set_param = (media_streamer_node_set_param)__ms_rtp_set_param; + node->set_param = (ms_node_set_param)__ms_rtp_node_set_property; break; case MEDIA_STREAMER_NODE_TYPE_QUEUE: node->gst_element = __ms_element_create(DEFAULT_QUEUE, NULL); @@ -114,6 +174,35 @@ int __ms_node_create(media_streamer_node_s *node, return MEDIA_STREAMER_ERROR_NONE; } +/* This signal callback is called when appsrc needs data, we add an idle handler + * to the mainloop to start pushing data into the appsrc */ +static void __ms_src_start_feed_cb(GstElement *pipeline, guint size, gpointer data) +{ + media_streamer_node_s *ms_src = (media_streamer_node_s *)data; + ms_retm_if(ms_src == NULL, "Handle is NULL"); + + if (ms_src->callbacks_structure != NULL) { + media_streamer_callback_s *src_callback = (media_streamer_callback_s *)ms_src->callbacks_structure; + media_streamer_custom_buffer_status_cb buffer_status_cb = + (media_streamer_custom_buffer_status_cb) src_callback->callback; + buffer_status_cb((media_streamer_node_h)ms_src, MEDIA_STREAMER_CUSTOM_BUFFER_UNDERRUN, src_callback->user_data); + } +} + +/* This callback is called when appsrc has enough data and we can stop sending. + * We remove the idle handler from the mainloop */ +static void __ms_src_stop_feed_cb(GstElement *pipeline, gpointer data) +{ + media_streamer_node_s *ms_src = (media_streamer_node_s *)data; + ms_retm_if(ms_src == NULL, "Handle is NULL"); + + if (ms_src->callbacks_structure != NULL) { + media_streamer_callback_s *src_callback = (media_streamer_callback_s *)ms_src->callbacks_structure; + media_streamer_custom_buffer_status_cb buffer_status_cb = + (media_streamer_custom_buffer_status_cb) src_callback->callback; + buffer_status_cb((media_streamer_node_h)ms_src, MEDIA_STREAMER_CUSTOM_BUFFER_OVERFLOW, src_callback->user_data); + } +} int __ms_src_node_create(media_streamer_node_s *node) { @@ -124,41 +213,44 @@ int __ms_src_node_create(media_streamer_node_s *node) __ms_load_ini_dictionary(&dict); + node->set_param = (ms_node_set_param)__ms_node_set_property; + switch (node->subtype) { - case MEDIA_STREAMER_SRC_TYPE_FILE: + case MEDIA_STREAMER_NODE_SRC_TYPE_FILE: ms_error("Error: not implemented yet"); break; - case MEDIA_STREAMER_SRC_TYPE_RTSP: + case MEDIA_STREAMER_NODE_SRC_TYPE_RTSP: node->gst_element = __ms_element_create(DEFAULT_UDP_SOURCE, NULL); break; - case MEDIA_STREAMER_SRC_TYPE_HTTP: + case MEDIA_STREAMER_NODE_SRC_TYPE_HTTP: ms_error("Error: not implemented yet"); break; - case MEDIA_STREAMER_SRC_TYPE_CAMERA: + case MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA: plugin_name = __ms_ini_get_string(dict, "sources:camera_source", DEFAULT_CAMERA_SOURCE); node->gst_element = __ms_camera_element_create(plugin_name); break; - case MEDIA_STREAMER_SRC_TYPE_AUDIO_CAPTURE: + case MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_CAPTURE: plugin_name = __ms_ini_get_string(dict, "sources:audio_source", DEFAULT_AUDIO_SOURCE); node->gst_element = __ms_element_create(plugin_name, NULL); break; - case MEDIA_STREAMER_SRC_TYPE_VIDEO_CAPTURE: + case MEDIA_STREAMER_NODE_SRC_TYPE_VIDEO_CAPTURE: plugin_name = __ms_ini_get_string(dict, "sources:video_source", DEFAULT_VIDEO_SOURCE); node->gst_element = __ms_element_create(plugin_name, NULL); break; - case MEDIA_STREAMER_SRC_TYPE_VIDEO_TEST: + case MEDIA_STREAMER_NODE_SRC_TYPE_VIDEO_TEST: node->gst_element = __ms_element_create(DEFAULT_VIDEO_TEST_SOURCE, NULL); - g_object_set(G_OBJECT(node->gst_element), "is-live", true, NULL); break; - case MEDIA_STREAMER_SRC_TYPE_AUDIO_TEST: + case MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_TEST: node->gst_element = __ms_element_create(DEFAULT_AUDIO_TEST_SOURCE, NULL); break; - case MEDIA_STREAMER_SRC_TYPE_CUSTOM: - ms_error("Error: not implemented yet"); + case MEDIA_STREAMER_NODE_SRC_TYPE_CUSTOM: + node->gst_element = __ms_element_create(DEFAULT_APP_SOURCE, NULL); + g_signal_connect(node->gst_element, "need-data", G_CALLBACK(__ms_src_start_feed_cb), (gpointer)node); + g_signal_connect(node->gst_element, "enough-data", G_CALLBACK(__ms_src_stop_feed_cb), (gpointer)node); break; default: ms_error("Error: invalid Src node Type [%d]", node->subtype); @@ -174,6 +266,38 @@ int __ms_src_node_create(media_streamer_node_s *node) return MEDIA_STREAMER_ERROR_NONE; } +/* The appsink has received a buffer */ +static void __ms_sink_new_buffer_cb(GstElement *sink, gpointer *data) +{ + media_streamer_node_s *ms_sink = (media_streamer_node_s *)data; + ms_retm_if(ms_sink == NULL, "Handle is NULL"); + + if (ms_sink->callbacks_structure != NULL) { + media_streamer_sink_callbacks_s *sink_callbacks = + (media_streamer_sink_callbacks_s *)ms_sink->callbacks_structure; + media_streamer_sink_data_ready_cb data_ready_cb = + (media_streamer_sink_data_ready_cb) sink_callbacks->data_ready_cb.callback; + + data_ready_cb((media_streamer_node_h)ms_sink, sink_callbacks->data_ready_cb.user_data); + } +} + +/* The appsink has got eos */ +static void sink_eos(GstElement *sink, gpointer *data) +{ + media_streamer_node_s *ms_sink = (media_streamer_node_s *)data; + ms_retm_if(ms_sink == NULL, "Handle is NULL"); + + if (ms_sink->callbacks_structure != NULL) { + media_streamer_sink_callbacks_s *sink_callbacks = + (media_streamer_sink_callbacks_s *)ms_sink->callbacks_structure; + media_streamer_sink_eos_cb eos_cb = + (media_streamer_sink_eos_cb) sink_callbacks->eos_cb.callback; + + eos_cb((media_streamer_node_h)ms_sink, sink_callbacks->eos_cb.user_data); + } +} + int __ms_sink_node_create(media_streamer_node_s *node) { ms_retvm_if(node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); @@ -183,31 +307,36 @@ int __ms_sink_node_create(media_streamer_node_s *node) __ms_load_ini_dictionary(&dict); + node->set_param = (ms_node_set_param)__ms_node_set_property; + switch (node->subtype) { - case MEDIA_STREAMER_SINK_TYPE_FILE: + case MEDIA_STREAMER_NODE_SINK_TYPE_FILE: ms_error("Error: not implemented yet"); break; - case MEDIA_STREAMER_SINK_TYPE_RTSP: + case MEDIA_STREAMER_NODE_SINK_TYPE_RTSP: node->gst_element = __ms_element_create(DEFAULT_UDP_SINK, NULL); break; - case MEDIA_STREAMER_SINK_TYPE_HTTP: + case MEDIA_STREAMER_NODE_SINK_TYPE_HTTP: ms_error("Error: not implemented yet"); break; - case MEDIA_STREAMER_SINK_TYPE_AUDIO: + case MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO: plugin_name = __ms_ini_get_string(dict, "sinks:audio_sink", DEFAULT_AUDIO_SINK); node->gst_element = __ms_element_create(plugin_name, NULL); break; - case MEDIA_STREAMER_SINK_TYPE_SCREEN: + case MEDIA_STREAMER_NODE_SINK_TYPE_SCREEN: plugin_name = __ms_ini_get_string(dict, "sinks:video_sink", DEFAULT_VIDEO_SINK); node->gst_element = __ms_element_create(plugin_name, NULL); break; - case MEDIA_STREAMER_SINK_TYPE_FAKE: + case MEDIA_STREAMER_NODE_SINK_TYPE_FAKE: node->gst_element = __ms_element_create(DEFAULT_FAKE_SINK, NULL); break; - case MEDIA_STREAMER_SINK_TYPE_CUSTOM: - + case MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM: + node->gst_element = __ms_element_create(DEFAULT_APP_SINK, NULL); + g_object_set(G_OBJECT(node->gst_element), "emit-signals", TRUE, NULL); + g_signal_connect(node->gst_element, "new-sample", G_CALLBACK(__ms_sink_new_buffer_cb), (gpointer)node); + g_signal_connect(node->gst_element, "eos", G_CALLBACK(sink_eos), (gpointer)node); break; default: ms_error("Error: invalid Sink node Type [%d]", node->subtype); @@ -229,9 +358,12 @@ void __ms_node_destroy(void *data) media_streamer_node_s *node = (media_streamer_node_s *)data; ms_retm_if(node == NULL, "Empty value while deleting element from table"); + __ms_element_unlink(node->gst_element); + node_name = g_strdup(node->name); MS_SAFE_UNREF(node->gst_element); MS_SAFE_FREE(node->name); + MS_SAFE_FREE(node->callbacks_structure); ms_info("Node [%s] destroyed", node_name); MS_SAFE_FREE(node_name); @@ -262,6 +394,69 @@ int __ms_node_remove_from_table(GHashTable *nodes_table, return MEDIA_STREAMER_ERROR_NONE; } +int __ms_autoplug_prepare(media_streamer_s *ms_streamer) +{ + GstElement *unlinked_element = NULL; + GstPad *unlinked_pad = NULL; + gchar *unlinked_element_name = NULL; + + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, + "Handle is NULL"); + + /*Find unlinked element into src_bin */ + unlinked_pad = gst_bin_find_unlinked_pad(GST_BIN(ms_streamer->src_bin), GST_PAD_SRC); + while (unlinked_pad) + { + GstCaps *pad_caps = gst_pad_query_caps(unlinked_pad, NULL); + GstStructure *src_pad_struct = gst_caps_get_structure(pad_caps, 0); + const gchar *field = gst_structure_get_name(src_pad_struct); + + unlinked_element = gst_pad_get_parent_element(unlinked_pad); + unlinked_element_name = gst_element_get_name(unlinked_element); + ms_debug("Autoplug: found unlinked element [%s] in src_bin with pad type [%s].", + unlinked_element_name, field); + + /*find elements into topology */ + GstPad *unlinked_topo_pad = gst_bin_find_unlinked_pad(GST_BIN(ms_streamer->topology_bin), GST_PAD_SINK); + GstElement *unlinked_topo_element = gst_pad_get_parent_element(unlinked_topo_pad); + gchar *unlinked_topo_pad_name = gst_pad_get_name(unlinked_topo_pad); + + GstElement *encoder; + GstElement *pay; + if (MS_ELEMENT_IS_VIDEO(field)) { + dictionary *dict = NULL; + __ms_load_ini_dictionary(&dict); + + encoder = __ms_video_encoder_element_create(dict, MEDIA_FORMAT_H263); + pay = __ms_element_create(DEFAULT_VIDEO_RTPPAY, NULL); + gst_bin_add_many(GST_BIN(ms_streamer->topology_bin), encoder, pay, NULL); + + __ms_destroy_ini_dictionary(dict); + + gst_element_link_many(unlinked_element, encoder, pay, NULL); + gst_element_link_pads(pay, "src", unlinked_topo_element, unlinked_topo_pad_name); + } else if (MS_ELEMENT_IS_AUDIO(field)) { + encoder = __ms_audio_encoder_element_create(); + pay = __ms_element_create(DEFAULT_AUDIO_RTPPAY, NULL); + gst_bin_add_many(GST_BIN(ms_streamer->topology_bin), encoder, pay, NULL); + + gst_element_link_many(unlinked_element, encoder, pay, NULL); + gst_element_link_pads(pay, "src", unlinked_topo_element, unlinked_topo_pad_name); + } else { + ms_debug("Autoplug mode doesn't support [%s] type nodes.", field); + } + + MS_SAFE_GFREE(unlinked_topo_pad_name); + MS_SAFE_GFREE(unlinked_element_name); + MS_SAFE_UNREF(unlinked_pad); + gst_caps_unref(pad_caps); + + unlinked_pad = gst_bin_find_unlinked_pad(GST_BIN(ms_streamer->src_bin), GST_PAD_SRC); + } + + return MEDIA_STREAMER_ERROR_NONE; +} + static void __params_foreach_cb(const char *key, const int type, const bundle_keyval_t *kv, diff --git a/src/media_streamer_priv.c b/src/media_streamer_priv.c index 9c6f051..37b5ddb 100755 --- a/src/media_streamer_priv.c +++ b/src/media_streamer_priv.c @@ -47,6 +47,7 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat } break; case MEDIA_STREAMER_STATE_READY: + ret = __ms_autoplug_prepare(ms_streamer); break; case MEDIA_STREAMER_STATE_PLAYING: ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PLAYING); @@ -94,6 +95,7 @@ int __ms_create(media_streamer_s *ms_streamer) return ret; } +#if 0 static void __node_remove_cb(gpointer key, gpointer value, gpointer user_data) @@ -137,7 +139,7 @@ static void __node_remove_cb(gpointer key, MS_SAFE_GFREE(bin_name); } - +#endif void __ms_streamer_destroy(media_streamer_s *ms_streamer) { @@ -145,35 +147,24 @@ void __ms_streamer_destroy(media_streamer_s *ms_streamer) ms_error("Error: can not set state [%d]", MEDIA_STREAMER_ERROR_INVALID_OPERATION); } - gst_element_unlink_many(ms_streamer->src_bin, - ms_streamer->topology_bin, - ms_streamer->sink_video_bin, NULL); - - g_hash_table_foreach(ms_streamer->nodes_table, __node_remove_cb, (gpointer)ms_streamer); + MS_TABLE_SAFE_UNREF(ms_streamer->nodes_table); - if (ms_streamer->src_bin && !gst_bin_remove(GST_BIN(ms_streamer->pipeline), ms_streamer->src_bin)) { - ms_error("Failed to remove src_bin from pipeline"); - } else { - ms_info("src_bin removed from pipeline"); + if (ms_streamer->sink_video_bin && + GST_OBJECT_PARENT(ms_streamer->sink_video_bin) != ms_streamer->pipeline) { + MS_SAFE_UNREF(ms_streamer->sink_video_bin); + ms_info("sink_video_bin removed from pipeline"); } - if (ms_streamer->sink_video_bin && !gst_bin_remove(GST_BIN(ms_streamer->pipeline), ms_streamer->sink_video_bin)) { - ms_error("Failed to remove sink_bin from pipeline"); - } else { - ms_info("sink_bin removed from pipeline"); + if (ms_streamer->sink_audio_bin && + GST_OBJECT_PARENT(ms_streamer->sink_audio_bin) != ms_streamer->pipeline) { + MS_SAFE_UNREF(ms_streamer->sink_audio_bin); + ms_info("sink_audio_bin removed from pipeline"); } - - if (ms_streamer->topology_bin && !gst_bin_remove(GST_BIN(ms_streamer->pipeline), ms_streamer->topology_bin)) { - ms_error("Failed to remove topology_bin from pipeline"); - } else { - ms_info("topology_bin removed from pipeline"); - } - - ms_streamer->state = MEDIA_STREAMER_STATE_NONE; + g_mutex_unlock(&ms_streamer->mutex_lock); + g_mutex_clear(&ms_streamer->mutex_lock); - MS_TABLE_SAFE_UNREF(ms_streamer->nodes_table); MS_SAFE_UNREF(ms_streamer->bus); MS_SAFE_UNREF(ms_streamer->pipeline); diff --git a/src/media_streamer_util.c b/src/media_streamer_util.c index 5e1520b..1cde4fc 100755 --- a/src/media_streamer_util.c +++ b/src/media_streamer_util.c @@ -192,4 +192,23 @@ const gchar *__ms_convert_mime_to_string(media_format_mimetype_e mime) } } + +media_format_mimetype_e __ms_convert_string_format_to_mime(const char *format_type) +{ + if (g_strrstr(format_type, "I420")) { + return MEDIA_FORMAT_I420; + } else if (g_strrstr(format_type, "YV12")) { + return MEDIA_FORMAT_YV12; + } else if (g_strrstr(format_type, "h263")) { + return MEDIA_FORMAT_H263; + } else if (g_strrstr(format_type, "h264")) { + return MEDIA_FORMAT_H264_SP; + } else if (g_strrstr(format_type, "S16BE")) { + return MEDIA_FORMAT_PCM; + } else { + ms_error("Invalid or Unsupported media format [%s].", format_type); + return MEDIA_FORMAT_NONE; + } +} + #endif diff --git a/test/media_streamer_test.c b/test/media_streamer_test.c index 8eba035..2b979c3 100755 --- a/test/media_streamer_test.c +++ b/test/media_streamer_test.c @@ -173,14 +173,21 @@ static gboolean _destroy(media_streamer_h streamer) return FALSE; } - g_menu_preset = PRESET_UNKNOWN; + + if (current_media_streamer == g_media_streamer) { + g_media_streamer = NULL; + } else { + g_media_streamer_2 = NULL; + } + current_media_streamer = NULL; + g_print("== success destroy \n"); return TRUE; } static void create_formats(void) { - if (!vfmt_raw || !vfmt_encoded || afmt_raw) { + if (!vfmt_raw || !vfmt_encoded || !afmt_raw) { g_print("Formats already created!"); } @@ -196,7 +203,7 @@ static void create_formats(void) /* Define encoded video format */ media_format_create(&vfmt_encoded); - if (media_format_set_video_mime(vfmt_encoded, MEDIA_FORMAT_H264_SP) != MEDIA_FORMAT_ERROR_NONE) { + if (media_format_set_video_mime(vfmt_encoded, MEDIA_FORMAT_H263) != MEDIA_FORMAT_ERROR_NONE) { g_print("media_format_set_video_mime failed!"); } media_format_set_video_width(vfmt_encoded, 800); @@ -215,7 +222,7 @@ static void create_formats(void) } static void set_rtp_params(media_streamer_node_h rtp_node, - const gchar *ip, + const char *ip, int video_port, int audio_port, gboolean port_reverse) @@ -242,8 +249,8 @@ static void set_rtp_params(media_streamer_node_h rtp_node, #endif #ifndef DISABLE_VIDEO - gchar *video_src_port = g_strdup_printf("%d", port_reverse ? (video_port + 5) : video_port); - gchar *video_sink_port = g_strdup_printf("%d", port_reverse ? video_port : (video_port + 5)); + char *video_src_port = g_strdup_printf("%d", port_reverse ? (video_port + 5) : video_port); + char *video_sink_port = g_strdup_printf("%d", port_reverse ? video_port : (video_port + 5)); if (g_menu_preset & PRESET_RTP_STREAMER) { bundle_add_str(params, "video_sink,port", video_sink_port); @@ -273,12 +280,13 @@ static gboolean _create_rtp_streamer(media_streamer_node_h rtp_bin) media_streamer_node_h video_src = NULL; #ifdef ONE_DEVICE_TEST if (g_menu_preset & SECOND_VOIP_MASK) { - media_streamer_src_create(MEDIA_STREAMER_SRC_TYPE_VIDEO_TEST, &video_src); + media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_VIDEO_TEST, &video_src); + media_streamer_node_set_param(video_src, "is-live", "true"); } else { - media_streamer_src_create(MEDIA_STREAMER_SRC_TYPE_CAMERA, &video_src); + media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA, &video_src); } #else - media_streamer_src_create(MEDIA_STREAMER_SRC_TYPE_CAMERA, &video_src); + media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA, &video_src); #endif /* media_streamer_node_set_fmt(video_src, vfmt_raw); */ media_streamer_node_add(current_media_streamer, video_src); @@ -306,7 +314,7 @@ static gboolean _create_rtp_streamer(media_streamer_node_h rtp_bin) #ifndef DISABLE_AUDIO /*********************** audiosrc *********************************** */ media_streamer_node_h audio_src = NULL; - media_streamer_src_create(MEDIA_STREAMER_SRC_TYPE_AUDIO_CAPTURE, &audio_src); + media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_CAPTURE, &audio_src); media_streamer_node_add(current_media_streamer, audio_src); /*********************** audioencoder *********************************** */ @@ -332,6 +340,41 @@ static gboolean _create_rtp_streamer(media_streamer_node_h rtp_bin) return TRUE; } +static gboolean _create_rtp_streamer_autoplug(media_streamer_node_h rtp_bin) +{ + g_print("== _create_rtp_streamer \n"); + +#ifndef DISABLE_VIDEO + /*********************** video source *********************************** */ + media_streamer_node_h video_src = NULL; +#ifdef ONE_DEVICE_TEST + if (g_menu_preset & SECOND_VOIP_MASK) { + media_streamer_node_create_src(MEDIA_STREAMER_SRC_TYPE_VIDEO_TEST, &video_src); + media_streamer_node_set_single_param(video_src, "is-live", "true"); + } else { + media_streamer_node_create_src(MEDIA_STREAMER_SRC_TYPE_CAMERA, &video_src); + } +#else + media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA, &video_src); +#endif + /* media_streamer_node_set_fmt(video_src, vfmt_raw); */ + media_streamer_node_add(current_media_streamer, video_src); + + g_print("== success streamer video part \n"); +#endif + +#ifndef DISABLE_AUDIO + /*********************** audiosrc *********************************** */ + media_streamer_node_h audio_src = NULL; + media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_CAPTURE, &audio_src); + media_streamer_node_add(current_media_streamer, audio_src); + + g_print("== success streamer audio part \n"); +#endif + + return TRUE; +} + static gboolean _create_rtp_client(media_streamer_node_h rtp_bin) { g_print("== _create_rtp_client \n"); @@ -349,7 +392,7 @@ static gboolean _create_rtp_client(media_streamer_node_h rtp_bin) /*********************** videosink *********************************** */ media_streamer_node_h video_sink = NULL; - media_streamer_sink_create(MEDIA_STREAMER_SINK_TYPE_SCREEN, &video_sink); + media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_SCREEN, &video_sink); media_streamer_node_add(current_media_streamer, video_sink); /*====================Linking Video Client=========================== */ @@ -378,7 +421,7 @@ static gboolean _create_rtp_client(media_streamer_node_h rtp_bin) /*********************** audiosink *********************************** */ media_streamer_node_h audio_sink = NULL; - media_streamer_sink_create(MEDIA_STREAMER_SINK_TYPE_AUDIO, &audio_sink); + media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_AUDIO, &audio_sink); media_streamer_node_add(current_media_streamer, audio_sink); /*====================Linking Audio Client=========================== */ @@ -394,6 +437,32 @@ static gboolean _create_rtp_client(media_streamer_node_h rtp_bin) return TRUE; } +static gboolean _create_rtp_client_autoplug(media_streamer_node_h rtp_bin) +{ + g_print("== _create_rtp_client \n"); + +#ifndef DISABLE_VIDEO + /*********************** videosink *********************************** */ + media_streamer_node_h video_sink = NULL; + media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_SCREEN, &video_sink); + media_streamer_node_add(current_media_streamer, video_sink); + + g_print("== success client video part \n"); +#endif + +#ifndef DISABLE_AUDIO + /*********************** 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); + + g_print("== success client audio part \n"); +#endif + + return TRUE; +} + + static media_streamer_node_h _create_rtp( int video_port, int audio_port, @@ -403,12 +472,83 @@ static media_streamer_node_h _create_rtp( /*********************** rtpbin *********************************** */ media_streamer_node_h rtp_bin = NULL; - media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_RTP, vfmt_encoded, vfmt_encoded, &rtp_bin); + media_streamer_node_create(MEDIA_STREAMER_NODE_TYPE_RTP, NULL, NULL, &rtp_bin); set_rtp_params(rtp_bin, g_broadcast_address, video_port, audio_port, second_client); media_streamer_node_add(current_media_streamer, rtp_bin); return rtp_bin; } +/* Application source callback */ +static void buffer_status_cb(media_streamer_node_h node, + media_streamer_custom_buffer_status_e status, + void *user_data) { + + static int count = 0; /* Try send only 10 packets*/ + if (status == MEDIA_STREAMER_CUSTOM_BUFFER_UNDERRUN + && count < 10) { + g_print("Buffer status cb got underflow\n"); + + char *test = g_strdup_printf("[%d]This is buffer_status_cb test!", count); + guint64 size = strlen(test); + + media_packet_h packet; + media_packet_create_from_external_memory(&vfmt_encoded, + (void *)test, size, NULL, NULL, &packet); + media_streamer_node_push_packet(node, packet); + count++; + } else { + media_streamer_node_push_packet(node, NULL); + g_print("Buffer status cb got overflow\n"); + } +} + +/* Application sink callbacks */ +static void new_buffer_cb(media_streamer_node_h node, void *user_data) +{ + char *received_data = NULL; + media_packet_h packet; + + media_streamer_node_pull_packet(node, &packet); + media_packet_get_buffer_data_ptr(packet, &received_data); + g_print("Received new packet from appsink with data [%s]\n", received_data); + + media_packet_destroy(packet); +} + +static void eos_cb(media_streamer_node_h node, void *user_data) +{ + + g_print("Got EOS cb from appsink\n"); +} + +static gboolean _create_app_test() +{ + g_print("== _create_appsrc \n"); + + /*********************** app_src *********************************** */ + media_streamer_node_h app_src = NULL; + media_streamer_node_create_src(MEDIA_STREAMER_NODE_SRC_TYPE_CUSTOM, &app_src); + media_streamer_node_add(current_media_streamer, app_src); + + /*********************** app_sink *********************************** */ + media_streamer_node_h app_sink = NULL; + media_streamer_node_create_sink(MEDIA_STREAMER_NODE_SINK_TYPE_CUSTOM, &app_sink); + media_streamer_node_set_pad_format(app_sink, "sink", vfmt_raw); + media_streamer_node_add(current_media_streamer, app_sink); + + /*====================Linking ======================================== */ + media_streamer_node_link(app_src, "src", app_sink, "sink"); + /*====================================================================== */ + + media_streamer_src_set_buffer_status_cb(app_src, buffer_status_cb, NULL); + media_streamer_sink_set_data_ready_cb(app_sink, new_buffer_cb, NULL); + media_streamer_sink_set_eos_cb(app_sink, eos_cb, NULL); + + g_print("== success appsrc part \n"); + + return TRUE; +} + /***************************************************************/ /** Testsuite */ /***************************************************************/ @@ -488,8 +628,8 @@ static void display_voip_menu(void) g_print("1. one streamer VoIP 1 \n"); g_print("2. one streamer VoIP 2 \n"); g_print("3. two streamers VoIP server 1 \n"); - g_print("4. two streamers VoIP server 2 \n"); - g_print("5. two streamers VoIP client 1 \n"); + g_print("4. two streamers VoIP client 1 \n"); + g_print("5. two streamers VoIP server 2 \n"); g_print("6. two streamers VoIP client 2 \n"); g_print("b. back \n"); g_print("----------------------------------------------------\n"); @@ -569,11 +709,19 @@ static void run_preset(void) switch (g_menu_preset) { case PRESET_RTP_STREAMER: rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, FALSE); - _create_rtp_streamer(rtp_bin); + if (g_autoplug_mode) { + _create_rtp_streamer_autoplug(rtp_bin); + } else { + _create_rtp_streamer(rtp_bin); + } break; case PRESET_RTP_CLIENT: rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, TRUE); - _create_rtp_client(rtp_bin); + if (g_autoplug_mode) { + _create_rtp_client_autoplug(rtp_bin); + } else { + _create_rtp_client(rtp_bin); + } break; case PRESET_VOIP: rtp_bin = _create_rtp(VIDEO_PORT, AUDIO_PORT, FALSE); @@ -661,13 +809,13 @@ void _interpret_voip_menu(char *cmd) g_menu_preset = PRESET_DOUBLE_VOIP_SERVER; g_menu_state = MENU_STATE_PRESET_MENU; } else if (!strncmp(cmd, "4", len)) { - /*double Server 2 */ - g_menu_preset = PRESET_DOUBLE_VOIP_SERVER_2; - g_menu_state = MENU_STATE_PRESET_MENU; - } else if (!strncmp(cmd, "5", len)) { /*double Client 1 */ g_menu_preset = PRESET_DOUBLE_VOIP_CLIENT; g_menu_state = MENU_STATE_PRESET_MENU; + } else if (!strncmp(cmd, "5", len)) { + /*double Server 2 */ + g_menu_preset = PRESET_DOUBLE_VOIP_SERVER_2; + g_menu_state = MENU_STATE_PRESET_MENU; } else if (!strncmp(cmd, "6", len)) { /*double Client 2 */ g_menu_preset = PRESET_DOUBLE_VOIP_CLIENT_2; @@ -752,7 +900,6 @@ void _interpret_preset_menu(char *cmd) _play(g_media_streamer); } else if (!strncmp(cmd, "7", len)) { _destroy(current_media_streamer); - current_media_streamer = NULL; } else if (!strncmp(cmd, "b", len)) { if (g_menu_preset & DOUBLE_STREAMER_MASK) { g_menu_state = MENU_STATE_VOIP_MENU; -- 2.7.4