--- /dev/null
+Satheesan E N <satheesan.en@samsung.com>\r
+Joungkook Seo <jk7704.seo@samsung.com>\r
--- /dev/null
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(fw_name "capi-mediamuxer")
+
+PROJECT(${fw_name})
+
+SET(CMAKE_INSTALL_PREFIX /usr)
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+
+SET(INC_DIR include)
+SET(INC_PORT_GST_DIR include/port_gst)
+SET(INC_PORT_CUSTOM_DIR include/port_custom)
+SET(INC_PORT_FFMPEG_DIR include/port_ffmpeg)
+INCLUDE_DIRECTORIES(${INC_DIR} ${INC_PORT_GST_DIR} ${INC_PORT_CUSTOM_DIR} ${INC_PORT_FFMPEG_DIR})
+
+SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0")
+SET(pc_dependents "capi-base-common capi-media-tool")
+
+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} -Wall -Werror")
+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=${LIB_INSTALL_DIR}")
+
+AUX_SOURCE_DIRECTORY (src MAIN_SRC)
+AUX_SOURCE_DIRECTORY (src/port_gst PORT_GST_SRC)
+AUX_SOURCE_DIRECTORY (src/port_custom PORT_CUST_SRC)
+AUX_SOURCE_DIRECTORY (src/port_ffmpeg PORT_FFMPEG_SRC)
+
+LIST (APPEND SOURCES
+ ${MAIN_SRC}
+ ${PORT_FFMPEG_SRC}
+ ${PORT_CUST_SRC}
+ ${PORT_GST_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_DIR})
+INSTALL(
+ DIRECTORY ${INC_DIR}/ DESTINATION include/media
+ FILES_MATCHING
+ PATTERN "mediamuxer_*.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)
+
--- /dev/null
+Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.\r
+\r
+ Apache License\r
+ Version 2.0, January 2004\r
+ http://www.apache.org/licenses/\r
+\r
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r
+\r
+ 1. Definitions.\r
+\r
+ "License" shall mean the terms and conditions for use, reproduction,\r
+ and distribution as defined by Sections 1 through 9 of this document.\r
+\r
+ "Licensor" shall mean the copyright owner or entity authorized by\r
+ the copyright owner that is granting the License.\r
+\r
+ "Legal Entity" shall mean the union of the acting entity and all\r
+ other entities that control, are controlled by, or are under common\r
+ control with that entity. For the purposes of this definition,\r
+ "control" means (i) the power, direct or indirect, to cause the\r
+ direction or management of such entity, whether by contract or\r
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the\r
+ outstanding shares, or (iii) beneficial ownership of such entity.\r
+\r
+ "You" (or "Your") shall mean an individual or Legal Entity\r
+ exercising permissions granted by this License.\r
+\r
+ "Source" form shall mean the preferred form for making modifications,\r
+ including but not limited to software source code, documentation\r
+ source, and configuration files.\r
+\r
+ "Object" form shall mean any form resulting from mechanical\r
+ transformation or translation of a Source form, including but\r
+ not limited to compiled object code, generated documentation,\r
+ and conversions to other media types.\r
+\r
+ "Work" shall mean the work of authorship, whether in Source or\r
+ Object form, made available under the License, as indicated by a\r
+ copyright notice that is included in or attached to the work\r
+ (an example is provided in the Appendix below).\r
+\r
+ "Derivative Works" shall mean any work, whether in Source or Object\r
+ form, that is based on (or derived from) the Work and for which the\r
+ editorial revisions, annotations, elaborations, or other modifications\r
+ represent, as a whole, an original work of authorship. For the purposes\r
+ of this License, Derivative Works shall not include works that remain\r
+ separable from, or merely link (or bind by name) to the interfaces of,\r
+ the Work and Derivative Works thereof.\r
+\r
+ "Contribution" shall mean any work of authorship, including\r
+ the original version of the Work and any modifications or additions\r
+ to that Work or Derivative Works thereof, that is intentionally\r
+ submitted to Licensor for inclusion in the Work by the copyright owner\r
+ or by an individual or Legal Entity authorized to submit on behalf of\r
+ the copyright owner. For the purposes of this definition, "submitted"\r
+ means any form of electronic, verbal, or written communication sent\r
+ to the Licensor or its representatives, including but not limited to\r
+ communication on electronic mailing lists, source code control systems,\r
+ and issue tracking systems that are managed by, or on behalf of, the\r
+ Licensor for the purpose of discussing and improving the Work, but\r
+ excluding communication that is conspicuously marked or otherwise\r
+ designated in writing by the copyright owner as "Not a Contribution."\r
+\r
+ "Contributor" shall mean Licensor and any individual or Legal Entity\r
+ on behalf of whom a Contribution has been received by Licensor and\r
+ subsequently incorporated within the Work.\r
+\r
+ 2. Grant of Copyright License. Subject to the terms and conditions of\r
+ this License, each Contributor hereby grants to You a perpetual,\r
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+ copyright license to reproduce, prepare Derivative Works of,\r
+ publicly display, publicly perform, sublicense, and distribute the\r
+ Work and such Derivative Works in Source or Object form.\r
+\r
+ 3. Grant of Patent License. Subject to the terms and conditions of\r
+ this License, each Contributor hereby grants to You a perpetual,\r
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+ (except as stated in this section) patent license to make, have made,\r
+ use, offer to sell, sell, import, and otherwise transfer the Work,\r
+ where such license applies only to those patent claims licensable\r
+ by such Contributor that are necessarily infringed by their\r
+ Contribution(s) alone or by combination of their Contribution(s)\r
+ with the Work to which such Contribution(s) was submitted. If You\r
+ institute patent litigation against any entity (including a\r
+ cross-claim or counterclaim in a lawsuit) alleging that the Work\r
+ or a Contribution incorporated within the Work constitutes direct\r
+ or contributory patent infringement, then any patent licenses\r
+ granted to You under this License for that Work shall terminate\r
+ as of the date such litigation is filed.\r
+\r
+ 4. Redistribution. You may reproduce and distribute copies of the\r
+ Work or Derivative Works thereof in any medium, with or without\r
+ modifications, and in Source or Object form, provided that You\r
+ meet the following conditions:\r
+\r
+ (a) You must give any other recipients of the Work or\r
+ Derivative Works a copy of this License; and\r
+\r
+ (b) You must cause any modified files to carry prominent notices\r
+ stating that You changed the files; and\r
+\r
+ (c) You must retain, in the Source form of any Derivative Works\r
+ that You distribute, all copyright, patent, trademark, and\r
+ attribution notices from the Source form of the Work,\r
+ excluding those notices that do not pertain to any part of\r
+ the Derivative Works; and\r
+\r
+ (d) If the Work includes a "NOTICE" text file as part of its\r
+ distribution, then any Derivative Works that You distribute must\r
+ include a readable copy of the attribution notices contained\r
+ within such NOTICE file, excluding those notices that do not\r
+ pertain to any part of the Derivative Works, in at least one\r
+ of the following places: within a NOTICE text file distributed\r
+ as part of the Derivative Works; within the Source form or\r
+ documentation, if provided along with the Derivative Works; or,\r
+ within a display generated by the Derivative Works, if and\r
+ wherever such third-party notices normally appear. The contents\r
+ of the NOTICE file are for informational purposes only and\r
+ do not modify the License. You may add Your own attribution\r
+ notices within Derivative Works that You distribute, alongside\r
+ or as an addendum to the NOTICE text from the Work, provided\r
+ that such additional attribution notices cannot be construed\r
+ as modifying the License.\r
+\r
+ You may add Your own copyright statement to Your modifications and\r
+ may provide additional or different license terms and conditions\r
+ for use, reproduction, or distribution of Your modifications, or\r
+ for any such Derivative Works as a whole, provided Your use,\r
+ reproduction, and distribution of the Work otherwise complies with\r
+ the conditions stated in this License.\r
+\r
+ 5. Submission of Contributions. Unless You explicitly state otherwise,\r
+ any Contribution intentionally submitted for inclusion in the Work\r
+ by You to the Licensor shall be under the terms and conditions of\r
+ this License, without any additional terms or conditions.\r
+ Notwithstanding the above, nothing herein shall supersede or modify\r
+ the terms of any separate license agreement you may have executed\r
+ with Licensor regarding such Contributions.\r
+\r
+ 6. Trademarks. This License does not grant permission to use the trade\r
+ names, trademarks, service marks, or product names of the Licensor,\r
+ except as required for reasonable and customary use in describing the\r
+ origin of the Work and reproducing the content of the NOTICE file.\r
+\r
+ 7. Disclaimer of Warranty. Unless required by applicable law or\r
+ agreed to in writing, Licensor provides the Work (and each\r
+ Contributor provides its Contributions) on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r
+ implied, including, without limitation, any warranties or conditions\r
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r
+ PARTICULAR PURPOSE. You are solely responsible for determining the\r
+ appropriateness of using or redistributing the Work and assume any\r
+ risks associated with Your exercise of permissions under this License.\r
+\r
+ 8. Limitation of Liability. In no event and under no legal theory,\r
+ whether in tort (including negligence), contract, or otherwise,\r
+ unless required by applicable law (such as deliberate and grossly\r
+ negligent acts) or agreed to in writing, shall any Contributor be\r
+ liable to You for damages, including any direct, indirect, special,\r
+ incidental, or consequential damages of any character arising as a\r
+ result of this License or out of the use or inability to use the\r
+ Work (including but not limited to damages for loss of goodwill,\r
+ work stoppage, computer failure or malfunction, or any and all\r
+ other commercial damages or losses), even if such Contributor\r
+ has been advised of the possibility of such damages.\r
+\r
+ 9. Accepting Warranty or Additional Liability. While redistributing\r
+ the Work or Derivative Works thereof, You may choose to offer,\r
+ and charge a fee for, acceptance of support, warranty, indemnity,\r
+ or other liability obligations and/or rights consistent with this\r
+ License. However, in accepting such obligations, You may act only\r
+ on Your own behalf and on Your sole responsibility, not on behalf\r
+ of any other Contributor, and only if You agree to indemnify,\r
+ defend, and hold each Contributor harmless for any liability\r
+ incurred by, or claims asserted against, such Contributor by reason\r
+ of your accepting any such warranty or additional liability.\r
+\r
+ END OF TERMS AND CONDITIONS\r
+\r
+ APPENDIX: How to apply the Apache License to your work.\r
+\r
+ To apply the Apache License to your work, attach the following\r
+ boilerplate notice, with the fields enclosed by brackets "[]"\r
+ replaced with your own identifying information. (Don't include\r
+ the brackets!) The text should be enclosed in the appropriate\r
+ comment syntax for the file format. We also recommend that a\r
+ file or class name and description of purpose be included on the\r
+ same "printed page" as the copyright notice for easier\r
+ identification within third-party archives.\r
+\r
+ Copyright [yyyy] [name of copyright owner]\r
+\r
+ Licensed under the Apache License, Version 2.0 (the "License");\r
+ you may not use this file except in compliance with the License.\r
+ You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
--- /dev/null
+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.
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+</manifest>
--- /dev/null
+# Package Information for pkg-config
+
+prefix=@PREFIX@
+exec_prefix=/usr
+libdir=@LIB_INSTALL_DIR@
+includedir=/usr/include/media
+
+Name: @PC_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @VERSION@
+Requires: @PC_REQUIRED@
+Libs: -L${libdir} @PC_LDFLAGS@
+Cflags: -I${includedir}
\ No newline at end of file
--- /dev/null
+/*
+ * 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_MEDIAMUXER_DOC_H__
+#define __TIZEN_MEDIAMUXER_DOC_H__
+
+/**
+ * @file mediamuxer_doc.h
+ * @brief This file contains high level documentation of the CAPI MEDIAMUXER.
+ */
+
+/**
+ * @ingroup CAPI_MEDIA_FRAMEWORK
+ * @defgroup CAPI_MEDIAMUXER_MODULE Media Muxer
+ * @brief The @ref CAPI_MEDIAMUXER_MODULE APIs provides functions for muxing media data
+ *
+ * @section CAPI_MEDIAMUXER_MODULE_HEADER Required Header
+ * \#include <mediamuxer.h>
+ *
+ * @section CAPI_MEDIAMUXER_MODULE_OVERVIEW Overview
+ *
+ * MEDIAMUXER API set allows :
+ * The API set allows one to directly access media muxer on device.
+ * Application can create, add relevent media track(s) and write corresponding
+ * samples to get muxed media files. mediamuxer takes encoded media as input
+ * and gives muxed media in a compatable container format.
+ *
+ * Typical Call Flow of mediamuxer APIs is:
+ * mediamuxer_create()
+ * mediamuxer_set_data_sink()
+ * mediamuxer_add_track(1)
+ * mediamuxer_add_track(2) [add more tracks, if needed]
+ * mediamuxer_start()
+ * while()
+ * if (is_track(1)_data_available)
+ * mediamuxer_write_sample(track(1)),
+ * else
+ * mediamuxer_close_track(1)
+ * if (is_track(2)_data_available)
+ * mediamuxer_write_sample(track(2))
+ * else
+ * mediamuxer_close_track(2)
+ * mediamuxer_stop()
+ * mediamuxer_destroy()
+ */
+
+#endif /* __TIZEN_MEDIAMUXER_DOC_H__ */
--- /dev/null
+/*
+ * 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_MEDIAMUXER_H__
+#define __TIZEN_MEDIAMUXER_H__
+
+#include <tizen.h>
+#include <stdint.h>
+#include <media_format.h>
+#include <media_packet.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef TIZEN_ERROR_MEDIA_MUXER
+#define TIZEN_ERROR_MEDIA_MUXER -0x05000000
+#endif
+
+/**
+* @file mediamuxer.h
+* @brief This file contains the capi media muxer API.
+*/
+
+/**
+* @addtogroup CAPI_MEDIAMUXER_MODULE
+* @
+*/
+
+/**
+ * @brief Media Muxer handle type
+ * @since_tizen 3.0
+ */
+typedef struct mediamuxer_s *mediamuxer_h;
+
+/**
+ * @brief Enumeration for media muxer state
+ * @since_tizen 3.0
+ */
+typedef enum {
+ MEDIAMUXER_STATE_NONE, /**< The mediamuxer is not created */
+ MEDIAMUXER_STATE_IDLE, /**< The mediamuxer is created, but not prepared */
+ MEDIAMUXER_STATE_READY, /**< The mediamuxer is ready to mux media */
+ MEDIAMUXER_STATE_MUXING, /**< The mediamuxer is muxing media */
+ MEDIAMUXER_STATE_PAUSED /**< The mediamuxer is paused while muxing media */
+} mediamuxer_state_e;
+
+/**
+ * @brief Enumeration for media muxer error
+ * @since_tizen 3.0
+ */
+typedef enum {
+ MEDIAMUXER_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */
+ MEDIAMUXER_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY,
+ MEDIAMUXER_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */
+ MEDIAMUXER_ERROR_INVALID_OPERATION = TIZEN_ERROR_INVALID_OPERATION, /**< Invalid operation */
+ MEDIAMUXER_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Not supported */
+ MEDIAMUXER_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */
+ MEDIAMUXER_ERROR_INVALID_STATE = TIZEN_ERROR_MEDIA_MUXER | 0x01, /**< Invalid state */
+ MEDIAMUXER_ERROR_INVALID_PATH = TIZEN_ERROR_MEDIA_MUXER | 0x02, /**< Invalid path */
+ MEDIAMUXER_ERROR_RESOURCE_LIMIT = TIZEN_ERROR_MEDIA_MUXER | 0x03 /**< Resource limit */
+} mediamuxer_error_e;
+
+/**
+ * @brief Enumeration for media muxer output format
+ * @since_tizen 3.0
+ */
+typedef enum {
+ MEDIAMUXER_CONTAINER_FORMAT_MP4 = MEDIA_FORMAT_CONTAINER_MP4, /**< The mediamuxer output format is MP4 container */
+} mediamuxer_output_format_e;
+
+/**
+ * @brief Called when error occurs in media muxer.
+ * @details Following error codes can be delivered.
+ * #MEDIAMUXER_ERROR_INVALID_OPERATION,
+ * #MEDIAMUXER_ERROR_NOT_SUPPORTED,
+ * #MEDIAMUXER_ERROR_INVALID_PATH,
+ * #MEDIAMUXER_ERROR_RESOURCE_LIMIT
+ * @since_tizen 3.0
+ * @param[in] error The error that occurred in media muxer
+ * @param[in] user_data The user data passed from the code where
+ * mediamuxer_set_error_cb() was invoked
+ * This data will be accessible from @a mediamuxer_error_cb
+ * @pre Create media muxer handle by calling mediamuxer_create() function.
+ * @see mediamuxer_set_error_cb()
+ * @see mediamuxer_unset_error_cb()
+ */
+typedef void (*mediamuxer_error_cb)(mediamuxer_error_e error, void *user_data);
+
+/**
+ * @brief Creates a media muxer handle for muxing.
+ * @since_tizen 3.0
+ * @param[out] muxer A new handle to media muxer
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @post The media muxer state will be #MEDIAMUXER_STATE_IDLE.
+ * @see mediamuxer_destroy()
+ */
+int mediamuxer_create(mediamuxer_h *muxer);
+
+/**
+ * @brief Sets the sink path of output stream.
+ * @since_tizen 3.0
+ * @remarks The mediastorage privilege(http://tizen.org/privilege/mediastorage) should be added if any video/audio files are to be saved in the internal storage.
+ * @remarks The externalstorage privilege(http://tizen.org/privilege/externalstorage) should be added if any video/audio files are to be saved in the external storage.
+ * @param[in] muxer A new handle to media muxer
+ * @param[in] path The location of the output media file, such as the file path
+ This is the path at which the muxed file should be saved.
+ * @param[in] format The format of the output media file
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state
+ * @retval #MEDIAMUXER_ERROR_PERMISSION_DENIED Permission denied
+ * @retval #MEDIAMUXER_ERROR_INVALID_PATH Invalid path
+ * @pre The media muxer state will be #MEDIAMUXER_STATE_IDLE by calling mediamuxer_create
+ * @see #mediamuxer_output_format_e
+ */
+int mediamuxer_set_data_sink(mediamuxer_h muxer, char *path, mediamuxer_output_format_e format);
+
+/**
+ * @brief Adds the media track of interest to the muxer handle.
+ * @since_tizen 3.0
+ * @param[in] muxer The media muxer handle
+ * @param[in] media_format The format of media muxer
+ * @param[out] track_index The index of the media track
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state
+ * @pre The media muxer state must be set to #MEDIAMUXER_STATE_IDLE.
+ * @see #media_format_h
+ * @see mediamuxer_create()
+ * @see mediamuxer_start()
+ * */
+int mediamuxer_add_track(mediamuxer_h muxer, media_format_h media_format, int *track_index);
+
+/**
+ * @brief Starts the media muxer.
+ * @remarks Initiates the necessary parameters, and keeps the muxer ready for writing data.
+ * @since_tizen 3.0
+ * @param[in] muxer The media muxer handle
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state
+ * @pre The media muxer state must be set to #MEDIAMUXER_STATE_IDLE.
+ * @post The media muxer state will be #MEDIAMUXER_STATE_READY.
+ * @see mediamuxer_create()
+ * @see mediamuxer_stop()
+ * */
+int mediamuxer_start(mediamuxer_h muxer);
+
+/**
+ * @brief Writes the media packet of interest to the muxer handle.
+ * @since_tizen 3.0
+ * @param[in] muxer The media muxer handle
+ * @param[in] track_index The index of the media track
+ * @param[in] inbuf The packet of media muxer
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state
+ * @pre The media muxer state must be set to #MEDIAMUXER_STATE_READY by calling mediamuxer_start() or
+ * set to #MEDIAMUXER_STATE_PAUSED by calling mediamuxer_pause().
+ * @post The media muxer state will be #MEDIAMUXER_STATE_MUXING.
+ * @see mediamuxer_start()
+ * @see mediamuxer_close_track()
+ * @see mediamuxer_pause()
+ * @see #media_packet_h
+ * */
+int mediamuxer_write_sample(mediamuxer_h muxer, int track_index, media_packet_h inbuf);
+
+/**
+ * @brief Closes the track from further writing of data.
+ * @remarks For each added track, user needs to call this API to indicate the end of stream.
+ * @since_tizen 3.0
+ * @param[in] muxer The media muxer handle
+ * @param[in] track_index the selected track index
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state
+ * @pre The media muxer state must be set to #MEDIAMUXER_STATE_MUXING.
+ * @see mediamuxer_write_sample()
+ * @see mediamuxer_pause()
+ * @see mediamuxer_stop()
+ * @see #mediamuxer_error_e
+ * */
+int mediamuxer_close_track(mediamuxer_h muxer, int track_index);
+
+/**
+ * @brief Pauses the media muxer.
+ * @remarks To temporarily disable writing data for muxing. This API pauses a playing muxer
+ If the prior state of the muxer is not in PLAYING, no action will be taken.
+ * @since_tizen 3.0
+ * @param[in] muxer The media muxer handle
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state
+ * @pre The media muxer state must be set to #MEDIAMUXER_STATE_MUXING.
+ * @post The media muxer state will be #MEDIAMUXER_STATE_PAUSED.
+ * @see mediamuxer_write_sample()
+ * @see mediamuxer_resume()
+ * */
+int mediamuxer_pause(mediamuxer_h muxer);
+
+/**
+ * @brief Resumes the media muxer.
+ * @remarks Make it ready for any further writing. This API will resume a paused muxer.
+ If the prior state of the muxer is not playing, no action will be taken.
+ * @since_tizen 3.0
+ * @param[in] muxer The media muxer handle
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state
+ * @pre The media muxer state must be set to #MEDIAMUXER_STATE_PAUSED.
+ * @post The media muxer state will be #MEDIAMUXER_STATE_MUXING.
+ * @see mediamuxer_pause()
+ * */
+int mediamuxer_resume(mediamuxer_h muxer);
+
+/**
+ * @brief Stops the media muxer.
+ * @remarks Unrefs the variables created after calling mediamuxer_start().
+ * @since_tizen 3.0
+ * @param[in] muxer The media muxer handle
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state
+ * @pre The media muxer state must be set to #MEDIAMUXER_STATE_MUXING by calling mediamuxer_start() or
+ * set to #MEDIAMUXER_STATE_PAUSED by calling mediamuxer_pause().
+ * @post The media muxer state will be #MEDIAMUXER_STATE_IDLE.
+ * @see mediamuxer_write_sample()
+ * @see mediamuxer_pause()
+ * @see mediamuxer_destroy()
+ * */
+int mediamuxer_stop(mediamuxer_h muxer);
+
+/**
+ * @brief Removes the instance of media muxer and clear all its context memory.
+ * @since_tizen 3.0
+ * @param[in] muxer The media muxer handle
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIAMUXER_ERROR_INVALID_STATE Invalid state
+ * @pre Create a media muxer handle by calling mediamuxer_create() function.
+ * @post The media muxer state will be #MEDIAMUXER_STATE_NONE.
+ * @see mediamuxer_create()
+ * */
+int mediamuxer_destroy(mediamuxer_h muxer);
+
+/**
+ * @brief Gets media muxer state.
+ * @since_tizen 3.0
+ * @param[in] muxer The media muxer handle
+ * @param[out] state The media muxer sate
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIAMUXER_ERROR_INVALID_OPERATION Invalid operation
+ * @pre Create a media muxer handle by calling mediamuxer_create() function.
+ * @see #mediamuxer_state_e
+ * */
+int mediamuxer_get_state(mediamuxer_h muxer, mediamuxer_state_e *state);
+
+/**
+ * @brief Registers a error callback function to be invoked when an error occurs.
+ * @details Following error codes can be delivered.
+ * #MEDIAMUXER_ERROR_INVALID_OPERATION,
+ * #MEDIAMUXER_ERROR_NOT_SUPPORTED,
+ * #MEDIAMUXER_ERROR_INVALID_PATH,
+ * #MEDIAMUXER_ERROR_RESOURCE_LIMIT
+ * @since_tizen 3.0
+ * @param[in] muxer The media muxer handle
+ * @param[in] callback Callback function pointer
+ * @param[in] user_data The user data passed from the code where
+ * mediamuxer_set_error_cb() was invoked
+ * This data will be accessible from @a mediamuxer_error_cb
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @pre Create a media muxer handle by calling mediamuxer_create() function.
+ * @post mediamuxer_error_cb() will be invoked.
+ * @see mediamuxer_unset_error_cb()
+ * @see mediamuxer_error_cb()
+ * */
+int mediamuxer_set_error_cb(mediamuxer_h muxer, mediamuxer_error_cb callback, void* user_data);
+
+/**
+ * @brief Unregisters the error callback function.
+ * @since_tizen 3.0
+ * @param[in] muxer The media muxer handle
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIAMUXER_ERROR_NONE Successful
+ * @retval #MEDIAMUXER_ERROR_INVALID_PARAMETER Invalid parameter
+ * @see mediamuxer_error_cb()
+ * */
+int mediamuxer_unset_error_cb(mediamuxer_h muxer);
+
+/**
+ * @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TIZEN_MEDIAMUXER_H__ */
--- /dev/null
+/*
+ * 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_MEDIAMUXER_ERROR_H__
+#define __TIZEN_MEDIAMUXER_ERROR_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**< Definition of number describing error group */
+#define MX_ERROR_CLASS 0x80000000
+/**< Category for describing common error group */
+#define MX_ERROR_COMMON_CLASS 0x80000100
+/**< Category for describing gst_port error group */
+#define MX_ERROR_GST_PORT_CLASS 0x80000200
+/**< Category for describing ffmpeg port error group */
+#define MX_ERROR_FFMPEG_PORT_CLASS 0x80000300
+/**< Category for describing custom error group */
+#define MX_ERROR_CUSTOM_PORT_CLASS 0x80000400
+
+/*
+ MX_ERROR_CLASS
+ */
+/**< Unclassified error */
+#define MX_ERROR_UNKNOWN (MX_ERROR_CLASS | 0x00)
+/**< Invalid argument */
+#define MX_ERROR_INVALID_ARGUMENT (MX_ERROR_CLASS | 0x01)
+/**< Out of memory */
+#define MX_ERROR_OUT_OF_MEMORY (MX_ERROR_CLASS | 0x02)
+/**< Out of storage */
+#define MX_ERROR_OUT_OF_STORAGE (MX_ERROR_CLASS | 0x03)
+/**< Invalid handle */
+#define MX_ERROR_INVALID_HANDLE (MX_ERROR_CLASS | 0x04)
+/**< Cannot find file */
+#define MX_ERROR_FILE_NOT_FOUND (MX_ERROR_CLASS | 0x05)
+/**< Fail to read data from file */
+#define MX_ERROR_FILE_READ (MX_ERROR_CLASS | 0x06)
+/**< Fail to write data to file */
+#define MX_ERROR_FILE_WRITE (MX_ERROR_CLASS | 0x07)
+/**< End of file */
+#define MX_ERROR_END_OF_FILE (MX_ERROR_CLASS | 0x08)
+/**< Not supported API*/
+#define MX_ERROR_NOT_SUPPORT_API (MX_ERROR_CLASS | 0x09)
+/**< port regitstration failed error */
+#define MX_ERROR_PORT_REG_FAILED (MX_ERROR_CLASS | 0x0a)
+
+/*
+ MX_ERROR_COMMON_CLASS
+ */
+/**< Invalid argument */
+#define MX_ERROR_COMMON_INVALID_ARGUMENT (MX_ERROR_COMMON_CLASS | 1)
+/**< Out of storage */
+#define MX_ERROR_COMMON_NO_FREE_SPACE (MX_ERROR_COMMON_CLASS | 2)
+/**< Out of memory */
+#define MX_ERROR_COMMON_OUT_OF_MEMORY (MX_ERROR_COMMON_CLASS | 3)
+/**< Unknown error */
+#define MX_ERROR_COMMON_UNKNOWN (MX_ERROR_COMMON_CLASS | 4)
+/**< Invalid argument */
+#define MX_ERROR_COMMON_INVALID_ATTRTYPE (MX_ERROR_COMMON_CLASS | 5)
+/**< Invalid permission */
+#define MX_ERROR_COMMON_INVALID_PERMISSION (MX_ERROR_COMMON_CLASS | 6)
+/**< Out of array */
+#define MX_ERROR_COMMON_OUT_OF_ARRAY (MX_ERROR_COMMON_CLASS | 7)
+/**< Out of value range*/
+#define MX_ERROR_COMMON_OUT_OF_RANGE (MX_ERROR_COMMON_CLASS | 8)
+/**< Attribute doesn't exist. */
+#define MX_ERROR_COMMON_ATTR_NOT_EXIST (MX_ERROR_COMMON_CLASS | 9)
+
+/*
+ * MX_ERROR_GST_PORT_CLASS
+ */
+/**< GST Port instance is not initialized */
+#define MX_ERROR_GST_PORT_NOT_INITIALIZED (MX_ERROR_GST_PORT_CLASS | 0x01)
+
+/*
+ MX_ERROR_FFMPEG_PORT_CLASS
+ */
+/**< FFMPEG Port instance is not initialized */
+#define MX_ERROR_FFMPEG_PORT_NOT_INITIALIZED (MX_ERROR_FFMPEG_PORT_CLASS | 0x01)
+
+/*
+ MX_ERROR_CUSTOM_PORT_CLASS
+ */
+/**< CUSTOM Port instance is not initialized */
+#define MX_ERROR_CUSTOM_PORT_NOT_INITIALIZED MX_ERROR_CUSTOM_PORT_CLASS | 0x01)
+
+typedef enum {
+ MX_ERROR_NONE = 0,
+ MX_ERROR = -1, /**< muxer happens error */
+ MX_MEMORY_ERROR = -2, /**< muxer memory is not enough */
+ MX_PARAM_ERROR = -3, /**< muxer parameter is error */
+ MX_INVALID_ARG = -4, /**< muxer has invalid arguments */
+ MX_PERMISSION_DENIED = -5,
+ MX_INVALID_STATUS = -6, /**< muxer works at invalid status */
+ MX_NOT_SUPPORTED = -7, /**< muxer can't support this specific video format */
+ MX_INVALID_IN_BUF = -8,
+ MX_INVALID_OUT_BUF = -9,
+ MX_INTERNAL_ERROR = -10,
+ MX_HW_ERROR = -11, /**< muxer happens hardware error */
+ MX_NOT_INITIALIZED = -12,
+ MX_INVALID_STREAM = -13,
+ MX_OUTPUT_BUFFER_EMPTY = -14,
+ MX_OUTPUT_BUFFER_OVERFLOW = -15,/**< muxer output buffer is overflow */
+ MX_MEMORY_ALLOCED = -16, /**< muxer has got memory and can decode one frame */
+ MX_COURRPTED_INI = -17, /**< value in the ini file is not valid */
+} mx_ret_e;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TIZEN_MEDIAMUXER_ERROR_H__ */
--- /dev/null
+/*
+ * 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_MEDIAMUXER_INI_H__
+#define __TIZEN_MEDIAMUXER_INI_H__
+
+#include <glib.h>
+#include <mm_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MEDIAMUXER_INI_DEFAULT_PATH "/usr/etc/mmfw_mediamuxer.ini"
+#define MEDIAMUXER_INI_MAX_STRLEN 100
+#define DEFAULT_PORT "GST_PORT"
+
+/* NOTE : following content should be same with above default values */
+/* FIXIT : need smarter way to generate default ini file. */
+/* FIXIT : finally, it should be an external file */
+#define MEDIAMUXER_DEFAULT_INI \
+ "\
+[general] \n\
+\n\
+;Add general config parameters here\n\
+\n\
+\n\
+\n\
+[port_in_use] \n\
+\n\
+;mediamuxer_port = GST_PORT \n\
+;mediamuxer_port = FFMPEG_PORT \n\
+;mediamuxer_port = CUSTOM_PORT \n\
+mediamuxer_port = GST_PORT \n\
+\n\
+[gst_port] \n\
+\n\
+;Add gst port specific config paramters here\n\
+\n\
+\n\
+[ffmpeg_port] \n\
+\n\
+;Add ffmpeg port specific config paramters here\n\
+\n\
+\n\
+[custom_port] \n\
+\n\
+;Add custom port specific config paramters here\n\
+\n\
+\n\
+\n\
+"
+
+typedef enum {
+ GST_PORT = 0,
+ FFMPEG_PORT,
+ CUSTOM_PORT,
+} port_mode;
+
+/* @ mark means the item has tested */
+typedef struct __mx_ini {
+ port_mode port_type;
+ /* general */
+ gchar port_name[MEDIAMUXER_INI_MAX_STRLEN];
+} mx_ini_t;
+
+int mx_ini_load(mx_ini_t *ini);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*__TIZEN_MEDIAMUXER_INI_H__*/
--- /dev/null
+/*
+ * 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_MEDIAMUXER_PORT_H__
+#define __TIZEN_MEDIAMUXER_PORT_H__
+
+/*=============================================================================
+| |
+| INCLUDE FILES |
+| |
+==============================================================================*/
+
+#include <glib.h>
+#include <mm_types.h>
+#include <mm_message.h>
+#include <mediamuxer_util.h>
+#include <mediamuxer.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ @addtogroup MEDIAMUXER
+ @{
+
+ @par
+ This part describes APIs used for playback of multimedia contents.
+ All multimedia contents are created by a media muxer through handle of
+ playback. In creating a muxer, it displays the muxer's status or information
+ by registering callback function.
+
+ @par
+ In case of streaming playback, network has to be opend by using datanetwork
+ API. If proxy, cookies and the other attributes for streaming playback are
+ needed, set those attributes using mx_set_attribute() before create muxer.
+
+ @par
+ The subtitle for local video playback is supported. Set "subtitle_uri"
+ attribute using mx_set_attribute() before the application creates the muxer.
+ Then the application could receive MMMessageParamType which includes
+ subtitle string and duration.
+
+ @par
+ MediaMuxer can have 5 states, and each state can be changed by calling
+ described functions on "Figure1. State of MediaMuxer".
+
+ @par
+ @image html muxer_state.jpg "Figure1. State of MediaMuxer" width=12cm
+ @image latex muxer_state.jpg "Figure1. State of MediaMuxer" width=12cm
+
+ @par
+ Most of functions which change muxer state work as synchronous. But,
+ mx_start() should be used asynchronously. Both mx_pause() and mx__resume()
+ should also be used asynchronously in the case of streaming data.
+ So, application have to confirm the result of those APIs through message
+ callback function.
+
+ @par
+ Note that "None" and Null" state could be reached from any state
+ by calling mx_destroy() and mx_unrealize().
+
+ @par
+ <div><table>
+ <tr>
+ <td><B>FUNCTION</B></td>
+ <td><B>PRE-STATE</B></td>
+ <td><B>POST-STATE</B></td>
+ <td><B>SYNC TYPE</B></td>
+ </tr>
+ <tr>
+ <td>mx_create()</td>
+ <td>NONE</td>
+ <td>NULL</td>
+ <td>SYNC</td>
+ </tr>
+ <tr>
+ <td>mx_destroy()</td>
+ <td>NULL</td>
+ <td>NONE</td>
+ <td>SYNC</td>
+ </tr>
+ <tr>
+ <td>mx_set_data_sink()</td>
+ <td>NULL</td>
+ <td>READY</td>
+ <td>SYNC</td>
+ </tr>
+ </table></div>
+
+ @par
+ Following are the attributes supported in muxer which may be set after
+ initialization. Those are handled as a string.
+
+ @par
+ <div><table>
+ <tr>
+ <td>PROPERTY</td>
+ <td>TYPE</td>
+ <td>VALID TYPE</td>
+ </tr>
+ <tr>
+ <td>"profile_uri"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"content_duration"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ <tr>
+ <td>"content_video_width"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ <tr>
+ <td>"content_video_height"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ <tr>
+ <td>"profile_user_param"</td>
+ <td>data</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"profile_play_count"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ <tr>
+ <td>"streaming_type"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ <tr>
+ <td>"streaming_udp_timeout"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ <tr>
+ <td>"streaming_user_agent"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"streaming_wap_profile"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"streaming_network_bandwidth"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ <tr>
+ <td>"streaming_cookie"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"streaming_proxy_ip"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"streaming_proxy_port"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ <tr>
+ <td>"subtitle_uri"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ </table></div>
+
+ @par
+ Following attributes are supported for playing stream data. Those value can
+ be readable only and valid after starting playback.
+ Please use mm_fileinfo for local playback.
+
+ @par
+ <div><table>
+ <tr>
+ <td>PROPERTY</td>
+ <td>TYPE</td>
+ <td>VALID TYPE</td>
+ </tr>
+ <tr>
+ <td>"content_video_found"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"content_video_codec"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"content_video_track_num"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ <tr>
+ <td>"content_audio_found"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"content_audio_codec"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"content_audio_bitrate"</td>
+ <td>int</td>
+ <td>array</td>
+ </tr>
+ <tr>
+ <td>"content_audio_channels"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ <tr>
+ <td>"content_audio_samplerate"</td>
+ <td>int</td>
+ <td>array</td>
+ </tr>
+ <tr>
+ <td>"content_audio_track_num"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ <tr>
+ <td>"content_text_track_num"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ <tr>
+ <td>"tag_artist"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"tag_title"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"tag_album"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"tag_genre"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"tag_author"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"tag_copyright"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"tag_date"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"tag_description"</td>
+ <td>string</td>
+ <td>N/A</td>
+ </tr>
+ <tr>
+ <td>"tag_track_num"</td>
+ <td>int</td>
+ <td>range</td>
+ </tr>
+ </table></div>
+
+ */
+
+/*=============================================================================|
+| |
+| GLOBAL DEFINITIONS AND DECLARATIONS |
+| |
+==============================================================================*/
+/**
+ * @brief Called when error occurs in media muxer.
+ * @details Following error codes can be delivered.
+ * #MEDIAMUXER_ERROR_INVALID_OPERATION,
+ * #MEDIAMUXER_ERROR_NOT_SUPPORTED,
+ * #MEDIAMUXER_ERROR_INVALID_PATH,
+ * #MEDIAMUXER_ERROR_RESOURCE_LIMIT
+ * @since_tizen 3.0
+ * @param[in] error The error that occurred in media muxer
+ * @param[in] user_data The user data passed from the code where
+ * mediamuxer_set_error_cb() was invoked
+ * This data will be accessible from @a mediamuxer_error_cb
+ * @pre Create media muxer handle by calling mediamuxer_create() function.
+ * @see mediamuxer_set_error_cb()
+ * @see mediamuxer_unset_error_cb()
+ */
+typedef void (*mx_error_cb)(mediamuxer_error_e error, void *user_data);
+
+/**
+ * Attribute validity structure
+ */
+typedef struct _media_port_muxer_ops {
+ unsigned int n_size;
+ int (*init)(MMHandleType *pHandle);
+ /* Add new ops at the end of structure, no order change */
+ int (*set_data_sink)(MMHandleType pHandle, char *uri, mediamuxer_output_format_e format);
+ int (*add_track)(MMHandleType pHandle, media_format_h media_format, int *track_index);
+ int (*start)(MMHandleType pHandle);
+ int (*write_sample)(MMHandleType pHandle, int track_index, media_packet_h inbuf);
+ int (*close_track)(MMHandleType pHandle, int track_index);
+ int (*pause)(MMHandleType pHandle);
+ int (*resume)(MMHandleType pHandle);
+ int (*stop)(MMHandleType pHandle);
+ int (*destroy)(MMHandleType pHandle);
+ int (*set_error_cb)(MMHandleType pHandle, mx_error_cb callback, void* user_data);
+} media_port_muxer_ops;
+
+/*=============================================================================
+| |
+| GLOBAL FUNCTION PROTOTYPES |
+| |
+==============================================================================*/
+
+/**
+ * This function creates a muxer object for parsing multimedia contents. \n
+ * The attributes of muxer are created to get/set some values with application.
+ * And, proper port is selected to do the actual parsing of the mdia.
+ *
+ * @param muxer [out] Handle of muxer
+ * @param op_uri uri at which muxed file should be stored
+ * @param format container format of the muxed data
+ *
+ * @return This function returns zero on success, or negative value with error
+ * code. Please refer 'mx_error.h' to know it in detail.
+ *
+ * @par Example
+ * @code
+ mx_create(&muxer, char *op_uri, mediamuxer_output_format_e format);
+ ...
+ mx_destroy(&muxer);
+ * @endcode
+ */
+int mx_create(MMHandleType *muxer);
+
+/**
+ * This function sets the input data source to parse. \n
+ * The source can be a local file or remote
+ *
+ * @param muxer Handle of muxer
+ * @param uri uri at which muxed file should be stored
+ * @param format container format of the muxed data
+ *
+ * @return This function returns zero on success, or negative value with error
+ * code. Please refer 'mx_error.h' to know it in detail.
+ *
+ * @par Example
+ * @code
+ if (mx_set_data_sink(muxer, uri, format) != MM_ERROR_NONE)
+ {
+ MX_E("failed to set the source \n");
+ }
+ * @endcode
+ */
+int mx_set_data_sink(MMHandleType muxer, char *uri, mediamuxer_output_format_e format);
+
+/**
+ * This function releases muxer object and all resources which were created by
+ * mx_create(). And, muxer handle will also be destroyed.
+ *
+ * @param muxer [in] Handle of muxer
+ *
+ * @return This function returns zero on success, or negative value with error
+ * code.
+ * @see mx_destroy
+ *
+ * @par Example
+ * @code
+if (mx_destroy(g_muxer) != MM_ERROR_NONE)
+{
+ MX_E("failed to destroy muxer\n");
+}
+ * @endcode
+ */
+int mx_destroy(MMHandleType muxer);
+
+/**
+ * This function starts/prepares the muxer object. \n
+ * For GST-port, this function creates necessary gst elemetns
+ *
+ * @param muxer [in] Handle of muxer
+ *
+ * @return This function returns zero on success, or negative value with error
+ code.
+ * @see mx_create
+ *
+ * @par Example
+ * @code
+if (mx_start(g_muxer) != MX_ERROR_NONE)
+{
+ MX_E("failed to start muxer\n");
+}
+ * @endcode
+ */
+int mx_start(MMHandleType muxer);
+
+/**
+ * This function adds Audio/Vidoe/Subtitle track in muxer handle \n
+ *
+ * @param muxer [in] Handle of muxer
+ * media_format [in] media format of A/V/S
+ * track_index [out] index of the media track
+ *
+ * @return This function returns zero on success, or negative value with error
+ code.
+ * @see mx_create
+ *
+ * @par Example
+ * @code
+if (mx_add_track(g_muxer,media_format,&track_index) != MX_ERROR_NONE)
+{
+ MX_E("failed to add track to muxer handle\n");
+}
+ * @endcode
+ */
+int mx_add_track(MMHandleType muxer, media_format_h media_format, int *track_index);
+
+/**
+ * This function writes Audio/Vidoe/Subtitle track to file using muxer handle \n
+ *
+ * @param muxer [in] Handle of muxer
+ * track_index index of the media track
+ * inbuf buffer to be muxed
+ *
+ * @return This function returns zero on success, or negative value with error
+ code.
+ * @see mx_write_sample
+ *
+ * @par Example
+ * @code
+if (mx_write_sample(g_muxer,track_id, inbuf) != MX_ERROR_NONE)
+{
+ MX_E("failed to write sample\n");
+}
+ * @endcode
+ */
+int mx_write_sample(MMHandleType mediamuxer, int track_index, media_packet_h inbuf);
+
+/**
+ * This function close the selected track. \n
+ * For GST-port, this function send the eos to the specific appsrc element
+ *
+ * @param muxer [in] Handle of muxer
+ * @param track_index [in] selected track
+ *
+ * @return This function returns zero on success, or negative value with error
+ code.
+ * @see mx_stop
+ *
+ * @par Example
+ * @code
+if (mx_close_track(g_muxer,1) != MX_ERROR_NONE)
+{
+ MX_E("failed to close audio track\n");
+}
+ * @endcode
+ */
+int mx_close_track(MMHandleType mediamuxer, int track_index);
+
+/**
+ * This function stops/un-prepares the muxer object. \n
+ * For GST-port, this function unrefs necessary gst elemetns
+ *
+ * @param muxer [in] Handle of muxer
+ *
+ * @return This function returns zero on success, or negative value with error
+ code.
+ * @see mx_stop
+ *
+ * @par Example
+ * @code
+if (mx_stop(g_muxer) != MX_ERROR_NONE)
+{
+ MX_E("failed to stop muxer\n");
+}
+ * @endcode
+ */
+int mx_stop(MMHandleType mediamuxer);
+
+/**
+ * This function pauses the muxing operation. \n
+ * For GST-port, this function pauses the pipeline
+ *
+ * @param muxer [in] Handle of muxer
+ *
+ * @return This function returns zero on success, or negative value with error
+ code.
+ * @see mx_resume
+ *
+ * @par Example
+ * @code
+if (mx_pause(g_muxer) != MX_ERROR_NONE)
+{
+ MX_E("failed to pause muxer\n");
+}
+ * @endcode
+ */
+int mx_pause(MMHandleType mediamuxer);
+
+/**
+ * This function resumes the muxing operation. \n
+ * For GST-port, this function sets the pipeline back to playing
+ *
+ * @param muxer [in] Handle of muxer
+ *
+ * @return This function returns zero on success, or negative value with error
+ code.
+ * @see mx_pause
+ *
+ * @par Example
+ * @code
+if (mx_resume(g_muxer) != MX_ERROR_NONE)
+{
+ MX_E("failed to resume muxer\n");
+}
+ * @endcode
+ */
+int mx_resume(MMHandleType mediamuxer);
+
+/**
+ * This function is to set error call back function
+ *
+ * @param muxer [in] Handle of muxer
+ * @param callback [in] call back function pointer
+ * @param user_data [in] user specific data pointer
+ *
+ * @return This function returns zero on success, or negative value with error code.
+ */
+int mx_set_error_cb(MMHandleType muxer, mediamuxer_error_cb callback, void* user_data);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TIZEN_MEDIAMUXER_PORT_H__ */
--- /dev/null
+/*
+ * 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_MEDIAMUXER_PRIVATE_H__
+#define __TIZEN_MEDIAMUXER_PRIVATE_H__
+#include <mediamuxer.h>
+#include <mediamuxer_port.h>
+#include <mediamuxer_ini.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "TIZEN_N_MEDIAMUXER"
+
+#define MUXER_CHECK_CONDITION(condition,error,msg) \
+ do \
+ { \
+ if (condition) {} else \
+ { MX_E("[%s] %s(0x%08x)",__FUNCTION__, msg,error); return error;}; \
+ }while(0)
+
+#define MUXER_INSTANCE_CHECK(muxer) \
+ MUXER_CHECK_CONDITION(muxer != NULL, \
+ MEDIAMUXER_ERROR_INVALID_PARAMETER,"MUXER_ERROR_INVALID_PARAMETER")
+
+#define MUXER_STATE_CHECK(muxer,expected_state) \
+ MUXER_CHECK_CONDITION(muxer->state == expected_state, \
+ MEDIAMUXER_ERROR_INVALID_STATE,"MUXER_ERROR_INVALID_STATE")
+
+#define MUXER_NULL_ARG_CHECK(arg) \
+ MUXER_CHECK_CONDITION(arg != NULL,MEDIAMUXER_ERROR_INVALID_PARAMETER, \
+ "MUXER_ERROR_INVALID_PARAMETER")
+
+/**
+ * @brief Enumerations of media muxer state
+ * @since_tizen 3.0
+ */
+
+int _convert_error_code(int code, char *func_name);
+
+typedef enum {
+ MEDIAMUXER_EVENT_TYPE_PREPARE,
+ MEDIAMUXER_EVENT_TYPE_COMPLETE,
+ MEDIAMUXER_EVENT_TYPE_INTERRUPT,
+ MEDIAMUXER_EVENT_TYPE_ERROR,
+ MEDIAMUXER_EVENT_TYPE_BUFFERING,
+ MEDIAMUXER_EVENT_TYPE_SUBTITLE,
+ MEDIAMUXER_EVENT_TYPE_CLOSED_CAPTION,
+ MEDIAMUXER_EVENT_TYPE_CAPTURE,
+ MEDIAMUXER_EVENT_TYPE_SEEK,
+ MEDIAMUXER_EVENT_TYPE_VIDEO_FRAME,
+ MEDIAMUXER_EVENT_TYPE_AUDIO_FRAME,
+ MEDIAMUXER_EVENT_TYPE_VIDEO_FRAME_RENDER_ERROR,
+ MEDIAMUXER_EVENT_TYPE_PD,
+ MEDIAMUXER_EVENT_TYPE_SUPPORTED_AUDIO_EFFECT,
+ MEDIAMUXER_EVENT_TYPE_SUPPORTED_AUDIO_EFFECT_PRESET,
+ MEDIAMUXER_EVENT_TYPE_MISSED_PLUGIN,
+ MEDIAMUXER_EVENT_TYPE_IMAGE_BUFFER,
+ MEDIAMUXER_EVENT_TYPE_OTHERS,
+ MEDIAMUXER_EVENT_TYPE_NUM
+} mediamuxer_event_e;
+
+typedef struct _mediamuxer_s {
+ MMHandleType mx_handle;
+ const void *user_cb[MEDIAMUXER_EVENT_TYPE_NUM];
+ void *user_data[MEDIAMUXER_EVENT_TYPE_NUM];
+ void *display_handle;
+ int state;
+ bool is_set_pixmap_cb;
+ bool is_stopped;
+ bool is_display_visible;
+ bool is_progressive_download;
+ pthread_t prepare_async_thread;
+ mediamuxer_error_cb error_cb;
+ void* error_cb_userdata;
+ mediamuxer_state_e muxer_state;
+} mediamuxer_s;
+
+typedef struct {
+ /* initialize values */
+ media_port_muxer_ops *muxer_ops;
+ /* initialize values */
+ mx_ini_t ini;
+ /* port specific handle */
+ MMHandleType mxport_handle;
+} mx_handle_t;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TIZEN_MEDIAMUXER_PRIVATE_H__ */
--- /dev/null
+/*
+ * 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_MEDIAMUXER_UTIL_H__
+#define __TIZEN_MEDIAMUXER_UTIL_H__
+
+#include <glib.h>
+#include <mediamuxer_ini.h>
+#include <mm_types.h>
+#include <mm_error.h>
+#include <mm_message.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#define PRINT_ON_CONSOLE
+#ifdef PRINT_ON_CONSOLE
+#include <stdlib.h>
+#include <stdio.h>
+#define PRINT_F g_print
+#define MX_FENTER(); PRINT_F("function:[%s] ENTER\n",__func__);
+#define MX_FLEAVE(); PRINT_F("function [%s] LEAVE\n",__func__);
+#define MX_C PRINT_F
+#define MX_E PRINT_F
+#define MX_W PRINT_F
+#define MX_I PRINT_F
+#define MX_L PRINT_F
+#define MX_V PRINT_F
+#else
+#include <stdlib.h>
+#include <stdio.h>
+#define MX_FENTER(); LOGI("function:[%s] ENTER\n",__func__);
+#define MX_FLEAVE(); LOGI("function [%s] LEAVE\n",__func__);
+#define MX_C LOGE /*MMF_DEBUG_LEVEL_0 */
+#define MX_E LOGE /*MMF_DEBUG_LEVEL_1 */
+#define MX_W LOGW /*MMF_DEBUG_LEVEL_2 */
+#define MX_I LOGI /*MMF_DEBUG_LEVEL_3 */
+#define MX_L LOGI /*MMF_DEBUG_LEVEL_4 */
+#define MX_V LOGV /*MMF_DEBUG_LEVEL_5 */
+#define MX_F LOGF /*MMF_DEBUG_LEVEL_6 */
+#endif
+
+/* general */
+#define MEDIAMUXER_FREEIF(x) \
+ do \
+ { \
+ if ( x ) \
+ g_free( x ); \
+ x = NULL; \
+ }while(0)
+
+#if 1
+#define MEDIAMUXER_FENTER(); MX_FENTER();
+#define MEDIAMUXER_FLEAVE(); MX_FLEAVE();
+#else
+#define MEDIAMUXER_FENTER();
+#define MEDIAMUXER_FLEAVE();
+#endif
+
+#define MEDIAMUXER_CHECK_NULL( x_var ) \
+ do \
+ { \
+ if ( ! x_var ) \
+ { \
+ MX_E("[%s] is NULL\n", #x_var ); \
+ goto ERROR; \
+ } \
+ } while (0)
+#define MEDIAMUXER_CHECK_SET_AND_PRINT( x_var, x_cond, ret, ret_val, err_text )\
+ do \
+ { \
+ if ( x_var != x_cond ) \
+ { \
+ ret = ret_val; \
+ MX_E("%s\n", #err_text ); \
+ goto ERROR; \
+ } \
+ } while (0)
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TIZEN_MEDIAMUXER_UTIL_H__ */
--- /dev/null
+/*
+ * 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_MEDIAMUXER_PORT_CUSTOM_H__
+#define __TIZEN_MEDIAMUXER_PORT_CUSTOM_H__
+
+#include <tizen.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*Place holder */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TIZEN_MEDIAMUXER_PORT_CUSTOM_H__ */
--- /dev/null
+/*
+ * 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_MEDIAMUXER_PORT_FFMPEG_H__
+#define __TIZEN_MEDIAMUXER_PORT_FFMPEG_H__
+
+#include <tizen.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*Place holder */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TIZEN_MEDIAMUXER_PORT_FFMPEG_H__ */
--- /dev/null
+/*
+ * 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_MEDIAMUXER_PORT_GST_H__
+#define __TIZEN_MEDIAMUXER_PORT_GST_H__
+
+#include <tizen.h>
+#include <gst/gst.h>
+#include <gst/gstelement.h>
+#include <gst/app/gstappsrc.h>
+#include <gst/video/video-format.h>
+
+#define MEDIAMUXER_ELEMENT_SET_STATE( x_element, x_state ) \
+ MX_I("setting state [%s:%d] to [%s]\n", #x_state, x_state, GST_ELEMENT_NAME( x_element ) ); \
+ if ( GST_STATE_CHANGE_FAILURE == gst_element_set_state ( x_element, x_state) ) \
+ { \
+ MX_E("failed to set state %s to %s\n", #x_state, GST_ELEMENT_NAME( x_element )); \
+ goto STATE_CHANGE_FAILED; \
+ }
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ _GST_EVENT_TYPE_COMPLETE,
+ _GST_EVENT_TYPE_ERROR,
+ _GST_EVENT_TYPE_EOS,
+ _GST_EVENT_TYPE_NUM
+} _gst_event_e;
+
+/* GST port Private data */
+typedef struct _mx_gst_track {
+ void *media_format;
+ char *caps;
+ int track_index;
+ int start_feed;
+ int stop_feed;
+} mx_gst_track;
+
+typedef struct _mxgst_handle_t {
+ void *hmux; /**< mux handle */
+ int state; /**< mx current state */
+ bool is_prepared;
+
+ mx_gst_track video_track;
+ mx_gst_track audio_track;
+
+ mediamuxer_output_format_e muxed_format;
+ char *output_uri;
+ bool eos_flg;
+ guint bus_watch_id;
+ GstElement *pipeline;
+ GstElement *audio_appsrc; /* Input audio buffers to be muxed */
+ GstElement *video_appsrc; /* Input video buffers to be muxed */
+ GstElement *audioparse;
+ GstElement *videoparse;
+ GstElement *muxer;
+ GstElement *sink; /* sink for the muxed output */
+ char *saveLocation; /* Save path for muxed data */
+ void* user_cb[_GST_EVENT_TYPE_NUM]; /* for user cb */
+ void* user_data[_GST_EVENT_TYPE_NUM];
+} mxgst_handle_t;
+
+/**
+ * @brief Called when the error has occured.
+ * @remarks It will be invoked when the error has occured.
+ * @since_tizen 3.0
+ * @param[in] error_code The error code
+ * @param[in] user_data The user data passed from the callback registration function
+ * @pre It will be invoked when the error has occured if user register this callback using mediamuxer_set_error_cb().
+ * @see mediamuxer_set_error_cb()
+ * @see mediamuxer_unset_error_cb()
+ */
+typedef void (*gst_error_cb)(mediamuxer_error_e error, void *user_data);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __TIZEN_MEDIAMUXER_PORT_GST_H__ */
--- /dev/null
+Name: capi-mediamuxer
+Summary: A Media Muxer library in Tizen Native API
+Version: 0.1.1
+Release: 1
+Group: Multimedia/API
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+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)
+
+Requires(post): /sbin/ldconfig
+Requires(post): libprivilege-control
+Requires(postun): /sbin/ldconfig
+
+%description
+
+%package devel
+Summary: Multimedia Framework Muxer Library (DEV)
+Group: Multimedia/API
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+
+%prep
+%setup -q
+
+
+%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
+%ifarch %{arm}
+export CFLAGS="$CFLAGS -DENABLE_FFMPEG_CODEC"
+%endif
+
+MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
+%cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DFULLVER=%{version} -DMAJORVER=${MAJORVER}
+
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}%{_datadir}/license
+mkdir -p %{buildroot}/usr/bin
+cp test/mediamuxer_test %{buildroot}/usr/bin
+cp LICENSE.APLv2 %{buildroot}%{_datadir}/license/%{name}
+
+%make_install
+
+%post
+/sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+
+%files
+%manifest capi-mediamuxer.manifest
+%{_libdir}/libcapi-mediamuxer.so.*
+%{_datadir}/license/%{name}
+%{_bindir}/*
+
+%files devel
+%{_includedir}/media/*.h
+%{_libdir}/pkgconfig/*.pc
+%{_libdir}/libcapi-mediamuxer.so
+
+
--- /dev/null
+message(In src folder...)
+add_subdirectory(port_gst)
+add_subdirectory(port_ffmpeg)
+add_subdirectory(port_custom)
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mm.h>
+#include <mediamuxer_port.h>
+#include <mm_types.h>
+#include <mediamuxer.h>
+#include <mediamuxer_private.h>
+#include <dlog.h>
+
+#ifndef USE_TASK_QUEUE
+#define USE_TASK_QUEUE
+#endif
+
+/*
+* Public Implementation
+*/
+static gboolean _mediamuxer_error_cb(mediamuxer_error_e error, void *user_data);
+
+int mediamuxer_create(mediamuxer_h *muxer)
+{
+ MX_I("mediamuxer_create\n");
+ mediamuxer_error_e ret = MM_ERROR_NONE;
+ MUXER_INSTANCE_CHECK(muxer);
+
+ mediamuxer_s *handle;
+ handle = (mediamuxer_s *) malloc(sizeof(mediamuxer_s));
+ if (handle != NULL) {
+ memset(handle, 0, sizeof(mediamuxer_s));
+ handle->muxer_state = MEDIAMUXER_STATE_NONE;
+ } else {
+ MX_E("[CoreAPI][%s] MUXER_ERROR_OUT_OF_MEMORY(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_OUT_OF_MEMORY);
+ return MEDIAMUXER_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = mx_create(&handle->mx_handle);
+ if (ret != MM_ERROR_NONE) {
+ MX_E("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION);
+ free(handle);
+ handle = NULL;
+ return MEDIAMUXER_ERROR_INVALID_OPERATION;
+ } else {
+ *muxer = (mediamuxer_h) handle;
+ handle->is_stopped = false;
+ MX_I("[CoreAPI][%s] new handle : %p", __FUNCTION__, *muxer);
+
+ /* set callback */
+ mx_set_error_cb(handle->mx_handle, (mediamuxer_error_cb)_mediamuxer_error_cb, handle);
+ handle->muxer_state = MEDIAMUXER_STATE_IDLE;
+ return MEDIAMUXER_ERROR_NONE;
+ }
+}
+
+int mediamuxer_set_data_sink(mediamuxer_h muxer, char *path, mediamuxer_output_format_e format)
+{
+ MX_I("mediamuxer_set_data_sink\n");
+ int ret = MEDIAMUXER_ERROR_NONE;
+ mediamuxer_s *handle;
+ MUXER_INSTANCE_CHECK(muxer);
+ handle = (mediamuxer_s *)(muxer);
+
+ if (path == NULL) {
+ MX_I("Invalid uri");
+ return MEDIAMUXER_ERROR_INVALID_PARAMETER;
+ }
+
+ if (format != MEDIAMUXER_CONTAINER_FORMAT_MP4) {
+ MX_E("\n Unsupported format: %d \n", format);
+ return MEDIAMUXER_ERROR_INVALID_PARAMETER;
+ }
+ if (handle->muxer_state == MEDIAMUXER_STATE_IDLE) {
+ ret = mx_set_data_sink(handle->mx_handle, path, format);
+ if (ret != MEDIAMUXER_ERROR_NONE) {
+ MX_E("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION);
+ ret = MEDIAMUXER_ERROR_INVALID_OPERATION;
+ } else {
+ MX_I("[CoreAPI][%s] set_data_sink successful, handle : %p",
+ __FUNCTION__, handle);
+ }
+ } else {
+ MX_E("[CoreAPI][%s] MEDIAMUXER_ERROR_INVALID_STATE(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE);
+ ret = MEDIAMUXER_ERROR_INVALID_STATE;
+ }
+ return ret;
+}
+
+int mediamuxer_add_track(mediamuxer_h muxer, media_format_h media_format, int *track_index)
+{
+ MX_I("mediamuxer_add_track\n");
+ mediamuxer_error_e ret = MEDIAMUXER_ERROR_NONE;
+ MUXER_INSTANCE_CHECK(muxer);
+ mediamuxer_s *handle;
+ handle = (mediamuxer_s *)(muxer);
+ if (handle->muxer_state == MEDIAMUXER_STATE_IDLE){
+ ret = mx_add_track(handle->mx_handle, media_format, track_index);
+ if (ret != MEDIAMUXER_ERROR_NONE) {
+ MX_E("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION);
+ ret = MEDIAMUXER_ERROR_INVALID_OPERATION;
+ } else {
+ MX_I("[CoreAPI][%s] add_track handle : %p", __FUNCTION__,
+ handle);
+ }
+ } else {
+ MX_E("[CoreAPI][%s] MEDIAMUXER_ERROR_INVALID_STATE(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE);
+ ret = MEDIAMUXER_ERROR_INVALID_STATE;
+ }
+ return ret;
+}
+
+int mediamuxer_start(mediamuxer_h muxer)
+{
+ MX_I("mediamuxer_start\n");
+ int ret = MEDIAMUXER_ERROR_NONE;
+ MUXER_INSTANCE_CHECK(muxer);
+ mediamuxer_s *handle = (mediamuxer_s *)(muxer);
+ if (handle->muxer_state == MEDIAMUXER_STATE_IDLE) {
+ ret = mx_start(handle->mx_handle);
+ if (ret != MEDIAMUXER_ERROR_NONE) {
+ MX_E("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION);
+ ret = MEDIAMUXER_ERROR_INVALID_OPERATION;
+ } else {
+ MX_I("[CoreAPI][%s] start successful, handle : %p",
+ __FUNCTION__, handle);
+ }
+ } else {
+ MX_E("[CoreAPI][%s] MEDIAMUXER_ERROR_INVALID_STATE(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE);
+ return MEDIAMUXER_ERROR_INVALID_STATE;
+ }
+ handle->muxer_state = MEDIAMUXER_STATE_READY;
+ return ret;
+}
+
+int mediamuxer_write_sample(mediamuxer_h muxer, int track_index, media_packet_h inbuf)
+{
+ MX_I("mediamuxer_write_sample\n");
+ int ret = MEDIAMUXER_ERROR_NONE;
+ MUXER_INSTANCE_CHECK(muxer);
+ mediamuxer_s *handle = (mediamuxer_s *)(muxer);
+ if (track_index < 0 || inbuf == NULL) {
+ return MEDIAMUXER_ERROR_INVALID_PARAMETER;
+ }
+ if (handle->muxer_state == MEDIAMUXER_STATE_READY
+ || handle->muxer_state == MEDIAMUXER_STATE_MUXING) {
+ ret = mx_write_sample(handle->mx_handle, track_index, inbuf);
+ if (ret != MEDIAMUXER_ERROR_NONE) {
+ MX_E
+ ("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION);
+ ret = MEDIAMUXER_ERROR_INVALID_OPERATION;
+ } else {
+ MX_I("[CoreAPI][%s] write_sample successful, handle : %p",
+ __FUNCTION__, handle);
+ }
+ } else {
+ MX_E("[CoreAPI][%s] MEDIAMUXER_ERROR_INVALID_STATE(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE);
+ return MEDIAMUXER_ERROR_INVALID_STATE;
+ }
+ handle->muxer_state = MEDIAMUXER_STATE_MUXING;
+ return ret;
+}
+
+int mediamuxer_close_track(mediamuxer_h muxer, int track_index)
+{
+ MX_I("mediamuxer_close_track\n");
+ int ret = MEDIAMUXER_ERROR_NONE;
+ MUXER_INSTANCE_CHECK(muxer);
+ mediamuxer_s *handle = (mediamuxer_s *)(muxer);
+ if (track_index < 0) {
+ return MEDIAMUXER_ERROR_INVALID_PARAMETER;
+ }
+ if (handle->muxer_state == MEDIAMUXER_STATE_MUXING ||
+ handle->muxer_state == MEDIAMUXER_STATE_IDLE ||
+ handle->muxer_state == MEDIAMUXER_STATE_READY) {
+ ret = mx_close_track(handle->mx_handle, track_index);
+ if (ret != MEDIAMUXER_ERROR_NONE) {
+ MX_E
+ ("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION);
+ ret = MEDIAMUXER_ERROR_INVALID_OPERATION;
+ } else {
+ MX_I("[CoreAPI][%s] close successful, handle : %p",
+ __FUNCTION__, handle);
+ }
+ } else {
+ MX_E("[CoreAPI][%s] MEDIAMUXER_ERROR_INVALID_STATE(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE);
+ ret = MEDIAMUXER_ERROR_INVALID_STATE;
+ }
+ return ret;
+}
+
+int mediamuxer_pause(mediamuxer_h muxer)
+{
+ MX_I("mediamuxer_pause\n");
+ int ret = MEDIAMUXER_ERROR_NONE;
+ MUXER_INSTANCE_CHECK(muxer);
+ mediamuxer_s *handle = (mediamuxer_s *)(muxer);
+ ret = mx_pause(handle->mx_handle);
+ if (handle->muxer_state == MEDIAMUXER_STATE_READY
+ || handle->muxer_state == MEDIAMUXER_STATE_MUXING) {
+ if (ret != MEDIAMUXER_ERROR_NONE) {
+ MX_E
+ ("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION);
+ ret = MEDIAMUXER_ERROR_INVALID_OPERATION;
+ } else {
+ MX_I("[CoreAPI][%s] pause successful, handle : %p",
+ __FUNCTION__, handle);
+ }
+ } else {
+ MX_E("[CoreAPI][%s] MEDIAMUXER_ERROR_INVALID_STATE(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE);
+ return MEDIAMUXER_ERROR_INVALID_STATE;
+ }
+ handle->muxer_state = MEDIAMUXER_STATE_PAUSED;
+ return ret;
+}
+
+int mediamuxer_resume(mediamuxer_h muxer)
+{
+ MX_I("mediamuxer_resume\n");
+ int ret = MEDIAMUXER_ERROR_NONE;
+ MUXER_INSTANCE_CHECK(muxer);
+ mediamuxer_s *handle = (mediamuxer_s *)(muxer);
+ if (handle->muxer_state == MEDIAMUXER_STATE_PAUSED) {
+ ret = mx_resume(handle->mx_handle);
+ if (ret != MEDIAMUXER_ERROR_NONE) {
+ MX_E
+ ("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION);
+ ret = MEDIAMUXER_ERROR_INVALID_OPERATION;
+ } else {
+ MX_I("[CoreAPI][%s] resume successful, handle : %p",
+ __FUNCTION__, handle);
+ }
+ } else {
+ MX_E("[CoreAPI][%s] MEDIAMUXER_ERROR_INVALID_STATE(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE);
+ return MEDIAMUXER_ERROR_INVALID_STATE;
+ }
+ handle->muxer_state = MEDIAMUXER_STATE_MUXING;
+ return ret;
+}
+
+int mediamuxer_stop(mediamuxer_h muxer)
+{
+ MX_I("mediamuxer_stop\n");
+ int ret = MEDIAMUXER_ERROR_NONE;
+ MUXER_INSTANCE_CHECK(muxer);
+ mediamuxer_s *handle = (mediamuxer_s *)(muxer);
+ if (handle->muxer_state == MEDIAMUXER_STATE_READY
+ || handle->muxer_state == MEDIAMUXER_STATE_MUXING
+ || handle->muxer_state == MEDIAMUXER_STATE_PAUSED) {
+ ret = mx_stop(handle->mx_handle);
+ if (ret != MEDIAMUXER_ERROR_NONE) {
+ MX_E
+ ("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION);
+ ret = MEDIAMUXER_ERROR_INVALID_OPERATION;
+ } else {
+ MX_I("[CoreAPI][%s] stop successful, handle : %p",
+ __FUNCTION__, handle);
+ }
+ } else {
+ MX_E("[CoreAPI][%s] MEDIAMUXER_ERROR_INVALID_STATE(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE);
+ return MEDIAMUXER_ERROR_INVALID_STATE;
+ }
+ handle->muxer_state = MEDIAMUXER_STATE_IDLE;
+ return ret;
+}
+
+int mediamuxer_destroy(mediamuxer_h muxer)
+{
+ MX_I("mediamuxer_destroy\n");
+ int ret = MEDIAMUXER_ERROR_NONE;
+ MUXER_INSTANCE_CHECK(muxer);
+ mediamuxer_s *handle;
+ handle = (mediamuxer_s *)(muxer);
+ if (handle->muxer_state == MEDIAMUXER_STATE_IDLE) {
+ ret = mx_destroy(handle->mx_handle);
+ if (ret != MEDIAMUXER_ERROR_NONE) {
+ MX_E("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION);
+ ret = MEDIAMUXER_ERROR_INVALID_OPERATION;
+ } else {
+ MX_I("[CoreAPI][%s] destroy handle : %p", __FUNCTION__,
+ handle);
+ }
+ } else {
+ MX_E("[CoreAPI][%s] MEDIAMUXER_ERROR_INVALID_STATE(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_STATE);
+ return MEDIAMUXER_ERROR_INVALID_STATE;
+ }
+ handle->muxer_state = MEDIAMUXER_STATE_NONE;
+ return ret;
+}
+
+int mediamuxer_get_state(mediamuxer_h muxer, mediamuxer_state_e *state)
+{
+ MX_I("mediamuxer_get_state\n");
+ int ret = MEDIAMUXER_ERROR_NONE;
+ MUXER_INSTANCE_CHECK(muxer);
+ mediamuxer_s *handle = (mediamuxer_s *)(muxer);
+ if (state != NULL) {
+ *state = handle->muxer_state;
+ } else {
+ MX_E("[CoreAPI][%s] MUXER_ERROR_INVALID_OPERATION(0x%08x)",
+ __FUNCTION__, MEDIAMUXER_ERROR_INVALID_OPERATION);
+ ret = MEDIAMUXER_ERROR_INVALID_OPERATION;
+ }
+ return ret;
+}
+
+int mediamuxer_set_error_cb(mediamuxer_h muxer, mediamuxer_error_cb callback, void* user_data)
+{
+ MUXER_INSTANCE_CHECK(muxer);
+ mediamuxer_s *handle;
+ handle = (mediamuxer_s *)(muxer);
+
+ handle->error_cb = callback;
+ handle->error_cb_userdata = user_data;
+
+ MX_I("set error_cb(%p)", callback);
+
+ return MEDIAMUXER_ERROR_NONE;
+}
+
+int mediamuxer_unset_error_cb(mediamuxer_h muxer)
+{
+ MUXER_INSTANCE_CHECK(muxer);
+ mediamuxer_s *handle;
+ handle = (mediamuxer_s *)(muxer);
+
+ handle->error_cb = NULL;
+ handle->error_cb_userdata = NULL;
+ MX_I("mediamuxer_unset_error_cb\n");
+ return MEDIAMUXER_ERROR_NONE;
+}
+
+static gboolean _mediamuxer_error_cb(mediamuxer_error_e error, void *user_data)
+{
+ if (user_data == NULL) {
+ MX_I("_mediamuxer_error_cb: ERROR %d to report. But call back is not set\n",error);
+ return 0;
+ }
+ mediamuxer_s * handle = (mediamuxer_s *) user_data;
+
+ if (handle->error_cb ) {
+ ((mediamuxer_error_cb)handle->error_cb)(error, handle->error_cb_userdata);
+ }
+ else {
+ MX_I("_mediamuxer_error_cb: ERROR %d to report. But call back is not set\n",error);
+ }
+ return 0;
+}
--- /dev/null
+/*
+ * 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 __MEDIAMUXER_INI_C__
+#define __MEDIAMUXER_INI_C__
+
+#include <glib.h>
+#include <stdlib.h>
+#include <glib/gstdio.h>
+#include <mm_debug.h>
+#include <mm_error.h>
+#include "iniparser.h"
+#include <mediamuxer_ini.h>
+#include <mediamuxer_private.h>
+#include <mediamuxer_error.h>
+
+/* macro */
+#define MEDIAMUXER_INI_GET_STRING( x_dict, x_item, x_ini, x_default ) \
+ do \
+ { \
+ gchar* str = iniparser_getstring(x_dict, x_ini, x_default); \
+ \
+ if ( str && \
+ ( strlen( str ) > 0 ) && \
+ ( strlen( str ) < MEDIAMUXER_INI_MAX_STRLEN ) ) \
+ { \
+ strcpy ( x_item, str ); \
+ } \
+ else \
+ { \
+ strcpy ( x_item, x_default ); \
+ } \
+ }while(0)
+
+#define MEDIAMUXER_INI_GET_COLOR( x_dict, x_item, x_ini, x_default ) \
+ do \
+ { \
+ gchar* str = iniparser_getstring(x_dict, x_ini, x_default); \
+ \
+ if ( str && \
+ ( strlen( str ) > 0 ) && \
+ ( strlen( str ) < MEDIAMUXER_INI_MAX_STRLEN ) ) \
+ { \
+ x_item = (guint) strtoul(str, NULL, 16); \
+ } \
+ else \
+ { \
+ x_item = (guint) strtoul(x_default, NULL, 16); \
+ } \
+ }while(0)
+
+/* x_ini is the list of index to set TRUE at x_list[index] */
+#define MEDIAMUXER_INI_GET_BOOLEAN_FROM_LIST( x_dict, x_list, \
+ x_list_max, x_ini, x_default ) \
+do \
+{ \
+ int index = 0; \
+ const char *delimiters = " ,"; \
+ char *usr_ptr = NULL; \
+ char *token = NULL; \
+ gchar temp_arr[MEDIAMUXER_INI_MAX_STRLEN] = {0}; \
+ MMMEDIAMUXER_INI_GET_STRING( x_dict, temp_arr, x_ini, x_default); \
+ token = strtok_r( temp_arr, delimiters, &usr_ptr ); \
+ while (token) \
+ { \
+ index = atoi(token); \
+ if (index < 0 || index > x_list_max -1) \
+ { \
+ MX_W("%d is not valid index\n", index); \
+ } \
+ else \
+ { \
+ x_list[index] = TRUE; \
+ } \
+ token = strtok_r( NULL, delimiters, &usr_ptr ); \
+ } \
+}while(0)
+
+/* x_ini is the list of value to be set at x_list[index] */
+#define MEDIAMUXER_INI_GET_INT_FROM_LIST( x_dict, x_list, \
+ x_list_max, x_ini, x_default ) \
+do \
+{ \
+ int index = 0; \
+ int value = 0; \
+ const char *delimiters = " ,"; \
+ char *usr_ptr = NULL; \
+ char *token = NULL; \
+ gchar temp_arr[MEDIAMUXER_INI_MAX_STRLEN] = {0}; \
+ MMMEDIAMUXER_INI_GET_STRING(x_dict, temp_arr, x_ini, x_default); \
+ token = strtok_r( temp_arr, delimiters, &usr_ptr ); \
+ while (token) \
+ { \
+ if ( index > x_list_max -1) \
+ { \
+ MX_E("%d is not valid index\n", index); \
+ break; \
+ } \
+ else \
+ { \
+ value = atoi(token); \
+ x_list[index] = value; \
+ index++; \
+ } \
+ token = strtok_r( NULL, delimiters, &usr_ptr ); \
+ } \
+}while(0)
+
+/* internal functions, macros here */
+#ifdef MEDIAMUXER_DEFAULT_INI
+static gboolean _generate_default_ini(void);
+#endif
+
+static void _mx_ini_check_ini_status(void);
+
+int mx_ini_load(mx_ini_t *ini)
+{
+ dictionary *dict = NULL;
+
+ _mx_ini_check_ini_status();
+
+ /* first, try to load existing ini file */
+ dict = iniparser_load(MEDIAMUXER_INI_DEFAULT_PATH);
+
+ /* if no file exists. create one with set of default values */
+ if (!dict) {
+#ifdef MEDIAMUXER_DEFAULT_INI
+ MX_L("No inifile found. muxer will create default inifile.\n");
+ if (FALSE == _generate_default_ini()) {
+ MX_W("Creating default inifile failed. \
+ MediaMuxer will use default values.\n");
+ } else {
+ /* load default ini */
+ dict = iniparser_load(MEDIAMUXER_INI_DEFAULT_PATH);
+ }
+#else
+ MX_L("No ini file found. \n");
+ return MM_ERROR_FILE_NOT_FOUND;
+#endif
+ }
+
+ /* get ini values */
+ memset(ini, 0, sizeof(mx_ini_t));
+
+ if (dict) { /* if dict is available */
+ /* general */
+ MEDIAMUXER_INI_GET_STRING(dict, ini->port_name,
+ "port_in_use:mediamuxer_port",
+ DEFAULT_PORT);
+ } else {
+ /* if dict is not available just fill
+ the structure with default value */
+ MX_W("failed to load ini. using hardcoded default\n");
+ strncpy(ini->port_name, DEFAULT_PORT,
+ MEDIAMUXER_INI_MAX_STRLEN - 1);
+ }
+
+ if (0 == strcmp(ini->port_name, "GST_PORT")) {
+ ini->port_type = GST_PORT;
+ } else if (0 == strcmp(ini->port_name, "FFMPEG_PORT")) {
+ ini->port_type = FFMPEG_PORT;
+ } else if (0 == strcmp(ini->port_name, "CUSTOM_PORT")) {
+ ini->port_type = CUSTOM_PORT;
+ } else {
+ MX_E("Invalid port is set to [%s] [%d]\n", ini->port_name,
+ ini->port_type);
+ goto ERROR;
+ }
+ MX_L("The port is set to [%s] [%d]\n", ini->port_name, ini->port_type);
+
+ /* free dict as we got our own structure */
+ iniparser_freedict(dict);
+
+ /* dump structure */
+ MX_L("muxer settings -----------------------------------\n");
+
+ /* general */
+ MX_L("port_name: %s\n", ini->port_name);
+ MX_L("port_type : %d\n", ini->port_type);
+
+ return MM_ERROR_NONE;
+ERROR:
+ return MX_COURRPTED_INI;
+}
+
+static void _mx_ini_check_ini_status(void)
+{
+ struct stat ini_buff;
+
+ if (g_stat(MEDIAMUXER_INI_DEFAULT_PATH, &ini_buff) < 0) {
+ MX_W("failed to get muxer ini status\n");
+ } else {
+ if (ini_buff.st_size < 5) {
+ MX_W("muxer.ini file size=%d, Corrupted! So, Removed\n",
+ (int)ini_buff.st_size);
+
+ if (g_remove(MEDIAMUXER_INI_DEFAULT_PATH) == -1)
+ MX_E("failed to delete corrupted ini");
+ }
+ }
+}
+
+#ifdef MEDIAMUXER_DEFAULT_INI
+static gboolean _generate_default_ini(void)
+{
+ FILE *fp = NULL;
+ gchar *default_ini = MEDIAMUXER_DEFAULT_INI;
+
+ /* create new file */
+ fp = fopen(MEDIAMUXER_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
+
+#endif /* #ifdef _MEDIAMUXER_INI_C_ */
--- /dev/null
+/*
+ * 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 <string.h>
+#include <mm_types.h>
+#include <mm_message.h>
+#include <mm_debug.h>
+#include <mediamuxer.h>
+#include <mediamuxer_ini.h>
+#include <mediamuxer_error.h>
+#include <mediamuxer_private.h>
+#include <mediamuxer_port.h>
+
+/* function type */
+extern int gst_port_register(media_port_muxer_ops *pOps);
+extern int ffmpeg_port_register(media_port_muxer_ops *pOps);
+extern int custom_port_register(media_port_muxer_ops *pOps);
+
+/*
+ * Sequence of functions should be same as the port enumeration "port_mode"
+ * in mx_ini.h file
+ */
+typedef int (*register_port)(media_port_muxer_ops *);
+register_port register_port_func[] = {
+ &gst_port_register,
+ &ffmpeg_port_register,
+ &custom_port_register
+};
+
+int mx_create(MMHandleType *muxer)
+{
+ int result = MX_ERROR_NONE;
+ media_port_muxer_ops *pOps = NULL;
+ mx_handle_t *new_muxer = NULL;
+ MEDIAMUXER_FENTER();
+ new_muxer = (mx_handle_t *) g_malloc(sizeof(mx_handle_t));
+ MEDIAMUXER_CHECK_NULL(new_muxer);
+ memset(new_muxer, 0, sizeof(mx_handle_t));
+
+ /* alloc ops structure */
+ pOps = (media_port_muxer_ops *) g_malloc(sizeof(media_port_muxer_ops));
+ MEDIAMUXER_CHECK_NULL(pOps);
+
+ new_muxer->muxer_ops = pOps;
+ MX_I("mx_create allocating new_demuxer->demuxer_ops %p:\n",
+ new_muxer->muxer_ops);
+ pOps->n_size = sizeof(media_port_muxer_ops);
+ /* load ini files */
+ result = mx_ini_load(&new_muxer->ini);
+ MEDIAMUXER_CHECK_SET_AND_PRINT(result, MX_ERROR_NONE, result,
+ MX_COURRPTED_INI, "can't load ini");
+
+ register_port_func[new_muxer->ini.port_type](pOps);
+ result = pOps->init(&new_muxer->mxport_handle);
+ MEDIAMUXER_CHECK_SET_AND_PRINT(result, MX_ERROR_NONE, result,
+ MX_NOT_INITIALIZED, "mx_create failed");
+ *muxer = (MMHandleType) new_muxer;
+ MEDIAMUXER_FLEAVE();
+ return result;
+ERROR:
+ *muxer = (MMHandleType) 0;
+ if (pOps)
+ g_free(pOps);
+ if (new_muxer)
+ g_free(new_muxer);
+ MEDIAMUXER_FLEAVE();
+ return result;
+}
+
+int mx_set_data_sink(MMHandleType mediamuxer, char *uri, mediamuxer_output_format_e format)
+{
+ int ret = MX_ERROR_NONE;
+ mx_handle_t *mx_handle = (mx_handle_t *) mediamuxer;
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(mx_handle);
+ media_port_muxer_ops *pOps = mx_handle->muxer_ops;
+ MEDIAMUXER_CHECK_NULL(pOps);
+ ret = pOps->set_data_sink(mx_handle->mxport_handle, uri, format);
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+int mx_add_track(MMHandleType mediamuxer, media_format_h media_format, int *track_index)
+{
+ int ret = MX_ERROR_NONE;
+ mx_handle_t *mx_handle = (mx_handle_t *) mediamuxer;
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(mx_handle);
+ media_port_muxer_ops *pOps = mx_handle->muxer_ops;
+ MEDIAMUXER_CHECK_NULL(pOps);
+ ret = pOps->add_track(mx_handle->mxport_handle, media_format, track_index);
+ MEDIAMUXER_CHECK_SET_AND_PRINT(ret, MX_ERROR_NONE, ret, MX_ERROR,
+ "error while adding track");
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+int mx_start(MMHandleType mediamuxer)
+{
+ int ret = MX_ERROR_NONE;
+ mx_handle_t *mx_handle = (mx_handle_t *)(mediamuxer);
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(mx_handle);
+ media_port_muxer_ops *pOps = mx_handle->muxer_ops;
+ MEDIAMUXER_CHECK_NULL(pOps);
+ ret = pOps->start(mx_handle->mxport_handle);
+ MEDIAMUXER_CHECK_SET_AND_PRINT(ret, MX_ERROR_NONE, ret, MX_ERROR,
+ "error while starting");
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+int mx_write_sample(MMHandleType mediamuxer, int track_index, media_packet_h inbuf)
+{
+ int ret = MX_ERROR_NONE;
+ mx_handle_t *mx_handle = (mx_handle_t *) mediamuxer;
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(mx_handle);
+ media_port_muxer_ops *pOps = mx_handle->muxer_ops;
+ MEDIAMUXER_CHECK_NULL(pOps);
+ ret = pOps->write_sample(mx_handle->mxport_handle, track_index, inbuf);
+ MEDIAMUXER_CHECK_SET_AND_PRINT(ret, MX_ERROR_NONE, ret, MX_ERROR,
+ "error while writing sample");
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+int mx_close_track(MMHandleType mediamuxer, int track_index)
+{
+ int ret = MX_ERROR_NONE;
+ mx_handle_t *mx_handle = (mx_handle_t *)(mediamuxer);
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(mx_handle);
+ media_port_muxer_ops *pOps = mx_handle->muxer_ops;
+ MEDIAMUXER_CHECK_NULL(pOps);
+ ret = pOps->close_track(mx_handle->mxport_handle, track_index);
+ MEDIAMUXER_CHECK_SET_AND_PRINT(ret, MX_ERROR_NONE, ret, MX_ERROR,
+ "error while closing track");
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+int mx_pause(MMHandleType mediamuxer)
+{
+ int ret = MX_ERROR_NONE;
+ mx_handle_t *mx_handle = (mx_handle_t *)(mediamuxer);
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(mx_handle);
+ media_port_muxer_ops *pOps = mx_handle->muxer_ops;
+ MEDIAMUXER_CHECK_NULL(pOps);
+ ret = pOps->pause(mx_handle->mxport_handle);
+ MEDIAMUXER_CHECK_SET_AND_PRINT(ret, MX_ERROR_NONE, ret, MX_ERROR,
+ "error while pausing");
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+int mx_resume(MMHandleType mediamuxer)
+{
+ int ret = MX_ERROR_NONE;
+ mx_handle_t *mx_handle = (mx_handle_t *)(mediamuxer);
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(mx_handle);
+ media_port_muxer_ops *pOps = mx_handle->muxer_ops;
+ MEDIAMUXER_CHECK_NULL(pOps);
+ ret = pOps->resume(mx_handle->mxport_handle);
+ MEDIAMUXER_CHECK_SET_AND_PRINT(ret, MX_ERROR_NONE, ret, MX_ERROR,
+ "error while resuming");
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+int mx_stop(MMHandleType mediamuxer)
+{
+ int ret = MX_ERROR_NONE;
+ mx_handle_t *mx_handle = (mx_handle_t *)(mediamuxer);
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(mx_handle);
+ media_port_muxer_ops *pOps = mx_handle->muxer_ops;
+ MEDIAMUXER_CHECK_NULL(pOps);
+ ret = pOps->stop(mx_handle->mxport_handle);
+ MEDIAMUXER_CHECK_SET_AND_PRINT(ret, MX_ERROR_NONE, ret, MX_ERROR,
+ "error while destroying");
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+int mx_destroy(MMHandleType mediamuxer)
+{
+ int ret = MX_ERROR_NONE;
+ mx_handle_t *mx_handle = (mx_handle_t *) mediamuxer;
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(mx_handle);
+ media_port_muxer_ops *pOps = mx_handle->muxer_ops;
+ MEDIAMUXER_CHECK_NULL(pOps);
+ ret = pOps->destroy(mx_handle->mxport_handle);
+ MEDIAMUXER_CHECK_SET_AND_PRINT(ret, MX_ERROR_NONE, ret, MX_ERROR,
+ "error while destroying");
+
+ /* free mediamuxer structure */
+ if (mx_handle) {
+ if (mx_handle->muxer_ops) {
+ MX_I("mx_destroy deallocating mx_handle->muxer_ops %p:\n",
+ mx_handle->muxer_ops);
+ g_free((void *)(mx_handle->muxer_ops));
+ }
+ MX_I("mx_destroy deallocating mx_handle %p:\n", mx_handle);
+ g_free((void *)mx_handle);
+ mx_handle = NULL;
+ }
+ERROR:
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+int mx_set_error_cb(MMHandleType muxer,
+ mediamuxer_error_cb callback, void* user_data)
+{
+ MEDIAMUXER_FENTER();
+ int result = MX_ERROR_NONE;
+ mx_handle_t *mx_handle = (mx_handle_t *) muxer;
+ MEDIAMUXER_CHECK_NULL(mx_handle);
+ media_port_muxer_ops *pOps = mx_handle->muxer_ops;
+ MEDIAMUXER_CHECK_NULL(pOps);
+ result = pOps->set_error_cb(mx_handle->mxport_handle, callback,user_data);
+ MEDIAMUXER_CHECK_SET_AND_PRINT(result, MX_ERROR_NONE, result,
+ MX_ERROR, "error while setting error call back");
+ MEDIAMUXER_FLEAVE();
+ return result;
+ERROR:
+ result = MX_ERROR_INVALID_ARGUMENT;
+ MEDIAMUXER_FLEAVE();
+ return result;
+}
--- /dev/null
+/*
+ * 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 <mm_debug.h>
+#include <mediamuxer_error.h>
+#include <mediamuxer_private.h>
+#include <mediamuxer_port.h>
+#include <mediamuxer_port_custom.h>
+
+static int custom_muxer_init(MMHandleType *pHandle);
+static int custom_muxer_set_data_sink(MMHandleType pHandle, char *uri,
+ mediamuxer_output_format_e format);
+
+/*Media Muxer API common*/
+static media_port_muxer_ops def_mux_ops = {
+ .n_size = 0,
+ .init = custom_muxer_init,
+ .set_data_sink = custom_muxer_set_data_sink,
+};
+
+int custom_port_register(media_port_muxer_ops *pOps)
+{
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(pOps);
+
+ def_mux_ops.n_size = sizeof(def_mux_ops);
+
+ memcpy((char *)pOps + sizeof(pOps->n_size),
+ (char *)&def_mux_ops + sizeof(def_mux_ops.n_size),
+ pOps->n_size - sizeof(pOps->n_size));
+
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ return ret;
+}
+
+static int custom_muxer_init(MMHandleType *pHandle)
+{
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_FENTER();
+ MX_E("%s:exit: Not implemented\n", __func__);
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int custom_muxer_set_data_sink(MMHandleType pHandle, char *uri,
+ mediamuxer_output_format_e format)
+{
+ MEDIAMUXER_FENTER();
+ MX_E("%s:exit: Not implemented\n", __func__);
+ MEDIAMUXER_FLEAVE();
+ return 0;
+}
--- /dev/null
+/*
+ * 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 <mm_debug.h>
+#include <mediamuxer_error.h>
+#include <mediamuxer_private.h>
+#include <mediamuxer_port.h>
+#include <mediamuxer_port_ffmpeg.h>
+
+static int ffmpeg_muxer_init(MMHandleType *pHandle);
+static int ffmpeg_muxer_set_data_sink(MMHandleType pHandle, char *uri,
+ mediamuxer_output_format_e format);
+
+/*Media Muxer API common*/
+static media_port_muxer_ops def_mux_ops = {
+ .n_size = 0,
+ .init = ffmpeg_muxer_init,
+ .set_data_sink = ffmpeg_muxer_set_data_sink,
+};
+
+int ffmpeg_port_register(media_port_muxer_ops *pOps)
+{
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(pOps);
+
+ def_mux_ops.n_size = sizeof(def_mux_ops);
+
+ memcpy((char *)pOps + sizeof(pOps->n_size),
+ (char *)&def_mux_ops + sizeof(def_mux_ops.n_size),
+ pOps->n_size - sizeof(pOps->n_size));
+
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ return ret;
+}
+
+static int ffmpeg_muxer_init(MMHandleType *pHandle)
+{
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_FENTER();
+ MX_E("%s:exit: Not implemented\n", __func__);
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int ffmpeg_muxer_set_data_sink(MMHandleType pHandle, char *uri,
+ mediamuxer_output_format_e format)
+{
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_FENTER();
+ MX_E("%s:exit: Not implemented\n", __func__);
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
--- /dev/null
+/*
+ * 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 <mm_debug.h>
+#include <mediamuxer_error.h>
+#include <mediamuxer_private.h>
+#include <mediamuxer_port.h>
+#include <mediamuxer_port_gst.h>
+
+#define EOS_POLL_PERIOD 1000
+#define WRITE_POLL_PERIOD 100
+/*#define SEND_FULL_CAPS_VIA_CODEC_DATA *//*For debug purpose*/
+#define ASYCHRONOUS_WRITE /*write sample is not blocking */
+
+static int gst_muxer_init(MMHandleType *pHandle);
+static int gst_muxer_set_data_sink(MMHandleType pHandle, char *uri,
+ mediamuxer_output_format_e format);
+static int gst_muxer_add_track(MMHandleType pHandle,
+ media_format_h media_format, int *track_index);
+static int gst_muxer_start(MMHandleType pHandle);
+static int gst_muxer_write_sample(MMHandleType pHandle, int track_index,
+ media_packet_h inbuf);
+static int gst_muxer_close_track(MMHandleType pHandle, int track_index);
+static int gst_muxer_pause(MMHandleType pHandle);
+static int gst_muxer_resume(MMHandleType pHandle);
+static int gst_muxer_stop(MMHandleType pHandle);
+static int gst_muxer_destroy(MMHandleType pHandle);
+static int gst_set_error_cb(MMHandleType pHandle,
+ gst_error_cb callback, void* user_data);
+
+/*Media Muxer API common*/
+static media_port_muxer_ops def_mux_ops = {
+ .n_size = 0,
+ .init = gst_muxer_init,
+ .set_data_sink = gst_muxer_set_data_sink,
+ .add_track = gst_muxer_add_track,
+ .start = gst_muxer_start,
+ .write_sample = gst_muxer_write_sample,
+ .close_track = gst_muxer_close_track,
+ .pause = gst_muxer_pause,
+ .resume = gst_muxer_resume,
+ .stop = gst_muxer_stop,
+ .destroy = gst_muxer_destroy,
+ .set_error_cb = gst_set_error_cb,
+};
+
+int gst_port_register(media_port_muxer_ops *pOps)
+{
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(pOps);
+
+ def_mux_ops.n_size = sizeof(def_mux_ops);
+
+ memcpy((char *)pOps + sizeof(pOps->n_size),
+ (char *)&def_mux_ops + sizeof(def_mux_ops.n_size),
+ pOps->n_size - sizeof(pOps->n_size));
+
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int gst_muxer_init(MMHandleType *pHandle)
+{
+ MEDIAMUXER_FENTER();
+ int ret = MX_ERROR_NONE;
+ mxgst_handle_t *new_mediamuxer = NULL;
+
+ new_mediamuxer = (mxgst_handle_t *) g_malloc(sizeof(mxgst_handle_t));
+ MX_I("GST_Muxer_Init allocating memory for new_mediamuxer: %p\n", new_mediamuxer);
+ if (!new_mediamuxer) {
+ MX_E("Cannot allocate memory for muxer \n");
+ ret = MX_ERROR;
+ goto ERROR;
+ }
+ memset(new_mediamuxer, 0, sizeof(mxgst_handle_t));
+ /* Set desired parameters */
+ new_mediamuxer->output_uri = NULL;
+ new_mediamuxer->muxed_format = -1;
+ new_mediamuxer->video_track.media_format = NULL;
+ new_mediamuxer->audio_track.media_format = NULL;
+ new_mediamuxer->video_track.track_index = -1;
+ new_mediamuxer->audio_track.track_index = -1;
+ new_mediamuxer->video_track.start_feed = 1;
+ new_mediamuxer->audio_track.start_feed = 1;
+ new_mediamuxer->video_track.stop_feed = 0;
+ new_mediamuxer->audio_track.stop_feed = 0;
+
+ MX_I("V.start_feed[%d],V.stop_feed[%d],A.start_feed[%d],A.stop_feed[%d]\n",
+ new_mediamuxer->video_track.start_feed,
+ new_mediamuxer->video_track.stop_feed,
+ new_mediamuxer->audio_track.start_feed,
+ new_mediamuxer->audio_track.stop_feed);
+
+ new_mediamuxer->eos_flg = false;
+ *pHandle = (MMHandleType) new_mediamuxer;
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ MX_E("%s: Not implemented\n", __func__);
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int gst_muxer_set_data_sink(MMHandleType pHandle,
+ char *uri, mediamuxer_output_format_e format)
+{
+ MEDIAMUXER_FENTER();
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_CHECK_NULL(pHandle);
+ mxgst_handle_t *mx_handle_gst = (mxgst_handle_t *) pHandle;
+
+ /* Set desired parameters */
+ mx_handle_gst->output_uri = uri;
+ mx_handle_gst->muxed_format = format;
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ MX_E("muxer handle already NULL, returning \n");
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int gst_muxer_add_track(MMHandleType pHandle,
+ media_format_h media_format, int *track_index)
+{
+ MEDIAMUXER_FENTER();
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_CHECK_NULL(pHandle);
+ mxgst_handle_t *mx_handle_gst = (mxgst_handle_t *) pHandle;
+
+ media_format_mimetype_e mimetype = 0;
+ if (media_format_get_video_info(media_format, &mimetype, NULL, NULL, NULL, NULL) !=
+ MEDIA_FORMAT_ERROR_INVALID_OPERATION) {
+ if (mimetype == MEDIA_FORMAT_H264_SP ||
+ mimetype == MEDIA_FORMAT_H264_MP ||
+ mimetype == MEDIA_FORMAT_H264_HP) {
+ if (mx_handle_gst->video_track.media_format == NULL) {
+ mx_handle_gst->video_track.media_format = (void *)media_format;
+ /* ToDo: track_index should be incremented accordingly for multiple tracks */
+ mx_handle_gst->video_track.track_index = 1;
+ mx_handle_gst->video_track.caps = NULL;
+ *track_index = mx_handle_gst->video_track.track_index;
+ MX_I("Video track added successfully: %p \n", mx_handle_gst->video_track.media_format);
+ } else {
+ MX_E("muxer handle already have a video track, \
+ add failed, as Multiple video tracks are not currently supported");
+ ret = MX_ERROR_NOT_SUPPORT_API;
+ goto ERROR;
+ }
+ }
+ } else if (media_format_get_audio_info(media_format, &mimetype, NULL, NULL, NULL, NULL) !=
+ MEDIA_FORMAT_ERROR_INVALID_OPERATION) {
+ if (mimetype == MEDIA_FORMAT_AAC ||
+ mimetype == MEDIA_FORMAT_AAC_LC ||
+ mimetype == MEDIA_FORMAT_AAC_HE ||
+ mimetype == MEDIA_FORMAT_AAC_HE_PS) {
+ if (mx_handle_gst->audio_track.media_format == NULL) {
+ mx_handle_gst->audio_track.media_format = (void *)media_format;
+ /* ToDo: track_index should be incremented accordingly for multiple tracks */
+ mx_handle_gst->audio_track.track_index = 2;
+ mx_handle_gst->audio_track.caps = NULL;
+ *track_index = mx_handle_gst->audio_track.track_index;
+ MX_I("Audio track added successfully: %p \n", mx_handle_gst->audio_track.media_format);
+ } else {
+ MX_E("muxer handle already have a audio track, add failed, \
+ as Multiple audio tracks are not currently supported");
+ ret = MX_ERROR_NOT_SUPPORT_API;
+ goto ERROR;
+ }
+ } else {
+ MX_E("Unsupported MIME Type\n");
+ }
+ } else {
+ MX_E("Unsupported A/V MIME Type\n");
+ }
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ MX_E(" gst_muxer_add_track failed \n");
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static gint __gst_handle_resource_error(mxgst_handle_t* gst_handle, int code)
+{
+ MEDIAMUXER_FENTER();
+ gint trans_err = MEDIAMUXER_ERROR_NONE;
+ g_return_val_if_fail(gst_handle, MX_PARAM_ERROR);
+
+ switch (code) {
+ /* ToDo: Add individual actions as and when needed */
+ case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
+ trans_err = MX_ERROR_COMMON_NO_FREE_SPACE;
+ break;
+ case GST_RESOURCE_ERROR_WRITE:
+ case GST_RESOURCE_ERROR_FAILED:
+ case GST_RESOURCE_ERROR_SEEK:
+ case GST_RESOURCE_ERROR_TOO_LAZY:
+ case GST_RESOURCE_ERROR_BUSY:
+ case GST_RESOURCE_ERROR_OPEN_WRITE:
+ case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
+ case GST_RESOURCE_ERROR_CLOSE:
+ case GST_RESOURCE_ERROR_SYNC:
+ case GST_RESOURCE_ERROR_SETTINGS:
+ default:
+ trans_err = MX_INTERNAL_ERROR;
+ break;
+ }
+ MEDIAMUXER_FLEAVE();
+ return trans_err;
+}
+
+static gint __gst_handle_core_error(mxgst_handle_t* gst_handle, int code)
+{
+ MEDIAMUXER_FENTER();
+ gint trans_err = MEDIAMUXER_ERROR_NONE;
+
+ /* g_return_val_if_fail(core, MX_PARAM_ERROR); */
+ switch (code) {
+ /* ToDo: Add individual actions as and when needed */
+ case GST_CORE_ERROR_MISSING_PLUGIN:
+ case GST_CORE_ERROR_STATE_CHANGE:
+ case GST_CORE_ERROR_SEEK:
+ case GST_CORE_ERROR_NOT_IMPLEMENTED:
+ case GST_CORE_ERROR_FAILED:
+ case GST_CORE_ERROR_TOO_LAZY:
+ case GST_CORE_ERROR_PAD:
+ case GST_CORE_ERROR_THREAD:
+ case GST_CORE_ERROR_NEGOTIATION:
+ case GST_CORE_ERROR_EVENT:
+ case GST_CORE_ERROR_CAPS:
+ case GST_CORE_ERROR_TAG:
+ case GST_CORE_ERROR_CLOCK:
+ case GST_CORE_ERROR_DISABLED:
+ default:
+ trans_err = MX_INTERNAL_ERROR;
+ break;
+ }
+ MEDIAMUXER_FLEAVE();
+ return trans_err;
+}
+
+static gint __gst_handle_library_error(mxgst_handle_t* gst_handle, int code)
+{
+ MEDIAMUXER_FENTER();
+ gint trans_err = MEDIAMUXER_ERROR_NONE;
+ g_return_val_if_fail(gst_handle, MX_PARAM_ERROR);
+
+ switch (code) {
+ /* ToDo: Add individual actions as and when needed */
+ case GST_LIBRARY_ERROR_FAILED:
+ case GST_LIBRARY_ERROR_TOO_LAZY:
+ case GST_LIBRARY_ERROR_INIT:
+ case GST_LIBRARY_ERROR_SHUTDOWN:
+ case GST_LIBRARY_ERROR_SETTINGS:
+ case GST_LIBRARY_ERROR_ENCODE:
+ default:
+ trans_err = MX_INTERNAL_ERROR;
+ break;
+ }
+ MEDIAMUXER_FLEAVE();
+ return trans_err;
+}
+
+static gboolean _mx_gst_bus_call(GstBus *bus, GstMessage *msg, gpointer data)
+{
+ MEDIAMUXER_FENTER();
+ int ret = MX_ERROR_NONE;
+ mxgst_handle_t *gst_handle = (mxgst_handle_t*)data;
+ switch (GST_MESSAGE_TYPE(msg)) {
+ case GST_MESSAGE_EOS:
+ MX_I("End of stream\n");
+ break;
+ case GST_MESSAGE_ERROR: {
+ gchar *debug;
+ GError *error;
+ gst_message_parse_error(msg, &error, &debug);
+ if (!error) {
+ MX_E("GST error message parsing failed");
+ break;
+ }
+ MX_E("Error: %s\n", error->message);
+ if (error) {
+ if (error->domain == GST_RESOURCE_ERROR)
+ ret = __gst_handle_resource_error(gst_handle, error->code);
+ else if (error->domain == GST_LIBRARY_ERROR)
+ ret = __gst_handle_library_error(gst_handle, error->code);
+ else if (error->domain == GST_CORE_ERROR)
+ ret = __gst_handle_core_error(gst_handle, error->code);
+ else
+ MX_E("Unexpected error has occured");
+ /* ToDo: Update the user callback with ret... */
+ return ret;
+ }
+ g_free(debug);
+ MX_E("Error: %s\n", error->message);
+ g_error_free(error);
+ }
+ break;
+ default:
+ MX_E("unhandled message: 0x%x", GST_MESSAGE_TYPE(msg));
+ break;
+ }
+ MEDIAMUXER_FLEAVE();
+ return TRUE;
+}
+
+/*
+ * This signal callback triggers when appsrc needs mux_data.
+ * Here, we add an idle handler to the mainloop to start pushing data into the appsrc
+ */
+static void _audio_start_feed(GstElement *source, guint size, mxgst_handle_t *gst_handle)
+{
+ MX_I("\nAudio Start feeding...\n");
+ gst_handle->audio_track.stop_feed = 0;
+ gst_handle->audio_track.start_feed = 1;
+}
+
+static void _video_start_feed(GstElement *source, guint size, mxgst_handle_t *gst_handle)
+{
+ MX_I("\nVideo Start feeding cb...\n");
+ gst_handle->video_track.stop_feed = 0;
+ gst_handle->video_track.start_feed = 1;
+}
+
+/*
+ * This callback triggers when appsrc has enough data and we can stop sending.
+ * We remove the idle handler from the mainloop.
+ */
+static void _audio_stop_feed(GstElement *source, mxgst_handle_t *gst_handle)
+{
+ MX_I("\nAudio Stop feeding cb...\n");
+ gst_handle->audio_track.stop_feed = 1;
+ gst_handle->audio_track.start_feed = 0;
+}
+
+static void _video_stop_feed(GstElement *source, mxgst_handle_t *gst_handle)
+{
+ MX_I("\nVideo Stop feeding...\n");
+ gst_handle->video_track.stop_feed = 1;
+ gst_handle->video_track.start_feed = 0;
+}
+
+mx_ret_e _gst_create_pipeline(mxgst_handle_t *gst_handle)
+{
+ MEDIAMUXER_FENTER();
+ gint ret = MX_ERROR_NONE;
+ GstBus *bus = NULL;
+ /* Note: Use a loop, if needed. GMainLoop *loop; */
+ GstPad *audio_pad, *video_pad, *aud_src, *vid_src;
+
+ /* Initialize GStreamer */
+ /* Note: Replace the arguments of gst_init to pass the command line args to GStreamer. */
+ gst_init(NULL, NULL);
+
+ /* Create the empty pipeline */
+ gst_handle->pipeline = gst_pipeline_new("Muxer Gst pipeline");
+
+ if (gst_handle->muxed_format == MEDIAMUXER_CONTAINER_FORMAT_MP4) {
+ gst_handle->muxer = gst_element_factory_make("qtmux", "media-muxer");
+ /* gst_element_factory_make("mp4mux", "media-muxer"); */
+ if (gst_handle->video_track.track_index == 1) { /* Video track */
+ gst_handle->video_appsrc = gst_element_factory_make("appsrc", "video appsrc");
+ gst_handle->videoparse = gst_element_factory_make("h264parse", "h264parse");
+ }
+ if (gst_handle->audio_track.track_index == 2) { /* Audio track */
+ gst_handle->audio_appsrc = gst_element_factory_make("appsrc", "audio appsrc");
+ gst_handle->audioparse = gst_element_factory_make("aacparse", "aacparse");
+ }
+ } else {
+ MX_E("Unsupported format. Currently suports only MPEG4");
+ ret = MEDIAMUXER_ERROR_INVALID_PATH;
+ goto ERROR;
+ }
+ gst_handle->sink = gst_element_factory_make("filesink", "muxer filesink");
+
+ if (!gst_handle->pipeline || !gst_handle->muxer || !gst_handle->sink) {
+ MX_E("One element could not be created. Exiting.\n");
+ ret = MEDIAMUXER_ERROR_RESOURCE_LIMIT;
+ goto ERROR;
+ }
+
+ /* Build the pipeline */
+ gst_bin_add_many(GST_BIN(gst_handle->pipeline),
+ gst_handle->muxer,
+ gst_handle->sink,
+ NULL);
+
+ if (gst_handle->video_track.track_index == 1) {
+ /* video track */
+ if (!gst_handle->video_appsrc || !gst_handle->videoparse) {
+ MX_E("One element (vparse) could not be created. Exiting.\n");
+ ret = MEDIAMUXER_ERROR_RESOURCE_LIMIT;
+ goto ERROR;
+ }
+ gst_bin_add_many(GST_BIN(gst_handle->pipeline),
+ gst_handle->video_appsrc,
+ gst_handle->videoparse,
+ NULL);
+ /* Set video caps for corresponding src elements */
+ g_object_set(gst_handle->video_appsrc, "caps",
+ gst_caps_from_string(gst_handle->video_track.caps), NULL);
+#ifdef ASYCHRONOUS_WRITE
+ g_signal_connect(gst_handle->video_appsrc, "need-data",
+ G_CALLBACK(_video_start_feed), gst_handle);
+ g_signal_connect(gst_handle->video_appsrc, "enough-data",
+ G_CALLBACK(_video_stop_feed), gst_handle);
+#else
+ g_object_set(gst_handle->video_appsrc, "block", TRUE, NULL);
+ gst_app_src_set_stream_type((GstAppSrc *)gst_handle->video_appsrc,
+ GST_APP_STREAM_TYPE_STREAM);
+#endif
+ }
+
+ if (gst_handle->audio_track.track_index == 2) {
+ /* Audio track */
+ if (!gst_handle->audio_appsrc || !gst_handle->audioparse) {
+ MX_E("One element (aparse) could not be created. Exiting.\n");
+ ret = MEDIAMUXER_ERROR_RESOURCE_LIMIT;
+ goto ERROR;
+ }
+ gst_bin_add_many(GST_BIN(gst_handle->pipeline),
+ gst_handle->audio_appsrc,
+ gst_handle->audioparse,
+ NULL);
+ /* Set audio caps for corresponding src elements */
+ g_object_set(gst_handle->audio_appsrc, "caps",
+ gst_caps_from_string(gst_handle->audio_track.caps), NULL);
+#ifdef ASYCHRONOUS_WRITE
+ g_signal_connect(gst_handle->audio_appsrc, "need-data",
+ G_CALLBACK(_audio_start_feed), gst_handle);
+ g_signal_connect(gst_handle->audio_appsrc, "enough-data",
+ G_CALLBACK(_audio_stop_feed), gst_handle);
+#else
+ g_object_set(gst_handle->audio_appsrc, "block", TRUE, NULL);
+ gst_app_src_set_stream_type((GstAppSrc *)gst_handle->audio_appsrc,
+ GST_APP_STREAM_TYPE_STREAM);
+#endif
+ }
+
+ if (!gst_element_link(gst_handle->muxer, gst_handle->sink))
+ MX_E("muxer-sink link failed");
+
+ if (gst_handle->video_track.track_index == 1) {
+ /* video track */
+ gst_element_link(gst_handle->video_appsrc, gst_handle->videoparse);
+ /* Link videoparse to muxer_video_pad. Request for muxer A/V pads. */
+ video_pad = gst_element_get_request_pad(gst_handle->muxer, "video_00");
+ vid_src = gst_element_get_static_pad(gst_handle->videoparse, "src");
+ if (gst_pad_link(vid_src, video_pad) != GST_PAD_LINK_OK)
+ MX_E("video parser to muxer link failed");
+ }
+
+ if (gst_handle->audio_track.track_index == 2) {
+ /* audio track */
+ /* we add all elements into the pipeline */
+ gst_element_link(gst_handle->audio_appsrc, gst_handle->audioparse);
+ /* Link audioparse to muxer_audio_pad. Request for muxer A/V pads. */
+ audio_pad = gst_element_get_request_pad(gst_handle->muxer, "audio_00");
+ aud_src = gst_element_get_static_pad(gst_handle->audioparse, "src");
+ if (gst_pad_link(aud_src, audio_pad) != GST_PAD_LINK_OK)
+ MX_E("audio parser to muxer link failed");
+ }
+
+ MX_I("Output_uri= %s\n", gst_handle->output_uri);
+ g_object_set(GST_OBJECT(gst_handle->sink), "location",
+ gst_handle->output_uri, NULL);
+
+ /* connect signals, bus watcher */
+ bus = gst_pipeline_get_bus(GST_PIPELINE(gst_handle->pipeline));
+ gst_handle->bus_watch_id = gst_bus_add_watch(bus, _mx_gst_bus_call, gst_handle);
+ gst_object_unref(bus);
+
+ /* set pipeline state to PLAYING */
+ MEDIAMUXER_ELEMENT_SET_STATE(GST_ELEMENT_CAST(gst_handle->pipeline),
+ GST_STATE_PLAYING);
+ return MX_ERROR_NONE;
+
+STATE_CHANGE_FAILED:
+ERROR:
+
+ if (gst_handle->pipeline)
+ gst_object_unref(GST_OBJECT(gst_handle->pipeline));
+
+ if (gst_handle->video_track.track_index == 1) { /* Video track */
+ if (gst_handle->videoparse)
+ gst_object_unref(GST_OBJECT(gst_handle->videoparse));
+
+ if (gst_handle->video_appsrc)
+ gst_object_unref(GST_OBJECT(gst_handle->video_appsrc));
+ }
+
+ if (gst_handle->audio_track.track_index == 2) { /* audio track */
+ if (gst_handle->audio_appsrc)
+ gst_object_unref(GST_OBJECT(gst_handle->audio_appsrc));
+ if (gst_handle->audioparse)
+ gst_object_unref(GST_OBJECT(gst_handle->audioparse));
+ }
+
+ if (gst_handle->muxer)
+ gst_object_unref(GST_OBJECT(gst_handle->muxer));
+
+ if (gst_handle->sink)
+ gst_object_unref(GST_OBJECT(gst_handle->sink));
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int gst_muxer_start(MMHandleType pHandle)
+{
+ MEDIAMUXER_FENTER();
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_CHECK_NULL(pHandle);
+ mxgst_handle_t *new_mediamuxer = (mxgst_handle_t *) pHandle;
+
+ MX_I("__gst_muxer_start adding elements to the pipeline:%p\n", new_mediamuxer);
+ ret = _gst_create_pipeline(new_mediamuxer);
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ MX_E("muxer handle NULL, returning \n");
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+int __gst_codec_specific_caps(GstCaps *new_cap,
+ media_format_mimetype_e mimetype)
+{
+ MEDIAMUXER_FENTER();
+ GValue val = G_VALUE_INIT;
+ switch (mimetype) {
+ /*video*/
+ case MEDIA_FORMAT_H261:
+ break;
+ case MEDIA_FORMAT_H263:
+ break;
+ case MEDIA_FORMAT_H263P:
+ break;
+ case MEDIA_FORMAT_H264_SP:
+ break;
+ case MEDIA_FORMAT_H264_MP:
+ break;
+ case MEDIA_FORMAT_H264_HP:
+ break;
+ case MEDIA_FORMAT_MJPEG:
+ break;
+ case MEDIA_FORMAT_MPEG1:
+ break;
+ case MEDIA_FORMAT_MPEG2_SP:
+ break;
+ case MEDIA_FORMAT_MPEG2_MP:
+ break;
+ case MEDIA_FORMAT_MPEG2_HP:
+ break;
+ case MEDIA_FORMAT_MPEG4_SP:
+ break;
+ case MEDIA_FORMAT_MPEG4_ASP:
+ break;
+ case MEDIA_FORMAT_HEVC:
+ break;
+ case MEDIA_FORMAT_VP8:
+ break;
+ case MEDIA_FORMAT_VP9:
+ break;
+ case MEDIA_FORMAT_VC1:
+ break;
+ case MEDIA_FORMAT_I420:
+ break;
+ case MEDIA_FORMAT_NV12:
+ break;
+ case MEDIA_FORMAT_NV12T:
+ break;
+ case MEDIA_FORMAT_YV12:
+ break;
+ case MEDIA_FORMAT_NV21:
+ break;
+ case MEDIA_FORMAT_NV16:
+ break;
+ case MEDIA_FORMAT_YUYV:
+ break;
+ case MEDIA_FORMAT_UYVY:
+ break;
+ case MEDIA_FORMAT_422P:
+ break;
+ case MEDIA_FORMAT_RGB565:
+ break;
+ case MEDIA_FORMAT_RGB888:
+ break;
+ case MEDIA_FORMAT_RGBA:
+ break;
+ case MEDIA_FORMAT_ARGB:
+ break;
+ /*audio*/
+ case MEDIA_FORMAT_L16:
+ break;
+ case MEDIA_FORMAT_ALAW:
+ break;
+ case MEDIA_FORMAT_ULAW:
+ break;
+ case MEDIA_FORMAT_AMR:
+ break;
+ case MEDIA_FORMAT_AMR_WB:
+ break;
+ case MEDIA_FORMAT_G729:
+ break;
+ case MEDIA_FORMAT_AAC:
+ g_value_init(&val, G_TYPE_INT);
+ g_value_set_int(&val, 4);
+ gst_caps_set_value(new_cap, "mpegversion", &val);
+ break;
+ case MEDIA_FORMAT_AAC_HE:
+ g_value_init(&val, G_TYPE_INT);
+ g_value_set_int(&val, 4);
+ gst_caps_set_value(new_cap, "mpegversion", &val);
+ break;
+ case MEDIA_FORMAT_AAC_HE_PS:
+ g_value_init(&val, G_TYPE_INT);
+ g_value_set_int(&val, 4);
+ gst_caps_set_value(new_cap, "mpegversion", &val);
+ break;
+ case MEDIA_FORMAT_MP3:
+ break;
+ case MEDIA_FORMAT_VORBIS:
+ break;
+ case MEDIA_FORMAT_PCM:
+ break;
+ case MEDIA_FORMAT_PCMA:
+ break;
+ case MEDIA_FORMAT_PCMU:
+ break;
+ default:
+ MX_E("Unknown media mimeype %d. Assuming H264\n", mimetype);
+ break;
+ }
+ MEDIAMUXER_FLEAVE();
+ return 0;
+}
+
+
+int _gst_set_caps(MMHandleType pHandle, media_packet_h packet)
+{
+ MEDIAMUXER_FENTER();
+ gint ret = MX_ERROR_NONE;
+ GstCaps *new_cap;
+ media_format_mimetype_e mimetype;
+ media_format_h format;
+ GValue val = G_VALUE_INIT;
+ int numerator;
+ int denominator = 1;
+ int channel;
+ int samplerate;
+ int bit;
+ int width;
+ int height;
+ int avg_bps;
+ int max_bps;
+ gchar *caps_string = NULL;
+
+ mxgst_handle_t *gst_handle = (mxgst_handle_t *) pHandle;
+ media_format_type_e formattype;
+ char *codec_data;
+ unsigned int codec_data_size;
+
+ if (media_packet_get_format(packet, &format)) {
+ MX_E("media_format_get_formati call failed \n");
+ goto ERROR;
+ }
+
+ if (media_format_get_type(format, &formattype)) {
+ MX_E("media_format_get_type failed\n");
+ goto ERROR;
+ }
+
+ switch (formattype) {
+ case MEDIA_FORMAT_AUDIO:
+ if (media_packet_get_codec_data(packet,
+ (void **)&codec_data, &codec_data_size)) {
+ MX_E("media_packet_get_codec_data call failed\n");
+ ret = MX_ERROR_UNKNOWN;
+ break;
+ }
+ MX_I("extracted codec data is =%s size is %d\n",
+ codec_data, codec_data_size);
+ if (gst_handle->audio_track.caps == NULL ||
+ g_strcmp0(codec_data, gst_handle->audio_track.caps) != 0) {
+
+#ifndef SEND_FULL_CAPS_VIA_CODEC_DATA
+
+ if (media_format_get_audio_info(format,
+ &mimetype, &channel, &samplerate,
+ &bit, &avg_bps)) {
+ MX_E("media_format_get_audio_info call failed\n");
+ ret = MX_ERROR_UNKNOWN;
+ break;
+ }
+ if (gst_handle->audio_track.caps == NULL) {
+ gst_handle->audio_track.caps =
+ (char *)g_malloc(codec_data_size);
+ if (gst_handle->audio_track.caps == NULL) {
+ MX_E("[%s][%d]memory allocation failed\n",
+ __func__, __LINE__);
+ ret = MX_ERROR_UNKNOWN;
+ break;
+ }
+ }
+ new_cap = gst_caps_from_string(codec_data);
+ if (__gst_codec_specific_caps(new_cap, mimetype)) {
+ MX_E("Setting Audio caps failed\n");
+ gst_caps_unref(new_cap);
+ ret = MX_ERROR_UNKNOWN;
+ break;
+ }
+ caps_string = gst_caps_to_string(new_cap);
+ MX_I("New cap set by codec data is=%s\n",
+ caps_string);
+ if (caps_string)
+ g_free(caps_string);
+ g_object_set(gst_handle->audio_appsrc,
+ "caps", new_cap, NULL);
+ g_stpcpy(gst_handle->audio_track.caps, codec_data);
+#else
+ /*Debugging purpose. The whole caps filter can be sent via codec_data*/
+ new_cap = gst_caps_from_string(codec_data);
+ MX_I("codec cap is=%s\n", codec_data);
+ g_object_set(gst_handle->audio_appsrc,
+ "caps", new_cap, NULL);
+ if (gst_handle->audio_track.caps == NULL) {
+ gst_handle->audio_track.caps =
+ (char *)g_malloc(codec_data_size);
+ if (gst_handle->audio_track.caps == NULL) {
+ MX_E("[%s][%d] \
+ memory allocation failed\n",
+ __func__, __LINE__);
+ gst_caps_unref(new_cap);
+ ret = MX_ERROR_UNKNOWN;
+ break;
+ }
+ }
+ g_stpcpy(gst_handle->audio_track.caps, codec_data);
+#endif
+ gst_caps_unref(new_cap);
+ }
+ break;
+ case MEDIA_FORMAT_VIDEO:
+ if (media_packet_get_codec_data(packet,
+ (void **)&codec_data, &codec_data_size)) {
+ MX_E("media_packet_get_codec_data call failed\n");
+ ret = MX_ERROR_UNKNOWN;
+ break;
+ }
+ MX_I("codec data is =%s size is %d\n",
+ codec_data, codec_data_size);
+ if (gst_handle->video_track.caps == NULL ||
+ g_strcmp0(codec_data, gst_handle->video_track.caps) != 0) {
+
+#ifndef SEND_FULL_CAPS_VIA_CODEC_DATA
+
+ if (media_format_get_video_info(format,
+ &mimetype, &width, &height,
+ &avg_bps, &max_bps)) {
+ MX_E("media_format_get_video_info call failed\n");
+ ret = MX_ERROR_UNKNOWN;
+ break;
+ }
+ if (gst_handle->video_track.caps == NULL) {
+ gst_handle->video_track.caps =
+ (char *)g_malloc(codec_data_size);
+ if (gst_handle->video_track.caps == NULL) {
+ MX_E("[%s][%d] \
+ memory allocation failed\n",
+ __func__, __LINE__);
+ ret = MX_ERROR_UNKNOWN;
+ break;
+ }
+ }
+ new_cap = gst_caps_from_string(codec_data);
+ MX_I("New cap set by codec data is=%s\n",
+ codec_data);
+ if (__gst_codec_specific_caps(new_cap, mimetype)) {
+ MX_E("Setting Audio caps failed\n");
+ gst_caps_unref(new_cap);
+ ret = MX_ERROR_UNKNOWN;
+ break;
+ }
+ g_stpcpy(gst_handle->video_track.caps, codec_data);
+
+ if (media_format_get_video_frame_rate(format,
+ &numerator)) {
+ MX_E("media_format_get_video_info call failed\n");
+ }
+ g_value_init(&val, GST_TYPE_FRACTION);
+ gst_value_set_fraction(&val, numerator, denominator);
+ gst_caps_set_value(new_cap, "framerate", &val);
+ caps_string = gst_caps_to_string(new_cap);
+ MX_I("New cap set by codec data is=%s\n",
+ caps_string);
+ if (caps_string)
+ g_free(caps_string);
+ g_object_set(gst_handle->video_appsrc, "caps",
+ new_cap, NULL);
+#else
+ /*Debugging purpose. The whole caps filter can be sent via codec_data*/
+ media_packet_get_codec_data(packet, &codec_data,
+ &codec_data_size);
+ MX_I("extracted codec data is =%s\n", codec_data);
+ new_cap = gst_caps_from_string(codec_data);
+ MX_I("New cap is=%s\n", codec_data);
+ g_object_set(gst_handle->video_appsrc, "caps",
+ new_cap, NULL);
+ if (gst_handle->video_track.caps == NULL) {
+ gst_handle->video_track.caps =
+ (char *)g_malloc(codec_data_size);
+ if (gst_handle->video_track.caps == NULL) {
+ MX_E("[%s][%d] \
+ memory allocation failed\n",
+ __func__, __LINE__);
+ gst_caps_unref(new_cap);
+ ret = MX_ERROR_UNKNOWN;
+ break;
+ }
+ }
+ g_stpcpy(gst_handle->video_track.caps, codec_data);
+#endif
+ gst_caps_unref(new_cap);
+ }
+ break;
+ case MEDIA_FORMAT_CONTAINER:
+ case MEDIA_FORMAT_TEXT:
+ case MEDIA_FORMAT_UNKNOWN:
+ default:
+ MX_E("Unknown format type\n");
+ }
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ ret = MX_ERROR_UNKNOWN;
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int _gst_copy_media_packet_to_buf(media_packet_h out_pkt,
+ GstBuffer *buffer)
+{
+ MEDIAMUXER_FENTER();
+ void *pkt_data;
+ uint64_t size;
+ unsigned char *data_ptr;
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(out_pkt);
+ /* GstMapInfo map; */
+ int ret = MX_ERROR_NONE;
+ /* copy data*/
+ media_packet_get_buffer_size(out_pkt, &size);
+ MX_I("Media packet Buffer capacity: %llu\n", size);
+ data_ptr = (unsigned char *) g_malloc(size);
+ if (!data_ptr) {
+ MX_E("Memory allocation failed in %s \n", __FUNCTION__);
+ ret = MX_MEMORY_ERROR;
+ goto ERROR;
+ }
+
+ if (media_packet_get_buffer_data_ptr(out_pkt, &pkt_data)) {
+ MX_E("unable to get the buffer pointer \
+ from media_packet_get_buffer_data_ptr\n");
+ ret = MX_ERROR_UNKNOWN;
+ goto ERROR;
+ }
+ /*if (!gst_buffer_map (buffer, &map, GST_MAP_READ)) {
+ MX_E("gst_buffer_map failed\n");
+ ret = MX_ERROR_UNKNOWN;
+ goto ERROR;
+ }*/
+ uint64_t info;
+ memcpy(data_ptr, (char *)pkt_data, size);
+ gst_buffer_insert_memory(buffer, -1,
+ gst_memory_new_wrapped(0, data_ptr, size, 0,
+ size, data_ptr, g_free));
+
+ if (media_packet_get_pts(out_pkt, &info)) {
+ MX_E("unable to get the pts\n");
+ ret = MX_ERROR_UNKNOWN;
+ goto ERROR;
+ }
+ buffer->pts = info;
+
+ if (media_packet_get_dts(out_pkt, &info)) {
+ MX_E("unable to get the dts\n");
+ ret = MX_ERROR_UNKNOWN;
+ goto ERROR;
+ }
+ buffer->dts = info;
+ if (media_packet_get_duration(out_pkt, &info)) {
+ MX_E("unable to get the duration\n");
+ ret = MX_ERROR_UNKNOWN;
+ goto ERROR;
+ }
+ buffer->duration = info;
+ /*TBD: set falgs is not available now in media_packet*/
+ media_buffer_flags_e flags;
+ if (media_packet_get_flags(out_pkt, &flags)) {
+ MX_E("unable to get the buffer size\n");
+ ret = MX_ERROR_UNKNOWN;
+ goto ERROR;
+ }
+ GST_BUFFER_FLAG_SET(buffer, flags);
+ERROR:
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int gst_muxer_write_sample(MMHandleType pHandle, int track_index,
+ media_packet_h inbuf)
+{
+ MEDIAMUXER_FENTER();
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_CHECK_NULL(pHandle);
+ mxgst_handle_t *gst_handle = (mxgst_handle_t *) pHandle;
+
+ _gst_set_caps(pHandle, inbuf);
+ MX_I("\nTrack_index=%d", track_index);
+
+ GstBuffer *gst_inbuf2 = NULL;
+ gst_inbuf2 = gst_buffer_new();
+ /* ToDo: Add functionality to the following function */
+ /* MX_I("\nBefore buff=%x", gst_inbuf2); */
+ _gst_copy_media_packet_to_buf(inbuf, gst_inbuf2);
+
+ if ((gst_handle->video_track.track_index != -1) &&
+ (track_index == gst_handle->video_track.track_index)) {
+ MX_I("\n pushing video");
+#ifdef ASYCHRONOUS_WRITE
+ /*poll now to make it synchronous*/
+ while (gst_handle->video_track.start_feed == 0) {
+ g_usleep(WRITE_POLL_PERIOD);
+ }
+ g_signal_emit_by_name(gst_handle->video_appsrc, "push-buffer", gst_inbuf2, &ret);
+#else
+ ret = gst_app_src_push_buffer((GstAppSrc *)gst_handle->video_appsrc, gst_inbuf2);
+#endif
+ MX_I("\n attempted a vid-buf push");
+ if (ret != GST_FLOW_OK) {
+ /* We got some error, stop sending data */
+ MX_E("--video appsrc push failed--");
+ }
+ } else if ((gst_handle->audio_track.track_index != -1) &&
+ (track_index == gst_handle->audio_track.track_index)) {
+ MX_I("\n pushing audio");
+#ifdef ASYCHRONOUS_WRITE
+ while (gst_handle->audio_track.start_feed == 0) {
+ g_usleep(WRITE_POLL_PERIOD);
+ }
+ g_signal_emit_by_name(gst_handle->audio_appsrc, "push-buffer", gst_inbuf2, &ret);
+#else
+ ret = gst_app_src_push_buffer((GstAppSrc *)gst_handle->audio_appsrc, gst_inbuf2);
+#endif
+ MX_I("\n attempted a aud-buf push");
+ if (ret != GST_FLOW_OK) {
+ /* We got some error, stop sending data */
+ MX_E("--audio appsrc push failed--");
+ }
+ } else {
+ MX_E("\nUnsupported track index. Only 1/2 track index is vaild");
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ }
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int gst_muxer_close_track(MMHandleType pHandle, int track_index)
+{
+ MEDIAMUXER_FENTER();
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_CHECK_NULL(pHandle);
+ mxgst_handle_t *gst_handle = (mxgst_handle_t *) pHandle;
+
+ MX_I("__gst_muxer_stop setting eos to sources:%p\n", gst_handle);
+ if (gst_handle->pipeline!= NULL) {
+ if (gst_handle->audio_track.track_index == track_index) {
+ MX_I("\n-----EOS for audioappsrc-----\n");
+ gst_app_src_end_of_stream((GstAppSrc *)(gst_handle->audio_appsrc));
+ } else if (gst_handle->video_track.track_index == track_index) {
+ MX_I("\n-----EOS for videoappsrc-----\n");
+ gst_app_src_end_of_stream((GstAppSrc *)(gst_handle->video_appsrc));
+ } else {
+ MX_E("\nInvalid track Index[%d].\n", track_index);
+ goto ERROR;
+ }
+ }
+ if (gst_handle->audio_track.track_index == track_index) {
+ gst_handle->audio_track.media_format = NULL;
+ gst_handle->audio_track.track_index = -1;
+ } else if (gst_handle->video_track.track_index == track_index) {
+ gst_handle->video_track.media_format = NULL;
+ gst_handle->video_track.track_index = -1;
+ }
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int gst_muxer_pause(MMHandleType pHandle)
+{
+ MEDIAMUXER_FENTER();
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_CHECK_NULL(pHandle);
+ mxgst_handle_t *gst_handle = (mxgst_handle_t *) pHandle;
+
+ GstState state;
+ MX_I("gst_muxer_pause setting pipeline to pause");
+ gst_element_get_state(gst_handle->pipeline, &state, NULL, GST_CLOCK_TIME_NONE);
+ if (state == GST_STATE_PLAYING) {
+ if (gst_element_set_state(gst_handle->pipeline, GST_STATE_PAUSED) ==
+ GST_STATE_CHANGE_FAILURE) {
+ MX_I("Setting pipeline to pause failed");
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ }
+ } else {
+ MX_I("pipeline is not in playing, PAUSE is intended to pause a playing pipeline. \
+ exiting with out state change");
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ }
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int gst_muxer_resume(MMHandleType pHandle)
+{
+ MEDIAMUXER_FENTER();
+ MEDIAMUXER_CHECK_NULL(pHandle);
+ int ret = MX_ERROR_NONE;
+ mxgst_handle_t *gst_handle = (mxgst_handle_t *) pHandle;
+
+ MX_I("gst_muxer_resume setting pipeline to playing");
+ if (gst_element_set_state(gst_handle->pipeline, GST_STATE_PLAYING) ==
+ GST_STATE_CHANGE_FAILURE) {
+ MX_I("Setting pipeline to resume failed");
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ }
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+mx_ret_e _gst_destroy_pipeline(mxgst_handle_t *gst_handle)
+{
+ gint ret = MX_ERROR_NONE;
+ MEDIAMUXER_FENTER();
+
+ /* Clean up nicely */
+ gst_element_set_state(gst_handle->pipeline, GST_STATE_NULL);
+
+ /* Free resources & set unused pointers to NULL */
+ if (gst_handle->output_uri != NULL) {
+ gst_handle->output_uri = NULL;
+ }
+
+ if (gst_handle->video_track.track_index == 1) { /* Video track */
+ if (gst_handle->video_track.caps != NULL) {
+ g_free(gst_handle->video_track.caps);
+ }
+
+ if (gst_handle->video_track.media_format != NULL) {
+ gst_handle->video_track.media_format = NULL;
+ }
+ }
+
+ if (gst_handle->audio_track.track_index == 2) { /* audio track */
+ if (gst_handle->audio_track.caps != NULL) {
+ g_free(gst_handle->audio_track.caps);
+ }
+
+ if (gst_handle->audio_track.media_format != NULL) {
+ gst_handle->audio_track.media_format = NULL;
+ }
+ }
+
+ if (gst_handle->pipeline)
+ gst_object_unref(GST_OBJECT(gst_handle->pipeline));
+
+ g_source_remove(gst_handle->bus_watch_id);
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int gst_muxer_stop(MMHandleType pHandle)
+{
+ MEDIAMUXER_FENTER();
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_CHECK_NULL(pHandle);
+ mxgst_handle_t *gst_handle = (mxgst_handle_t *) pHandle;
+
+ MX_I("__gst_muxer_stop setting eos to sources:%p\n", gst_handle);
+ ret = _gst_destroy_pipeline(gst_handle);
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+static int gst_muxer_destroy(MMHandleType pHandle)
+{
+ MEDIAMUXER_FENTER();
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_CHECK_NULL(pHandle);
+ mxgst_handle_t *new_mediamuxer = (mxgst_handle_t *) pHandle;
+
+ MX_I("__gst_muxer_destroy deallocating new_mediamuxer:%p\n", new_mediamuxer);
+ g_free(new_mediamuxer);
+ MEDIAMUXER_FLEAVE();
+ return ret;
+ERROR:
+ MX_E("muxer handle already NULL, returning \n");
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
+
+int gst_set_error_cb(MMHandleType pHandle, gst_error_cb callback, void* user_data)
+{
+ MEDIAMUXER_FENTER();
+ int ret = MX_ERROR_NONE;
+ MEDIAMUXER_CHECK_NULL(pHandle);
+ mxgst_handle_t *gst_handle = (mxgst_handle_t *) pHandle;
+
+ if (!gst_handle) {
+ MX_E("fail invaild param\n");
+ ret = MX_INVALID_ARG;
+ goto ERROR;
+ }
+
+ if (gst_handle->user_cb[_GST_EVENT_TYPE_ERROR]) {
+ MX_E("Already set mediamuxer_error_cb\n");
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ goto ERROR;
+ }
+ else {
+ if (!callback) {
+ ret = MX_ERROR_INVALID_ARGUMENT;
+ goto ERROR;
+ }
+ }
+
+ MX_I("Set event handler callback(cb = %p, data = %p)\n", callback, user_data);
+ gst_handle->user_cb[_GST_EVENT_TYPE_ERROR] = (gst_error_cb) callback;
+ gst_handle->user_data[_GST_EVENT_TYPE_ERROR] = user_data;
+ MEDIAMUXER_FLEAVE();
+ return MX_ERROR_NONE;
+ERROR:
+ MEDIAMUXER_FLEAVE();
+ return ret;
+}
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(fw_test "${fw_name}-test")
+
+INCLUDE_DIRECTORIES(../include)
+INCLUDE_DIRECTORIES(../include/headers)
+link_directories(${CMAKE_SOURCE_DIR}/../)
+
+INCLUDE(FindPkgConfig)
+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-mediamuxer ${${fw_test}_LDFLAGS})
+ENDFOREACH()
+
--- /dev/null
+/*
+ * 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 FILES |
+| |
+==============================================================================*/
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <mm_error.h>
+#include <mm_debug.h>
+#include "../include/mediamuxer_port.h"
+#include <mediamuxer.h>
+#include <mediamuxer_private.h>
+#include <media_packet_internal.h>
+/* Read encoded medial files locally: encoded A/V files along with info & caps */
+#define H264_FILE video_data
+#define H264_INFO video_extra_info
+#define AAC_FILE audio_data
+#define AAC_INFO audio_extra_info
+
+/*-----------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS: |
+-----------------------------------------------------------------------*/
+#define MAX_STRING_LEN 100
+#define PACKAGE "mediamuxer_test"
+
+mediamuxer_h myMuxer = 0;
+media_format_h media_format = NULL;
+media_format_h media_format_a = NULL;
+
+bool aud_eos = 0;
+bool vid_eos = 0;
+char audio_extra_info[1000];
+char audio_data[1000];
+char video_extra_info[1000];
+char video_data[1000];
+
+int test_mediamuxer_create()
+{
+ g_print("test_mediamuxer_create\n");
+ g_print("%p", myMuxer);
+
+ if (mediamuxer_create(&myMuxer)
+ != MEDIAMUXER_ERROR_NONE) {
+ g_print("mediamuxer create is failed\n");
+ }
+ g_print("\n Muxer->mx_handle created successfully with address=%p",
+ (void *)((mediamuxer_s *) myMuxer)->mx_handle);
+ g_print("\n Muxer handle created successfully with address=%p",
+ myMuxer);
+
+ return 0;
+}
+
+int test_mediamuxer_set_data_sink()
+{
+ char *op_uri = "MyTest.mp4";
+
+ /* Set data source after creating */
+ mediamuxer_set_data_sink(myMuxer, op_uri, MEDIAMUXER_CONTAINER_FORMAT_MP4);
+ return 0;
+}
+
+int test_mediamuxer_destroy()
+{
+ int ret = 0;
+ g_print("test_mediamuxer_destroy\n");
+ ret = mediamuxer_destroy(myMuxer);
+ myMuxer = NULL;
+ g_print("\nDestroy operation returned: %d\n", ret);
+ return ret;
+}
+
+int test_mediamuxer_start()
+{
+ g_print("mediamuxer_start completed \n");
+ mediamuxer_start(myMuxer);
+ return 0;
+}
+
+int test_mediamuxer_add_track_video()
+{
+ int track_index_vid = -1;
+ media_format_mimetype_e mimetype;
+ int width;
+ int height;
+ int avg_bps;
+ int max_bps;
+
+ g_print("test_mediamuxer_add_track_video\n");
+ media_format_create(&media_format);
+
+ /* MEDIA_FORMAT_H264_SP MEDIA_FORMAT_H264_MP MEDIA_FORMAT_H264_HP */
+ media_format_set_video_mime(media_format, MEDIA_FORMAT_H264_SP);
+
+ media_format_set_video_width(media_format, 640);
+ media_format_set_video_height(media_format, 480);
+ media_format_set_video_avg_bps(media_format, 10);
+ media_format_set_video_max_bps(media_format, 10);
+
+ media_format_get_video_info(media_format, &mimetype, &width, &height, &avg_bps, &max_bps);
+
+ g_print("\n Video Mime trying to set: %x %x\n", (int)(mimetype), (int)(MEDIA_FORMAT_H264_SP));
+ g_print("\n Video param trying to set: (width, height, avg_bps, max_bps): %d %d %d %d \n",
+ width, height, avg_bps, max_bps);
+
+ /* To add video track */
+ mediamuxer_add_track(myMuxer, media_format, &track_index_vid);
+ g_print("audio track index returned is: %d", track_index_vid);
+ return 0;
+}
+
+int test_mediamuxer_add_track_audio()
+{
+ int track_index_aud = -1;
+ media_format_mimetype_e mimetype;
+ int channel;
+ int samplerate;
+ int bit;
+ int avg_bps;
+
+ g_print("test_mediamuxer_add_track\n");
+ media_format_create(&media_format_a);
+
+ /* MEDIA_FORMAT_AAC MEDIA_FORMAT_AAC_LC MEDIA_FORMAT_AAC_HE MEDIA_FORMAT_AAC_HE_PS */
+ if (media_format_set_audio_mime(media_format_a, MEDIA_FORMAT_AAC) == MEDIA_FORMAT_ERROR_INVALID_OPERATION)
+ g_print("Problem during media_format_set_audio_mime operation");
+
+ if (media_format_set_audio_channel(media_format_a, 2) == MEDIA_FORMAT_ERROR_INVALID_OPERATION)
+ g_print("Problem during media_format_set_audio_channel operation");
+ media_format_set_audio_samplerate(media_format_a, 44000);
+ media_format_set_audio_bit(media_format_a, 1);
+ media_format_set_audio_avg_bps(media_format_a, 10);
+ media_format_set_audio_aac_type(media_format_a, true);
+
+ media_format_get_audio_info(media_format_a, &mimetype, &channel, &samplerate, &bit, &avg_bps);
+
+ g_print("\n Audio Mime trying to set: %x %x\n", (int)(mimetype), (int)(MEDIA_FORMAT_AAC));
+ g_print("\n Audio Param trying to set: (ch, samplert, bt, avg_bps) %d %d %d %d \n",
+ channel, samplerate, bit, avg_bps);
+
+ /* To add audio track */
+ mediamuxer_add_track(myMuxer, media_format_a, &track_index_aud);
+ g_print("track index returned is: %d", track_index_aud);
+ return 0;
+}
+
+void app_err_cb(mediamuxer_error_e error, void *user_data)
+{
+ printf("Got Error %d from mediamuxer\n",error);
+}
+
+int test_mediamuxer_set_error_cb()
+{
+ int ret = 0;
+ g_print("test_mediamuxer_set_error_cb\n");
+ ret = mediamuxer_set_error_cb(myMuxer, app_err_cb, myMuxer);
+ return ret;
+}
+
+void *_write_video_data()
+{
+ FILE *pvFile;
+ FILE *pvFileInfo;
+ unsigned int size;
+ unsigned int vsize;
+ unsigned int is_video_readable = 1;
+ unsigned int is_video_pts_readable;
+ unsigned int is_video_dts_readable;
+ unsigned int is_video_duration_readable;
+ unsigned int is_video_flag_readable;
+ unsigned int is_video_key_readable;
+ unsigned long long int pts_vid;
+ unsigned long long int dts_vid;
+ unsigned long long int duration_vid;
+ int flg_vid;
+ int *status = (int *)g_malloc(sizeof(int) * 1);
+ *status = -1;
+ int track_index_vid = 1; /* track_index=2 for video */
+ int vcount = 0;
+ guint8 *ptr_vid;
+ int key_vid;
+ char *vid_caps;
+ int ret_scan;
+ media_packet_h vid_pkt;
+ media_format_h vidfmt;
+ unsigned int vcap_size;
+
+ pvFile = fopen(H264_FILE, "rb");
+ pvFileInfo = fopen(H264_INFO, "rt");
+
+ if (pvFile == NULL || pvFileInfo == NULL) {
+ g_print("\nOne of the files (info/data) cant be loaded...\n");
+ return (void *)status;
+ }
+
+ ret_scan = fscanf(pvFileInfo, "%d\n", &size);
+ vid_caps = (char *)malloc(size + 1);
+ ret_scan = fscanf(pvFileInfo, "%[^\n]s\n", vid_caps);
+ g_print("\nV_Caps = %s\n", vid_caps);
+ vcap_size = size + 1;
+
+ if (!ret_scan) { /* ToDo: repeat the same for every scanf */
+ g_print("\nscan failed");
+ return (void *)status;
+ }
+
+ while (is_video_readable == 1) {
+ /* Read encoded video data */
+ is_video_readable = fscanf(pvFileInfo, "%d\n", &vsize);
+ is_video_pts_readable = fscanf(pvFileInfo, "%llu\n", &pts_vid);
+ is_video_dts_readable = fscanf(pvFileInfo, "%llu\n", &dts_vid);
+ is_video_duration_readable = fscanf(pvFileInfo, "%llu\n", &duration_vid);
+ is_video_flag_readable = fscanf(pvFileInfo, "%u\n", &flg_vid);
+ is_video_key_readable = fscanf(pvFileInfo, "%d\n", &key_vid);
+
+ if (is_video_readable == 1 && is_video_pts_readable == 1 && is_video_dts_readable == 1
+ && is_video_duration_readable == 1 && is_video_flag_readable == 1
+ && is_video_key_readable == 1) {
+ g_print("\nv%d: ", ++vcount);
+ g_print("\nv_Size: %d, v_pts: %llu, v_dts: %llu v_duration: %llu, v_flag: %d",
+ vsize, pts_vid, dts_vid, duration_vid, key_vid);
+ ptr_vid = g_malloc(vsize);
+ g_assert(ptr_vid);
+ vsize = fread(ptr_vid, 1, vsize, pvFile);
+
+ if (media_format_create(&vidfmt)) {
+ g_print("media_format_create failed\n");
+ return (void *)status;
+ }
+ if (media_format_set_video_mime(vidfmt, MEDIA_FORMAT_H264_SP)) {
+ g_print("media_format_set_audio_mime failed\n");
+ return (void *)status;
+ }
+ media_format_set_video_width(vidfmt, vsize / 2 + 1);
+ media_format_set_video_height(vidfmt, vsize / 2 + 1);
+ /*frame rate is came from the caps filter of demuxer*/
+ if (media_format_set_video_frame_rate(vidfmt, 30)) {
+ g_print("media_format_set_video_frame_rate failed\n");
+ return (void *)status;
+ }
+
+ uint64_t ns;
+ guint8 *dptr;
+
+ if (media_packet_create(vidfmt, NULL, NULL, &vid_pkt)) {
+ g_print("\ncreate v media packet failed tc\n");
+ return (void *)status;
+ }
+
+ if (media_packet_alloc(vid_pkt)) {
+ g_print(" v media packet alloc failed\n");
+ return (void *)status;
+ }
+ media_packet_get_buffer_data_ptr(vid_pkt, (void **)&dptr);
+ media_packet_get_buffer_size(vid_pkt, &ns);
+ g_print("set v buf size as %d, data size=%d\n", (int)ns, vsize);
+
+ memcpy((char *)dptr, ptr_vid, vsize);
+ if (media_packet_set_buffer_size(vid_pkt, vsize)) {
+ g_print("set v buf size failed\n");
+ return (void *)status;
+ }
+
+
+ if (media_packet_get_buffer_size(vid_pkt, &ns)) {
+ g_print("unable to set the v buffer size actual =%d, fixed %d\n", size, (int)ns);
+ return (void *)status;
+ }
+ g_print(" fixed size %d\n", (int)ns);
+
+ if (media_packet_set_pts(vid_pkt, pts_vid)) {
+ g_print("unable to set the pts\n");
+ return (void *)status;
+ }
+ if (media_packet_set_dts(vid_pkt, dts_vid)) {
+ g_print("unable to set the pts\n");
+ return (void *)status;
+ }
+ if (media_packet_set_duration(vid_pkt, duration_vid)) {
+ g_print("unable to set the pts\n");
+ return (void *)status;
+ }
+
+ if (media_packet_set_flags(vid_pkt, flg_vid)) {
+ g_print("unable to set the flag size\n");
+ return (void *)status;
+ }
+ if (media_packet_set_codec_data(vid_pkt, vid_caps, vcap_size)) {
+ g_print("unable to set the flag size\n");
+ return (void *)status;
+ }
+
+
+ g_print("V write sample call. packet add:%x\n", (unsigned int)vid_pkt);
+ mediamuxer_write_sample(myMuxer, track_index_vid, vid_pkt);
+
+ media_packet_destroy(vid_pkt);
+ } else {
+ g_print("\nVideo while done in the test suite");
+ mediamuxer_close_track(myMuxer, track_index_vid);
+ }
+ }
+ g_print("\n\n\n ******* Out of while loop ****** \n\n\n");
+ fclose(pvFile);
+ fclose(pvFileInfo);
+ *status = 0;
+ return (void *)status;
+}
+
+void *_write_audio_data()
+{
+ FILE *paFile;
+ FILE *paFileInfo;
+ unsigned int size;
+ unsigned int is_audio_readable = 1;
+ unsigned int is_audio_pts_readable;
+ unsigned int is_audio_dts_readable;
+ unsigned int is_audio_duration_readable;
+ unsigned int is_audio_flag_readable;
+ unsigned int is_audio_key_readable;
+ unsigned char *ptr1;
+ unsigned long long int pts;
+ unsigned long long int dts;
+ unsigned long long int duration;
+ int flg;
+
+ int key;
+ int acount = 0;
+ int track_index_aud = 2; /* track_index=2 for audio */
+ char *aud_caps;
+ int ret_scan;
+ media_packet_h aud_pkt;
+ media_format_h audfmt;
+ unsigned int acap_size;
+ int *status = (int *)g_malloc(sizeof(int) * 1);
+ *status = -1;
+
+ paFileInfo = fopen(AAC_INFO, "rt");
+ paFile = fopen(AAC_FILE, "rb");
+
+ if (paFile == NULL || paFileInfo == NULL) {
+ g_print("\nOne of the files (info/data) cant be loaded...\n");
+ return (void *)status;
+ }
+
+ ret_scan = fscanf(paFileInfo, "%d\n", &size);
+ aud_caps = (char *)malloc(1 + size);
+ ret_scan = fscanf(paFileInfo, "%[^\n]s\n", aud_caps);
+ g_print("\nA_Caps = %s\n", aud_caps);
+ acap_size = size + 1;
+
+ if (!ret_scan) { /* ToDo: repeat the same for every scanf */
+ g_print("\nscan failed");
+ return (void *)status;
+ }
+
+ while (is_audio_readable == 1) {
+
+ /* Read encoded audio data */
+ is_audio_readable = fscanf(paFileInfo, "%d\n", &size);
+ is_audio_pts_readable = fscanf(paFileInfo, "%llu\n", &pts);
+ is_audio_dts_readable = fscanf(paFileInfo, "%llu\n", &dts);
+ is_audio_duration_readable = fscanf(paFileInfo, "%llu\n", &duration);
+ is_audio_flag_readable = fscanf(paFileInfo, "%u\n", &flg);
+ is_audio_key_readable = fscanf(paFileInfo, "%d\n", &key);
+
+ if (is_audio_readable == 1 && is_audio_pts_readable == 1
+ && is_audio_dts_readable == 1 && is_audio_duration_readable == 1
+ && is_audio_flag_readable == 1 && is_audio_key_readable == 1) {
+ g_print("\na%d: ", ++acount);
+ g_print("\nSize: %d, a_pts: %llu, a_dts: %llu, a_duration: %llu, a_flag:%d, a_key:%d",
+ size, pts, dts, duration, flg, key);
+
+ if (media_format_create(&audfmt)) {
+ g_print("media_format_create failed\n");
+ return (void *)status;
+ }
+ if (media_format_set_audio_mime(audfmt, MEDIA_FORMAT_AAC)) {
+ g_print("media_format_set_audio_mime failed\n");
+ return (void *)status;
+ }
+
+ ptr1 = g_malloc(size);
+ g_assert(ptr1);
+
+ size = fread(ptr1, 1, size, paFile);
+
+ /* To create media_pkt */
+ uint64_t ns;
+ guint8 *dptr;
+
+ if (media_packet_create(audfmt, NULL, NULL, &aud_pkt)) {
+ g_print("create audio media_packet failed\n");
+ return (void *)status;
+ }
+
+ if (media_packet_alloc(aud_pkt)) {
+ g_print("audio media_packet alloc failed\n");
+ return (void *)status;
+ }
+ media_packet_get_buffer_data_ptr(aud_pkt, (void **)&dptr);
+ memcpy((char *)dptr, ptr1, size);
+
+ if (media_packet_set_buffer_size(aud_pkt, (uint64_t)size)) {
+ g_print("audio set_buffer_size failed\n");
+ return (void *)status;
+ }
+
+ if (media_packet_get_buffer_size(aud_pkt, &ns)) {
+ g_print("unable to set the buffer size actual =%d, fixed %d\n", size, (int)&ns);
+ return (void *)status;
+ }
+
+ g_print(" fixed size %d\n", (int)ns);
+
+ if (media_packet_set_pts(aud_pkt, pts)) {
+ g_print("unable to set the pts\n");
+ return (void *)status;
+ }
+
+ if (media_packet_set_dts(aud_pkt, dts)) {
+ g_print("unable to set the pts\n");
+ return (void *)status;
+ }
+
+ if (media_packet_set_duration(aud_pkt, duration)) {
+ g_print("unable to set the pts\n");
+ return (void *)status;
+ }
+
+ if (media_packet_set_flags(aud_pkt, key)) {
+ g_print("unable to set the flag size\n");
+ return (void *)status;
+ }
+ if (media_packet_set_codec_data(aud_pkt, aud_caps, acap_size)) {
+ g_print("unable to set the audio codec data e\n");
+ return (void *)status;
+ }
+
+
+ g_print("A write sample call. packet add:%x\n", (unsigned int)aud_pkt);
+ mediamuxer_write_sample(myMuxer, track_index_aud, aud_pkt);
+
+ media_packet_destroy(aud_pkt);
+ } else {
+ g_print("\nAudio while done in the test suite");
+ mediamuxer_close_track(myMuxer, track_index_aud);
+ }
+
+ }
+ g_print("\n\n\n ******* Out of while loop ****** \n\n\n");
+
+ fclose(paFile);
+ fclose(paFileInfo);
+ *status = 0;
+ return (void *)status;
+}
+
+
+int test_mediamuxer_write_sample()
+{
+ pthread_t thread[2];
+ pthread_attr_t attr;
+ /* Initialize and set thread detached attribute */
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ g_print("In main: creating thread for audio\n");
+ pthread_create(&thread[0], &attr, _write_video_data, NULL);
+ pthread_create(&thread[1], &attr, _write_audio_data, NULL);
+ pthread_attr_destroy(&attr);
+ return 0;
+}
+
+int test_mediamuxer_stop()
+{
+ g_print("test_mediamuxer_stop\n");
+ mediamuxer_stop(myMuxer);
+ media_format_unref(media_format_a);
+ media_format_unref(media_format);
+ return 0;
+}
+
+int test_mediamuxer_pause()
+{
+ g_print("test_mediamuxer_pause\n");
+ mediamuxer_state_e state;
+ if (mediamuxer_get_state(myMuxer, &state) == MEDIAMUXER_ERROR_NONE) {
+ g_print("\nMediamuxer_state=%d",state);
+ if (state == MEDIAMUXER_STATE_MUXING)
+ mediamuxer_pause(myMuxer);
+ }
+ return 0;
+}
+
+int test_mediamuxer_resume()
+{
+ g_print("test_mediamuxer_resume\n");
+ mediamuxer_resume(myMuxer);
+ return 0;
+}
+
+int test_mediamuxer_add_track()
+{
+ g_print("test_mediamuxer_add_track\n");
+ return 0;
+}
+
+void quit_testApp(void)
+{
+ /* To Do: Replace exit(0) with smooth exit */
+ exit(0);
+}
+
+enum {
+ CURRENT_STATUS_MAINMENU,
+ CURRENT_STATUS_AUDIO_FILENAME,
+ CURRENT_STATUS_AUDIO_INFONAME,
+ CURRENT_STATUS_VIDEO_FILENAME,
+ CURRENT_STATUS_VIDEO_INFONAME,
+};
+
+int g_menu_state = CURRENT_STATUS_MAINMENU;
+static void display_sub_basic();
+
+void reset_menu_state()
+{
+ g_menu_state = CURRENT_STATUS_MAINMENU;
+ return;
+}
+
+static void input_filepath(char *filename)
+{
+ g_print("Opening file %s\n", filename);
+ return;
+}
+
+void _interpret_main_menu(char *cmd)
+{
+ int len = strlen(cmd);
+ if (len == 1) {
+ if (strncmp(cmd, "c", 1) == 0) {
+ test_mediamuxer_create();
+ } else if (strncmp(cmd, "o", 1) == 0) {
+ test_mediamuxer_set_data_sink();
+ } else if (strncmp(cmd, "d", 1) == 0) {
+ test_mediamuxer_destroy();
+ } else if (strncmp(cmd, "s", 1) == 0) {
+ test_mediamuxer_start();
+ } else if (strncmp(cmd, "a", 1) == 0) {
+ g_menu_state = CURRENT_STATUS_AUDIO_FILENAME;
+ } else if (strncmp(cmd, "v", 1) == 0) {
+ g_menu_state = CURRENT_STATUS_VIDEO_FILENAME;
+ } else if (strncmp(cmd, "m", 1) == 0) {
+ test_mediamuxer_write_sample();
+ } else if (strncmp(cmd, "e", 1) == 0) {
+ test_mediamuxer_stop();
+ } else if (strncmp(cmd, "p", 1) == 0) {
+ test_mediamuxer_pause();
+ } else if (strncmp(cmd, "r", 1) == 0) {
+ test_mediamuxer_resume();
+ } else if (strncmp(cmd, "b", 1) == 0) {
+ test_mediamuxer_set_error_cb();
+ } else if (strncmp(cmd, "q", 1) == 0) {
+ quit_testApp();
+ } else {
+ g_print("unknown menu command. Please try again\n");
+ }
+ } else {
+ g_print("unknown menu command. Please try again\n");
+ }
+
+ return;
+}
+
+static void displaymenu(void)
+{
+ if (g_menu_state == CURRENT_STATUS_MAINMENU) {
+ display_sub_basic();
+ } else if (g_menu_state == CURRENT_STATUS_AUDIO_FILENAME) {
+ g_print("*** input encoded audio_data path:\n");
+ g_print("[This is the raw encoded audio file to be muxed]:");
+ } else if (g_menu_state == CURRENT_STATUS_AUDIO_INFONAME) {
+ g_print("*** input encoded audio info (extra data) path\n");
+ g_print("[This is the extra-information needed to mux.");
+ g_print("This includes gst-caps too]:");
+ } else if (g_menu_state == CURRENT_STATUS_VIDEO_FILENAME) {
+ g_print("*** input encoded video path\n");
+ g_print("[This is the raw encoded video file to be muxed]:");
+ } else if (g_menu_state == CURRENT_STATUS_VIDEO_INFONAME) {
+ g_print("*** input encoded video info (extra data) path\n");
+ g_print("[This is the extra-information needed to mux.");
+ g_print("This includes gst-caps too]:");
+ } else {
+ g_print("*** unknown status.\n");
+ exit(0);
+ }
+ g_print(" >>> ");
+}
+
+gboolean timeout_menu_display(void *data)
+{
+ displaymenu();
+ return FALSE;
+}
+
+static void interpret(char *cmd)
+{
+
+ switch (g_menu_state) {
+ case CURRENT_STATUS_MAINMENU: {
+ _interpret_main_menu(cmd);
+ break;
+ }
+ case CURRENT_STATUS_AUDIO_FILENAME: {
+ input_filepath(cmd);
+ strcpy(audio_data, cmd);
+ g_menu_state = CURRENT_STATUS_AUDIO_INFONAME;
+ break;
+ }
+ case CURRENT_STATUS_AUDIO_INFONAME: {
+ input_filepath(cmd);
+ strcpy(audio_extra_info, cmd);
+ test_mediamuxer_add_track_audio();
+ g_menu_state = CURRENT_STATUS_MAINMENU;
+
+ break;
+ }
+ case CURRENT_STATUS_VIDEO_FILENAME: {
+ input_filepath(cmd);
+ strcpy(video_data, cmd);
+ g_menu_state = CURRENT_STATUS_VIDEO_INFONAME;
+ break;
+ }
+ case CURRENT_STATUS_VIDEO_INFONAME: {
+ input_filepath(cmd);
+ strcpy(video_extra_info, cmd);
+ test_mediamuxer_add_track_video();
+ g_menu_state = CURRENT_STATUS_MAINMENU;
+ break;
+ }
+ default:
+ break;
+ }
+ g_timeout_add(100, timeout_menu_display, 0);
+}
+
+static void display_sub_basic()
+{
+ g_print("\n");
+ g_print("==========================================================\n");
+ g_print(" media muxer test\n");
+ g_print("----------------------------------------------------------\n");
+ g_print("c. Create \t");
+ g_print("o. Set Data Sink \t");
+ g_print("a. AddAudioTrack \t");
+ g_print("v. AddVideoTrack \t");
+ g_print("s. Start \t");
+ g_print("m. StartMuxing \t");
+ g_print("p. PauseMuxing \t");
+ g_print("r. ResumeMuxing \t");
+ g_print("b. set error callback \t");
+ g_print("e. Stop (eos) \n");
+ g_print("d. destroy \t");
+ g_print("q. quit \t");
+ g_print("\n");
+ g_print("==========================================================\n");
+}
+
+/**
+ * This function is to execute command.
+ *
+ * @param channel [in] 1st parameter
+ *
+ * @return This function returns TRUE/FALSE
+ * @remark
+ * @see
+ */
+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(buf);
+ return TRUE;
+}
+
+/**
+ * This function is the example main function for mediamuxer API.
+ *
+ * @param
+ *
+ * @return This function returns 0.
+ * @remark
+ * @see other functions
+ */
+int main(int argc, char *argv[])
+{
+ GIOChannel *stdin_channel;
+ GMainLoop *loop = g_main_loop_new(NULL, 0);
+ 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);
+
+ displaymenu();
+ /* g_print("RUN main loop\n"); */
+ g_main_loop_run(loop);
+ g_print("STOP main loop\n");
+
+ g_main_loop_unref(loop);
+ return 0;
+}