From f2ff588a8a38033ed9d0427e104fa684dd6cda23 Mon Sep 17 00:00:00 2001 From: "Hyuntae, Kim" Date: Tue, 22 Dec 2015 08:36:38 +0900 Subject: [PATCH] [mediastreamrecorder] initial code for streamrecorder Change-Id: Iaa58d74566b11fd58f1720bb68e5cc3a7f109a3e --- AUTHORS | 5 + CMakeLists.txt | 118 +++ LICENSE.APLv2 | 206 ++++ NOTICE | 3 + capi-media-streamrecorder.manifest | 5 + capi-media-streamrecorder.pc.in | 15 + .../capi_media_streamrecorder_state_diagram.png | Bin 0 -> 21389 bytes doc/streamrecorder_doc.h | 229 ++++ include/streamrecorder.h | 1103 ++++++++++++++++++++ include/streamrecorder_private.h | 95 ++ packaging/capi-media-streamrecorder.spec | 65 ++ src/streamrecorder.c | 957 +++++++++++++++++ src/streamrecorder_private.c | 1038 ++++++++++++++++++ test/CMakeLists.txt | 24 + test/streamrecorder_test.c | 827 +++++++++++++++ 15 files changed, 4690 insertions(+) create mode 100644 AUTHORS create mode 100644 CMakeLists.txt create mode 100644 LICENSE.APLv2 create mode 100644 NOTICE create mode 100644 capi-media-streamrecorder.manifest create mode 100644 capi-media-streamrecorder.pc.in create mode 100644 doc/images/capi_media_streamrecorder_state_diagram.png create mode 100644 doc/streamrecorder_doc.h create mode 100644 include/streamrecorder.h create mode 100644 include/streamrecorder_private.h create mode 100644 packaging/capi-media-streamrecorder.spec create mode 100644 src/streamrecorder.c create mode 100644 src/streamrecorder_private.c create mode 100644 test/CMakeLists.txt create mode 100644 test/streamrecorder_test.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..ac14513 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,5 @@ +sahil bansal +ruchika saxena +hyuntae kim +Jeongmo Yang +Heechul Jeon diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..195f9c8 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,118 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +SET(Services + "application" + "base" + "content" + "location" + "media" + "messaging" + "network" + "social" + "telephony" + "system" + ) + +# project +SET(project_prefix "capi") +SET(prefix "/usr") +SET(maintainer "Sahil Bansal ") +SET(description "A Stream Recorder library in Tizen Native API") +SET(service "media") +SET(submodule "streamrecorder") + +# for package file +SET(dependents "dlog mm-streamrecorder capi-media-audio-io capi-media-tool") +SET(pc_dependents "capi-base-common capi-media-audio-io capi-media-tool") + +SET(fw_name "${project_prefix}-${service}-${submodule}") + +PROJECT(${fw_name}) + +SET(CMAKE_INSTALL_PREFIX ${prefix}) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +SET(INC_DIR include) +INCLUDE_DIRECTORIES(${INC_DIR}) + +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 "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Wextra -Wno-array-bounds -Wno-empty-body -Wno-ignored-qualifiers -Wno-unused-parameter -Wshadow -Wwrite-strings -Wswitch-default -Wno-unused-but-set-parameter -Wno-unused-but-set-variable") +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 SOURCES) +ADD_LIBRARY(${fw_name} SHARED ${SOURCES}) + +SET_TARGET_PROPERTIES(${fw_name} + PROPERTIES + VERSION ${FULLVER} + SOVERSION ${MAJORVER} + CLEAN_DIRECT_OUTPUT 1 +) + +TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS}) + +INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR}) +INSTALL( + DIRECTORY ${INC_DIR}/ DESTINATION include/${service} + FILES_MATCHING + PATTERN "*_private.h" EXCLUDE + PATTERN "${INC_DIR}/*.h" + ) + +SET(PC_NAME ${fw_name}) +SET(PC_REQUIRED ${pc_dependents}) +SET(PC_LDFLAGS -l${fw_name}) + +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_INSTALL_DIR}/pkgconfig) + +ADD_SUBDIRECTORY(test) + +IF(UNIX) + +ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution) +ADD_CUSTOM_COMMAND( + DEPENDS clean + COMMENT "distribution clean" + COMMAND find + ARGS . + -not -name config.cmake -and \( + -name tester.c -or + -name Testing -or + -name CMakeFiles -or + -name cmake.depends -or + -name cmake.check_depends -or + -name CMakeCache.txt -or + -name cmake.check_cache -or + -name *.cmake -or + -name Makefile -or + -name core -or + -name core.* -or + -name gmon.out -or + -name install_manifest.txt -or + -name *.pc -or + -name *~ \) + | grep -v TC | xargs rm -rf + TARGET distclean + VERBATIM +) + +ENDIF(UNIX) diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100644 index 0000000..bbe9d02 --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,206 @@ +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..0e0f016 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE.APLv2 file for Apache License terms and conditions. diff --git a/capi-media-streamrecorder.manifest b/capi-media-streamrecorder.manifest new file mode 100644 index 0000000..a76fdba --- /dev/null +++ b/capi-media-streamrecorder.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/capi-media-streamrecorder.pc.in b/capi-media-streamrecorder.pc.in new file mode 100644 index 0000000..1508489 --- /dev/null +++ b/capi-media-streamrecorder.pc.in @@ -0,0 +1,15 @@ + +# 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} + diff --git a/doc/images/capi_media_streamrecorder_state_diagram.png b/doc/images/capi_media_streamrecorder_state_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..2aabd6dfefda88abde9cefa6ba698f44107c0f4b GIT binary patch literal 21389 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 + * + * @section CAPI_MEDIA_STREAMRECORDER_MODULE_OVERVIEW Overview + * The StreamRecorder API allows application developers to support using the video or audio recorder. It includes functions that record video or audio and supports to set up + * notifications for state changes of creation, prepared, record, pause, information about resolution and binary data format, and functions for artistic. + * + * The StreamRecorder API allows creation of components required in recording video or audio including: + * - selecting a proper output format + * - controlling the StreamRecorder state + * - getting supported formats and video resolutions + * + * The StreamRecorder API also notifies you (by callback mechanism) when a significant parameter changes. + * + * @subsection CAPI_MEDIA_STREAMRECORDER_DIFFERENCE Difference + * Basically, the StreamRecorder API can help easily to make video/audio content same as the Recorder API.\n + * + * However, the StreamRecorder API is different from Recorder API. \n + * The StreamRecorder API is able to record user buffer from application. This allows the user to make unique contents with a purpose. + * + *
+ * + * + * + * + * + * + * + * + * + * + *
Difference RecorderStreamRecorder
INPUT Camera / Mic Device Media Packet / Buffer
+ * + * @subsection CAPI_MEDIA_STREAMRECORDER_LIFE_CYCLE_STATE_DIAGRAM State Diagram + * @image html capi_media_streamrecorder_state_diagram.png + * + * @subsection CAPI_MEDIA_STREAMRECORDER_LIFE_CYCLE_STATE_TRANSITIONS State Transitions + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
FUNCTIONPRE-STATEPOST-STATESYNC TYPE
streamrecorder_create() NONE CREATED SYNC
streamrecorder_prepare() CREATED PREPARED SYNC
streamrecorder_start() PREPARED / PAUSED RECORDING SYNC
streamrecorder_pause() RECORDING PAUSED SYNC
streamrecorder_commit() RECORDING/ PAUSED PREPARED SYNC
streamrecorder_cancel() RECORDING/ PAUSED PREPARED SYNC
streamrecorder_unprepare() PREPARED CREATED SYNC
streamrecorder_destroy() CREATED NONE SYNC
+ * + * @subsection CAPI_MEDIA_STREAMRECORDER_LIFE_CYCLE_CALLBACK_OPERATIONS Callback(Event) Operations + * The callback mechanism is used to notify the application about significant StreamRecorder events. + *
+ * + * + * + * + * + * + * + * + * + * + * + * + *
REGISTERUNREGISTERCALLBACKDESCRIPTION
streamrecorder_set_error_cb()streamrecorder_unset_error_cb()streamrecorder_error_cb()This callback is used to notify error has occurred
+ * + * @subsection CAPI_MEDIA_STREAMRECORDER_FOREACH_OPERATIONS Foreach Operations + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
FOREACHCALLBACKDESCRIPTION
streamrecorder_foreach_supported_audio_encoder()streamrecorder_supported_audio_encoder_cb()Supported audio encoders
streamrecorder_foreach_supported_video_encoder()streamrecorder_supported_video_encoder_cb()Supported video encoders
streamrecorder_foreach_supported_file_format()streamrecorder_supported_file_format_cb()Supported file formats
streamrecorder_foreach_supported_video_resolution()streamrecorder_supported_video_resolution_cb()Supported video resolutions
+ * + */ + + +/** + * @defgroup CAPI_MEDIA_STREAMRECORDER_ATTRIBUTES_MODULE Attributes + * @brief The @ref CAPI_MEDIA_STREAMRECORDER_ATTRIBUTES_MODULE API provides functions to fetch StreamRecorder attributes. + * @ingroup CAPI_MEDIA_STREAMRECORDER_MODULE + * + * @section CAPI_MEDIA_STREAMRECORDER_ATTRIBUTES_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_MEDIA_STREAMRECORDER_ATTRIBUTES_MODULE_OVERVIEW Overview + * The StreamRecorder Attributes API provides functions to get/set basic StreamRecorder attributes. + * + * With the StreamRecorder Attributes API you are able to set and get StreamRecorder attributes like: + *
    + *
  • File name
  • + *
  • File format
  • + *
  • Audio encoder
  • + *
  • Video encoder
  • + *
  • Recording size limit
  • + *
  • Recording time limit
  • + *
  • Audio samplerate
  • + *
  • Audio encoder bitrate
  • + *
  • Video encoder bitrate
  • + *
  • Audio channel
  • + *
+ * + */ + +/** + * @defgroup CAPI_MEDIA_STREAMRECORDER_CALLBACK_MODULE Callback + * @brief The @ref CAPI_MEDIA_STREAMRECORDER_CALLBACK_MODULE API Callbacks from the StreamRecorder frameworks. + * @ingroup CAPI_MEDIA_STREAMRECORDER_MODULE + * + * @section CAPI_MEDIA_STREAMRECORDER_CALLBACK_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_MEDIA_STREAMRECORDER_CALLBACK_MODULE_OVERVIEW Overview + * The StreamRecorder Callback API provides functions status. + * + */ + +/** + * @ingroup CAPI_MEDIA_STREAMRECORDER_MODULE + * @defgroup CAPI_MEDIA_STREAMRECORDER_CAPABILITY_MODULE Capability + * @brief The @ref CAPI_MEDIA_STREAMRECORDER_CAPABILITY_MODULE API provides capability information of the StreamRecorder. + * @section CAPI_MEDIA_STREAMRECORDER_CAPABILITY_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_MEDIA_STREAMRECORDER_CAPABILITY_MODULE_OVERVIEW Overview + * The StreamRecorder Capability API provides functions to obtain capability information of the StreamRecorder. + * + */ + +#endif /* __TIZEN_MEDIA_STREAMRECORDER_DOC_H__ */ + + diff --git a/include/streamrecorder.h b/include/streamrecorder.h new file mode 100644 index 0000000..b9c8653 --- /dev/null +++ b/include/streamrecorder.h @@ -0,0 +1,1103 @@ +/* +* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#ifndef __TIZEN_MEDIA_STREAMRECORDER_H__ +#define __TIZEN_MEDIA_STREAMRECORDER_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file streamrecorder.h + * @brief This file contains the Streamrecorder API, related structures and enumerations. + * @since_tizen 3.0 + */ + +/** + * @addtogroup CAPI_MEDIA_STREAMRECORDER_MODULE + * @{ + */ + +#ifndef TIZEN_ERROR_STREAMRECORDER +#define TIZEN_ERROR_STREAMRECORDER -0x01B0000 +#endif /* TIZEN_ERROR_STREAMRECORDER */ + +/** + * @brief The Streamrecorder handle. + * @since_tizen 3.0 + */ +typedef struct streamrecorder_s *streamrecorder_h; + +/** + * @brief Enumeration for the source type. + * @since_tizen 3.0 + */ +typedef enum { + STREAMRECORDER_SOURCE_VIDEO, /**< Video only */ + STREAMRECORDER_SOURCE_AUDIO, /**< Audio only */ + STREAMRECORDER_SOURCE_VIDEO_AUDIO, /**< Video and Audio */ +} streamrecorder_source_e; + +/** + * @brief Enumeration for the pixel format. + * @since_tizen 3.0 + */ +typedef enum { + STREAMRECORDER_VIDEO_SOURCE_FORMAT_INVALID = -1, /**< Invalid pixel format */ + STREAMRECORDER_VIDEO_SOURCE_FORMAT_NV12, /**< NV12 pixel format */ + STREAMRECORDER_VIDEO_SOURCE_FORMAT_NV21, /**< NV12 pixel format */ + STREAMRECORDER_VIDEO_SOURCE_FORMAT_I420, /**< I420 pixel format */ + STREAMRECORDER_VIDEO_SOURCE_FORMAT_NUM /**< Number of the video source format */ +} streamrecorder_video_source_format_e; + +/** + * @brief Enumeration for the file container format. + * @since_tizen 3.0 + */ +typedef enum { + STREAMRECORDER_FILE_FORMAT_3GP, /**< 3GP file format */ + STREAMRECORDER_FILE_FORMAT_MP4, /**< MP4 file format */ + STREAMRECORDER_FILE_FORMAT_AMR, /**< AMR file format */ + STREAMRECORDER_FILE_FORMAT_ADTS, /**< ADTS file format */ + STREAMRECORDER_FILE_FORMAT_WAV, /**< WAV file format */ +} streamrecorder_file_format_e; + +/** + * @brief Enumeration for the audio codec. + * @since_tizen 3.0 + */ +typedef enum { + STREAMRECORDER_AUDIO_CODEC_AMR = 0, /**< AMR codec */ + STREAMRECORDER_AUDIO_CODEC_AAC, /**< AAC codec */ + STREAMRECORDER_AUDIO_CODEC_PCM /**< PCM codec */ +} streamrecorder_audio_codec_e; + +/** + * @brief Enumeration for the video codec. + * @since_tizen 3.0 + */ +typedef enum { + STREAMRECORDER_VIDEO_CODEC_H263, /**< H263 codec */ + STREAMRECORDER_VIDEO_CODEC_MPEG4, /**< MPEG4 codec */ +} streamrecorder_video_codec_e; + +/** + * @brief Enumeration for the recording limit reached. + * @since_tizen 3.0 + */ +typedef enum { + STREAMRECORDER_RECORDING_LIMIT_TYPE_TIME, /**< Time limit (second) of recording file */ + STREAMRECORDER_RECORDING_LIMIT_TYPE_SIZE, /**< Size limit (kilo bytes [KB]) of recording file */ +} streamrecorder_recording_limit_type_e; + +/** + * @brief Enumeration for Streamrecorder error type. + * @since_tizen 3.0 + */ +typedef enum { + STREAMRECORDER_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ + STREAMRECORDER_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ + STREAMRECORDER_ERROR_INVALID_STATE = TIZEN_ERROR_STREAMRECORDER | 0x01, /**< Invalid state */ + STREAMRECORDER_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY , /**< Out of memory */ + STREAMRECORDER_ERROR_INVALID_OPERATION = TIZEN_ERROR_INVALID_OPERATION, /**< Internal error */ + STREAMRECORDER_ERROR_OUT_OF_STORAGE = TIZEN_ERROR_STREAMRECORDER | 0x02, /**< Out of storage */ + STREAMRECORDER_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< The access to the resources can not be granted */ + STREAMRECORDER_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< The feature is not supported */ +} streamrecorder_error_e; + +/** + * @brief Enumeration for the Streamrecorder notification. + * @since_tizen 3.0 + */ +typedef enum { + STREAMRECORDER_NOTIFY_NONE = 0, /**< None */ + STREAMRECORDER_NOTIFY_STATE_CHANGED, /**< The notification of normal state changes */ +} streamrecorder_notify_e; + +/** + * @brief Enumeration for Streamrecorder states. + * @since_tizen 3.0 + */ +typedef enum { + STREAMRECORDER_STATE_NONE, /**< StreamRecorder is not created */ + STREAMRECORDER_STATE_CREATED, /**< StreamRecorder is created, but not prepared */ + STREAMRECORDER_STATE_PREPARED, /**< StreamRecorder is prepared to record */ + STREAMRECORDER_STATE_RECORDING, /**< StreamRecorder is recording media */ + STREAMRECORDER_STATE_PAUSED, /**< StreamRecorder is paused while recording media */ +} streamrecorder_state_e; + +/** + * @} + */ + +/** + * @addtogroup CAPI_MEDIA_STREAMRECORDER_CALLBACK_MODULE + * @{ + */ + +/** + * @brief Called when limitation error occurs while recording. + * @details The callback function is possible to receive three types of limits: time and size. + * @since_tizen 3.0 + * @remarks After being called, recording data except present recorded data will be discarded and not written in the recording file. Also the state of streamrecorder is not changed. + * @param[in] type The imitation type + * @param[in] user_data The user data passed from the callback registration function + * @pre You have to register a callback using streamrecorder_set_recording_limit_reached_cb(). + * @see streamrecorder_set_recording_status_cb() + * @see streamrecorder_set_recording_limit_reached_cb() + * @see streamrecorder_unset_recording_limit_reached_cb() + */ +typedef void (*streamrecorder_recording_limit_reached_cb)(streamrecorder_recording_limit_type_e type, void *user_data); + +/** + * @brief Called to indicate the recording status. + * @since_tizen 3.0 + * @remarks This callback function is repeatedly invoked during the #STREAMRECORDER_STATE_RECORDING state. + * @param[in] elapsed_time The time of the recording (milliseconds) + * @param[in] file_size The size of the recording file (KB) + * @param[in] user_data The user data passed from the callback registration function + * @pre streamrecorder_start() will invoke this callback if you register it using streamrecorder_set_recording_status_cb(). + * @see streamrecorder_set_recording_status_cb() + * @see streamrecorder_unset_recording_status_cb() + * @see streamrecorder_start() + */ +typedef void (*streamrecorder_recording_status_cb)(unsigned long long elapsed_time, unsigned long long file_size, void *user_data); + +/** + * @brief Called when the streamrecorder gets some nofications. + * @since_tizen 3.0 + * @param[in] previous The previous state of the streamrecorder + * @param[in] current The current state of the streamrecorder + * @param[in] notification The notification type of the srecorder + * @param[in] user_data The user data passed from the callback registration function + * @pre This function is required to register a callback using streamrecorder_set_notify_cb(). + * @see streamrecorder_set_notify_cb() + * @see streamrecorder_prepare() + * @see streamrecorder_unprepare() + * @see streamrecorder_start() + * @see streamrecorder_pause() + * @see streamrecorder_commit() + * @see streamrecorder_cancel() + */ +typedef void (*streamrecorder_notify_cb)(streamrecorder_state_e previous, streamrecorder_state_e current, streamrecorder_notify_e notification, void *user_data); + +/** + * @brief Called when the error occurred. + * @since_tizen 3.0 + * @remarks This callback informs about the critical error situation. \n + * When being invoked, user should release the resource and terminate the application. \n + * This error code will be reported. \n + * #STREAMRECORDER_ERROR_INVALID_OPERATION \n + * #STREAMRECORDER_ERROR_OUT_OF_MEMORY + * @param[in] error The error code + * @param[in] current_state The current state of the streamrecorder + * @param[in] user_data The user data passed from the callback registration function + * @pre This callback function is invoked if you register this callback using streamrecorder_set_error_cb(). + * @see streamrecorder_set_error_cb() + * @see streamrecorder_unset_error_cb() + */ +typedef void (*streamrecorder_error_cb)(streamrecorder_error_e error, streamrecorder_state_e current_state, void *user_data); + +/** + * @brief Called iteratively to notify about the buffer has been consumed + * @since_tizen 3.0 + * @remarks The user needs to release consumed buffer if buffer is allocated by user including media packet + * @param[in] buffer The consumed buffer that user pushed + * @param[in] user_data The user data passed + * @see streamrecorder_set_buffer_consume_completed_cb() will invoke this callback. + * @see streamrecorder_unset_buffer_consume_completed_cb() + */ +typedef void (*streamrecorder_consume_completed_cb)(void *buffer, void *user_data); + +/** + * @} + */ + +/** + * @addtogroup CAPI_MEDIA_STREAMRECORDER_CAPABILITY_MODULE + * @{ + */ + +/** + * @brief Called once for each supported video resolution. + * @since_tizen 3.0 + * @param[in] width The video image width + * @param[in] height The video image height + * @param[in] user_data The user data passed from the foreach function + * @return @c true to continue with the next iteration of the loop, \n otherwise @c false to break out of the loop + * @pre streamrecorder_foreach_supported_video_resolution() will invoke this callback. + * @see streamrecorder_foreach_supported_video_resolution() + */ +typedef bool (*streamrecorder_supported_video_resolution_cb)(int width, int height, void *user_data); + +/** + * @brief Called iteratively to notify about the supported file formats. + * @since_tizen 3.0 + * @param[in] format The format of recording files + * @param[in] user_data The user data passed from the foreach function + * @return @c true to continue with the next iteration of the loop, \n otherwise @c false to break out of the loop + * @pre streamrecorder_foreach_supported_file_format() will invoke this callback. + * @see streamrecorder_foreach_supported_file_format() + */ +typedef bool (*streamrecorder_supported_file_format_cb)(streamrecorder_file_format_e format, void *user_data); + +/** + * @brief Called iteratively to notify about the supported audio encoders. + * @since_tizen 3.0 + * @param[in] codec The codec of audio encoder + * @param[in] user_data The user data passed from the foreach function + * @return @c true to continue with the next iteration of the loop, \n otherwise @c false to break out of the loop + * @pre streamrecorder_foreach_supported_audio_encoder() will invoke this callback. + * @see streamrecorder_foreach_supported_audio_encoder() + */ +typedef bool (*streamrecorder_supported_audio_encoder_cb)(streamrecorder_audio_codec_e codec, void *user_data); + +/** + * @brief Called iteratively to notify about the supported video encoders. + * @since_tizen 3.0 + * @param[in] codec The codec of video encoder + * @param[in] user_data The user data passed from the foreach function + * @return @c true to continue with the next iteration of the loop, \n otherwise @c false to break out of the loop + * @pre streamrecorder_foreach_supported_video_encoder() will invoke this callback. + * @see streamrecorder_foreach_supported_video_encoder() + */ +typedef bool (*streamrecorder_supported_video_encoder_cb)(streamrecorder_video_codec_e codec, void *user_data); + +/** + * @} + */ + +/** + * @addtogroup CAPI_MEDIA_STREAMRECORDER_MODULE + * @{ + */ + +/** + * @brief Creates a streamrecorder handle to record a video or audio + * @since_tizen 3.0 + * @remarks You must release @a recorder using streamrecorder_destroy(). + * @param[out] recorder A handle to the streamrecorder + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_OUT_OF_MEMORY Out of memory + * @retval #STREAMRECORDER_ERROR_INVALID_OPERATION Invalid operation + */ +int streamrecorder_create(streamrecorder_h *recorder); + +/** + * @brief Destroys the streamrecorder handle + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_OPERATION Invalid operation + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @pre The recorder state should be #STREAMRECORDER_STATE_CREATED. + * @post The recorder state will be #STREAMRECORDER_STATE_NONE. + */ +int streamrecorder_destroy(streamrecorder_h recorder); + +/** + * @brief Prepares the streamrecorder for recording. + * @since_tizen 3.0 + * @remarks Before calling the function, it is required to properly set streamrecorder_enable_source_buffer(), + * audio encoder (streamrecorder_set_audio_encoder()), + * video encoder(streamrecorder_set_video_encoder()) and file format (streamrecorder_set_file_format()). + * @param[in] recorder The handle to the streamrecorder + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_OPERATION Invalid operation + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @pre The recorder state should be #STREAMRECORDER_STATE_CREATED. \n + * The streamrecorder_enable_source_buffer() should be invoked before this function. + * @post The streamrecorder state will be #STREAMRECORDER_STATE_PREPARED + * @see streamrecorder_unprepare() + * @see streamrecorder_set_audio_encoder() + * @see streamrecorder_set_video_encoder() + * @see streamrecorder_set_file_format() + */ +int streamrecorder_prepare(streamrecorder_h recorder); + +/** + * @brief Resets the streamrecorder. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_OPERATION Invalid operation + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @pre The streamrecorder state should be #STREAMRECORDER_STATE_PREPARED set by streamrecorder_prepare(), streamrecorder_cancel() or streamrecorder_commit(). + * @post The streamrecorder state will be #STREAMRECORDER_STATE_CREATED. + * @see streamrecorder_prepare() + * @see streamrecorder_cancel() + * @see streamrecorder_commit() + */ +int streamrecorder_unprepare(streamrecorder_h recorder); + +/** + * @brief Starts the recording. + * @since_tizen 3.0 + * @remarks If file path has been set to an existing file, this file is removed automatically and updated by new one. \n + * When you want to record audio or video file, you need to add privilege according to rules below additionally. \n + * http://tizen.org/privilege/mediastorage is needed if input or output path are relevant to media storage.\n + * http://tizen.org/privilege/externalstorage is needed if input or output path are relevant to external storage. + * The filename should be set before this function is invoked. + * @param[in] recorder The handle to the streamrecorder + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_OPERATION Invalid operation + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @retval #STREAMRECORDER_ERROR_PERMISSION_DENIED The access to the resources can not be granted + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_PREPARED by streamrecorder_prepare() or #STREAMRECORDER_STATE_PAUSED by streamrecorder_pause(). \n + * The filename should be set by streamrecorder_set_filename(). + * @post The recorder state will be #STREAMRECORDER_STATE_RECORDING. + * @see streamrecorder_pause() + * @see streamrecorder_commit() + * @see streamrecorder_cancel() + * @see streamrecorder_set_audio_encoder() + * @see streamrecorder_set_filename() + * @see streamrecorder_set_file_format() + * @see streamrecorder_recording_status_cb() + * @see streamrecorder_set_filename() + */ +int streamrecorder_start(streamrecorder_h recorder); + +/** + * @brief Pauses the recording. + * @since_tizen 3.0 + * @remarks Recording can be resumed with streamrecorder_start(). + * @param[in] recorder The handle to the streamrecorder + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_OPERATION Invalid operation + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_RECORDING. + * @post The streamrecorder state will be #STREAMRECORDER_STATE_PAUSED. + * @see streamrecorder_pause() + * @see streamrecorder_commit() + * @see streamrecorder_cancel() + */ +int streamrecorder_pause(streamrecorder_h recorder); + +/** + * @brief Stops recording and saves the result. + * @since_tizen 3.0 + * @remarks When you want to record audio or video file, you need to add privilege according to rules below additionally. \n + * http://tizen.org/privilege/mediastorage is needed if input or output path are relevant to media storage.\n + * http://tizen.org/privilege/externalstorage is needed if input or output path are relevant to external storage. + * @param[in] recorder The handle to the streamrecorder + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_OPERATION Invalid operation + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @retval #STREAMRECORDER_ERROR_PERMISSION_DENIED The access to the resources can not be granted + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_RECORDING set by streamrecorder_start() or #STREAMRECORDER_STATE_PAUSED by streamrecorder_pause(). + * @post The streamrecorder state will be #STREAMRECORDER_STATE_PREPARED. + * @see streamrecorder_pause() + * @see streamrecorder_cancel() + * @see streamrecorder_set_filename() + * @see streamrecorder_start() + */ +int streamrecorder_commit(streamrecorder_h recorder); + +/** + * @brief Cancels the recording. + * @details The recording data is discarded and not written in the recording file. + * @since_tizen 3.0 + * @remarks When you want to record audio or video file, you need to add privilege according to rules below additionally. \n + * http://tizen.org/privilege/mediastorage is needed if input or output path are relevant to media storage.\n + * http://tizen.org/privilege/externalstorage is needed if input or output path are relevant to external storage. + * @param[in] recorder The handle to the streamrecorder + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_OPERATION Invalid operation + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @retval #STREAMRECORDER_ERROR_PERMISSION_DENIED The access to the resources can not be granted + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_RECORDING set by streamrecorder_start() or #STREAMRECORDER_STATE_PAUSED by streamrecorder_pause(). + * @post The streamrecorder state will be #STREAMRECORDER_STATE_PREPARED. + * @see streamrecorder_pause() + * @see streamrecorder_commit() + * @see streamrecorder_cancel() + * @see streamrecorder_start() + */ +int streamrecorder_cancel(streamrecorder_h recorder); + +/** + * @brief Pushes buffer to StreamRecorder to record audio/video + * @since_tizen 3.0 + * @remarks When you want to record audio or video file, you need to add privilege according to rules below additionally. \n + * http://tizen.org/privilege/mediastorage is needed if input or output path are relevant to media storage.\n + * http://tizen.org/privilege/externalstorage is needed if input or output path are relevant to external storage. + * @param[in] recorder The handle to the streamrecorder + * @param[in] inbuf The media packet containing buffer and other associated values + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_PERMISSION_DENIED The access to the resources can not be granted + */ +int streamrecorder_push_stream_buffer(streamrecorder_h recorder, media_packet_h inbuf); + +/** + * @brief Sets the video source as live buffer to be used for recording + * @since_tizen 3.0 + * @remarks if you want to enable video or audio or both recording, call before streamrecorder_prepare() + * @param[in] recorder A handle to the streamrecorder + * @param[in] type The type of source input + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @pre The streamrecorder state must be only #STREAMRECORDER_STATE_CREATED + */ +int streamrecorder_enable_source_buffer(streamrecorder_h recorder, streamrecorder_source_e type); + +/** + * @brief Gets the streamrecorder's current state. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[out] state The current state of the streamrecorder + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + */ +int streamrecorder_get_state(streamrecorder_h recorder, streamrecorder_state_e *state); + +/** + * @} + */ + +/** + * @addtogroup CAPI_MEDIA_STREAMRECORDER_ATTRIBUTES_MODULE + * @{ + */ + + +/** + * @brief Sets the file path to record. + * @details This function sets file path which defines where newly recorded data should be stored. + * @since_tizen 3.0 + * @remarks If the same file already exists in the file system, then old file will be overwritten. + * @param[in] recorder The handle to the streamrecorder + * @param[in] path The recording file path + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_CREATED. \n + * streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_get_filename() + */ +int streamrecorder_set_filename(streamrecorder_h recorder, const char *path); + +/** + * @brief Gets the file path to record. + * @since_tizen 3.0 + * @remarks You must release @a path using free(). + * @param[in] recorder The handle to the streamrecorder + * @param[out] path The recording file path + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_set_filename() + */ +int streamrecorder_get_filename(streamrecorder_h recorder, char **path); + +/** + * @brief Sets the file format for recording media stream. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[in] format The media file format + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @retval #STREAMRECORDER_ERROR_INVALID_OPERATION Invalid operation + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_CREATED. \n + * streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_get_file_format() + * @see streamrecorder_foreach_supported_file_format() + */ +int streamrecorder_set_file_format(streamrecorder_h recorder, streamrecorder_file_format_e format); + + +/** + * @brief Gets the file format for recording media stream. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[out] format The media file format + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @pre The streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_set_file_format() + * @see streamrecorder_foreach_supported_file_format() + */ +int streamrecorder_get_file_format(streamrecorder_h recorder, streamrecorder_file_format_e *format); + + +/** + * @brief Sets the audio codec for encoding an audio stream. + * @since_tizen 3.0 + * @remarks You can get available audio encoders by using streamrecorder_foreach_supported_audio_encoder(). \n + * @param[in] recorder The handle to the streamrecorder + * @param[in] codec The audio codec + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @retval #STREAMRECORDER_ERROR_NOT_SUPPORTED The feature is not supported + * @retval #STREAMRECORDER_ERROR_INVALID_OPERATION Invalid operation + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_CREATED. \n + * streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_get_audio_encoder() + * @see streamrecorder_foreach_supported_audio_encoder() + */ +int streamrecorder_set_audio_encoder(streamrecorder_h recorder, streamrecorder_audio_codec_e codec); + +/** + * @brief Gets the audio codec for encoding an audio stream. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[out] codec The audio codec + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_NOT_SUPPORTED The feature is not supported + * @pre The streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_set_audio_encoder() + * @see streamrecorder_foreach_supported_audio_encoder() + */ +int streamrecorder_get_audio_encoder(streamrecorder_h recorder, streamrecorder_audio_codec_e *codec); + +/** + * @brief Sets the resolution of the video recording. + * @since_tizen 3.0 + * @remarks This function should be called before recording (streamrecorder_start()). + * @param[in] recorder The handle to the streamrecorder + * @param[in] width The input width + * @param[in] height The input height + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @retval #STREAMRECORDER_ERROR_NOT_SUPPORTED The feature is not supported + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_CREATED. \n + * streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_start() + * @see streamrecorder_get_video_resolution() + * @see streamrecorder_foreach_supported_video_resolution() + */ +int streamrecorder_set_video_resolution(streamrecorder_h recorder, int width, int height); + +/** + * @brief Gets the resolution of the video recording. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[out] width The video width + * @param[out] height The video height + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_NOT_SUPPORTED The feature is not supported + * @pre The streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_set_video_resolution() + * @see streamrecorder_foreach_supported_video_resolution() + */ +int streamrecorder_get_video_resolution(streamrecorder_h recorder, int *width, int *height); + +/** + * @brief Sets the video codec for encoding video stream. + * @since_tizen 3.0 + * @remarks You can get available video encoders by using recorder_foreach_supported_video_encoder(). + * @param[in] recorder The handle to the streamrecorder + * @param[in] codec The video codec + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @retval #STREAMRECORDER_ERROR_NOT_SUPPORTED The feature is not supported + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_CREATED. \n + * streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_get_video_encoder() + * @see streamrecorder_foreach_supported_video_encoder() + */ +int streamrecorder_set_video_encoder(streamrecorder_h recorder, streamrecorder_video_codec_e codec); + +/** + * @brief Gets the video codec for encoding video stream. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[out] codec The video codec + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_NOT_SUPPORTED The feature is not supported + * @pre The streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_set_video_encoder() + * @see streamrecorder_foreach_supported_video_encoder() + */ +int streamrecorder_get_video_encoder(streamrecorder_h recorder, streamrecorder_video_codec_e *codec); + +/** + * @brief Sets the recording frame rate. + * @since_tizen 3.0 + * @remarks This function should be called before prepared state. + * @param[in] recorder The handle to the streamrecorder + * @param[in] framerate The frame rate for recording + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @see streamrecorder_get_video_framerate() + */ +int streamrecorder_set_video_framerate(streamrecorder_h recorder, int framerate); + +/** + * @brief Gets the recording frame rate. + * @since_tizen 3.0 + * @param[in] recorder The handle to the camera + * @param[out] framerate The frame rate for recording that already is set + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @see streamrecorder_set_video_framerate() + */ +int streamrecorder_get_video_framerate(streamrecorder_h recorder, int *framerate); + +/** + * @brief Sets the video source format. + * @since_tizen 3.0 + * @remarks This function should be called before prepared state. + * @param[in] recorder The handle to the streamrecorder + * @param[in] format The color type of video source + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @see streamrecorder_get_video_source_format() + */ +int streamrecorder_set_video_source_format(streamrecorder_h recorder, streamrecorder_video_source_format_e format); + +/** + * @brief Gets the video source format. + * @since_tizen 3.0 + * @remarks This function should be called before prepared state. + * @param[in] recorder The handle to the streamrecorder + * @param[out] format The color type of video source that already is set + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @see streamrecorder_set_video_source_format() + */ +int streamrecorder_get_video_source_format(streamrecorder_h recorder, streamrecorder_video_source_format_e *format); + +/** + * @brief Sets the maximum size of a recording file. + * @since_tizen 3.0 + * @remarks After reaching the limitation, the recording data is discarded and not written in the recording file. + * @param[in] recorder The handle to the streamrecorder + * @param[in] type The recording limit type + * @param[in] limit If limit type is STREAMRECORDER_RECORDING_LIMIT_TYPE_SIZE, the limit value is the maximum size of the recording file(KB), \n + * otherwise limit value is the maximum time of the recording file (in seconds) \n + * @c 0 means unlimited recording size or time. + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_CREATED. \n + * streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_get_recording_limit() + */ +int streamrecorder_set_recording_limit(streamrecorder_h recorder, streamrecorder_recording_limit_type_e type, int limit); + +/** + * @brief Gets the maximum size of a recording file. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[in] type The recording limit type + * @param[out] limit If limit type is STREAMRECORDER_RECORDING_LIMIT_TYPE_SIZE, the limit value is the maximum size of the recording file(KB), \n + * otherwise limit value is the maximum time of the recording file (in seconds) \n + * @c 0 means unlimited recording size or time. + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @pre The streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_set_recording_limit() + */ +int streamrecorder_get_recording_limit(streamrecorder_h recorder, streamrecorder_recording_limit_type_e type, int *limit); + +/** + * @brief Sets the sampling rate of an audio stream. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[in] samplerate The sample rate in Hertz + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_CREATED. \n + * streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_get_audio_samplerate() + */ +int streamrecorder_set_audio_samplerate(streamrecorder_h recorder, int samplerate); + +/** + * @brief Gets the sampling rate of an audio stream. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[out] samplerate The sample rate in Hertz + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @pre The streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_set_audio_samplerate() + */ +int streamrecorder_get_audio_samplerate(streamrecorder_h recorder, int *samplerate); + +/** + * @brief Sets the bitrate of an audio encoder. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[in] bitrate The bitrate (for mms : 12200[bps], normal : 288000[bps]) + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_CREATED. \n + * streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_get_audio_encoder_bitrate() + */ +int streamrecorder_set_audio_encoder_bitrate(streamrecorder_h recorder, int bitrate); + +/** + * @brief Sets the bitrate of a video encoder. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[in] bitrate The bitrate in bits per second + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_CREATED. \n + * streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_get_video_encoder_bitrate() + */ +int streamrecorder_set_video_encoder_bitrate(streamrecorder_h recorder, int bitrate); + +/** + * @brief Gets the bitrate of an audio encoder. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[out] bitrate The bitrate in bits per second + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @pre The streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_set_audio_encoder_bitrate() + */ +int streamrecorder_get_audio_encoder_bitrate(streamrecorder_h recorder, int *bitrate); + +/** + * @brief Gets the bitrate of a video encoder. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[out] bitrate The bitrate in bits per second + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @pre The streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_set_audio_encoder_bitrate() + */ +int streamrecorder_get_video_encoder_bitrate(streamrecorder_h recorder, int *bitrate); + +/** + * @brief Sets the number of the audio channel. + * @since_tizen 3.0 + * @remarks This attribute is applied only in STREAMRECORDER_STATE_CREATED state. \n + * For mono recording, setting channel to @c 1. \n + * For stereo recording, setting channel to @c 2. + * @param[in] recorder The handle to the streamrecorder + * @param[in] channel_count The number of the audio channel + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #STREAMRECORDER_ERROR_INVALID_STATE Invalid state + * @pre The streamrecorder state must be #STREAMRECORDER_STATE_CREATED.\n + * streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_get_audio_channel() + */ +int streamrecorder_set_audio_channel(streamrecorder_h recorder, int channel_count); + +/** + * @brief Gets the number of the audio channel. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[out] channel_count The number of the audio channel + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @pre The streamrecorder_enable_source_buffer() should be invoked before this function. + * @see streamrecorder_set_audio_channel() + */ +int streamrecorder_get_audio_channel(streamrecorder_h recorder, int *channel_count); + +/** + * @} + */ + +/** + * @addtogroup CAPI_MEDIA_STREAMRECORDER_CAPABILITY_MODULE + * @{ + */ + + +/** + * @brief Retrieves all supported file formats by invoking a specific callback for each supported file format. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[in] callback The iteration callback + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @post streamrecorder_supported_file_format_cb() will be invoked. + * @see streamrecorder_get_file_format() + * @see streamrecorder_set_file_format() + * @see streamrecorder_supported_file_format_cb() + */ +int streamrecorder_foreach_supported_file_format(streamrecorder_h recorder, streamrecorder_supported_file_format_cb callback, void *user_data); + +/** + * @brief Retrieves all supported audio encoders by invoking a specific callback for each supported audio encoder. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[in] callback The iteration callback + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @post streamrecorder_supported_audio_encoder_cb() will be invoked. + * @see streamrecorder_set_audio_encoder() + * @see streamrecorder_get_audio_encoder() + * @see streamrecorder_supported_audio_encoder_cb() + */ +int streamrecorder_foreach_supported_audio_encoder(streamrecorder_h recorder, streamrecorder_supported_audio_encoder_cb callback, void *user_data); + +/** + * @brief Retrieves all supported video encoders by invoking a specific callback for each supported video encoder. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[in] callback The iteration callback + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @post streamrecorder_supported_video_encoder_cb() will be invoked. + * @see streamrecorder_set_video_encoder() + * @see streamrecorder_get_video_encoder() + * @see streamrecorder_supported_video_encoder_cb() + */ +int streamrecorder_foreach_supported_video_encoder(streamrecorder_h recorder, streamrecorder_supported_video_encoder_cb callback, void *user_data); + +/** + * @brief Retrieves all supported video resolutions by invoking callback function once for each supported video resolution. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[in] foreach_cb The callback function to be invoked + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @post This function invokes streamrecorder_supported_video_resolution_cb() repeatedly to retrieve each supported video resolution. + * @see streamrecorder_set_video_resolution() + * @see streamrecorder_get_video_resolution() + * @see streamrecorder_supported_video_resolution_cb() + */ +int streamrecorder_foreach_supported_video_resolution(streamrecorder_h recorder, + streamrecorder_supported_video_resolution_cb foreach_cb, void *user_data); + +/** + * @} + */ + +/** + * @addtogroup CAPI_MEDIA_STREAMRECORDER_CALLBACK_MODULE + * @{ + */ + + +/** + * @brief Registers the callback function that will be invoked when the streamrecorder get some notification. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[in] callback The function pointer of user callback + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @post streamrecorder_notify_cb() will be invoked. + * @see streamrecorder_unset_notify_cb() + * @see streamrecorder_notify_cb() + */ +int streamrecorder_set_notify_cb(streamrecorder_h recorder, streamrecorder_notify_cb callback, void *user_data); + +/** + * @brief Unregisters the callback function. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @see streamrecorder_set_notify_cb() + */ +int streamrecorder_unset_notify_cb(streamrecorder_h recorder); + +/** + * @brief Registers a callback function to be invoked when the recording information changes. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @param[in] callback The function pointer of user callback + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @post streamrecorder_recording_status_cb() will be invoked. + * @see streamrecorder_unset_recording_status_cb() + * @see streamrecorder_recording_status_cb() + */ +int streamrecorder_set_recording_status_cb(streamrecorder_h recorder, streamrecorder_recording_status_cb callback, void *user_data); + +/** + * @brief Unregisters the callback function. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @see streamrecorder_set_recording_status_cb() + */ +int streamrecorder_unset_recording_status_cb(streamrecorder_h recorder); + +/** + * @brief Registers the callback function to be run when reached the recording limit. + * @since_tizen 3.0 + * @param[in] recorder The handle to treamrecorder + * @param[in] callback The function pointer of user callback + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @post streamrecorder_recording_limit_reached_cb() will be invoked. + * @see streamrecorder_unset_recording_limit_reached_cb() + * @see streamrecorder_set_size_limit() + * @see streamrecorder_set_time_limit() + * @see streamrecorder_recording_limit_reached_cb() + */ +int streamrecorder_set_recording_limit_reached_cb(streamrecorder_h recorder, streamrecorder_recording_limit_reached_cb callback, void *user_data); + +/** + * @brief Unregisters the callback function. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @see streamrecorder_set_recording_limit_reached_cb() + */ +int streamrecorder_unset_recording_limit_reached_cb(streamrecorder_h recorder); + +/** + * @brief Registers a callback function to be called when an asynchronous operation error occurred. + * @since_tizen 3.0 + * @remarks This callback informs critical error situation.\n + * When this callback is invoked, user should release the resource and terminate the application. \n + * These error codes will occur. \n + * #STREAMRECORDER_ERROR_INVALID_OPERATION \n + * #STREAMRECORDER_ERROR_OUT_OF_MEMORY + * @param[in] recorder The handle to the streamrecorder + * @param[in] callback The callback function to register + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @post This function will invoke streamrecorder_error_cb() when an asynchronous operation error occur. + * @see streamrecorder_unset_error_cb() + * @see streamrecorder_error_cb() + */ +int streamrecorder_set_error_cb(streamrecorder_h recorder, streamrecorder_error_cb callback, void *user_data); + + +/** + * @brief Unregisters the callback function. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @return @c on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @see streamrecorder_set_error_cb() + */ +int streamrecorder_unset_error_cb(streamrecorder_h recorder); + +/** + * @brief Registers a callback function to be called when asynchronous buffers are consumed. + * @since_tizen 3.0 + * @remarks This callback informs to user dealloc buffer.\n + * When this callback is invoked, user should release the buffer or media packet. \n + * @param[in] recorder The handle to the streamrecorder + * @param[in] callback The callback function to register + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @see streamrecorder_unset_buffer_consume_completed_cb() + * @see streamrecorder_push_stream_buffer() + */ +int streamrecorder_set_buffer_consume_completed_cb(streamrecorder_h recorder, streamrecorder_consume_completed_cb callback, void *user_data); + +/** + * @brief Unregisters the callback function. + * @since_tizen 3.0 + * @param[in] recorder The handle to the streamrecorder + * @return @c on success, otherwise a negative error value + * @retval #STREAMRECORDER_ERROR_NONE Successful + * @retval #STREAMRECORDER_ERROR_INVALID_PARAMETER Invalid parameter + * @see streamrecorder_set_buffer_consume_completed_cb() + */ +int streamrecorder_unset_buffer_consume_completed_cb(streamrecorder_h recorder); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_MEDIA_STREAMRECORDER_H__ */ + diff --git a/include/streamrecorder_private.h b/include/streamrecorder_private.h new file mode 100644 index 0000000..223ece6 --- /dev/null +++ b/include/streamrecorder_private.h @@ -0,0 +1,95 @@ +/* +* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + + +#ifndef __TIZEN_MEDIA_STREAMRECORDER_PRIVATE_H__ +#define __TIZEN_MEDIA_STREAMRECORDER_PRIVATE_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + _STREAMRECORDER_EVENT_TYPE_NOTIFY, + _STREAMRECORDER_EVENT_TYPE_RECORDING_LIMITED, + _STREAMRECORDER_EVENT_TYPE_RECORDING_STATUS, + _STREAMRECORDER_EVENT_TYPE_ERROR, + _STREAMRECORDER_EVENT_TYPE_CONSUME_COMPLETE, + _STREAMRECORDER_EVENT_TYPE_NUM +}_streamrecorder_event_e; + +typedef struct { + MMHandleType mm_handle; + void* user_cb[_STREAMRECORDER_EVENT_TYPE_NUM]; + void* user_data[_STREAMRECORDER_EVENT_TYPE_NUM]; + unsigned int state; + _streamrecorder_event_e type; + double last_max_input_level; +}streamrecorder_s; + +int __convert_streamrecorder_error_code(const char *func, int code); +int _streamrecorder_set_videosource_buffer(streamrecorder_h recorder); +int _streamrecorder_set_audiosource_buffer(streamrecorder_h recorder); +int _streamrecorder_get_state(streamrecorder_h recorder, streamrecorder_state_e *state); +int _streamrecorder_destroy(streamrecorder_h recorder); +int _streamrecorder_prepare(streamrecorder_h recorder); +int _streamrecorder_unprepare(streamrecorder_h recorder); +int _streamrecorder_start(streamrecorder_h recorder); +int _streamrecorder_pause(streamrecorder_h recorder); +int _streamrecorder_commit(streamrecorder_h recorder); +int _streamrecorder_cancel(streamrecorder_h recorder); +int _streamrecorder_set_video_framerate(streamrecorder_h recorder, int framerate); +int _streamrecorder_get_video_framerate(streamrecorder_h recorder, int *framerate); +int _streamrecorder_set_video_source_format(streamrecorder_h recorder, int format); +int _streamrecorder_get_video_source_format(streamrecorder_h recorder, int *format); +int _streamrecorder_set_video_resolution(streamrecorder_h recorder, int width, int height); +int _streamrecorder_get_video_resolution(streamrecorder_h recorder, int *width, int *height); +int _streamrecorder_foreach_supported_video_resolution(streamrecorder_h recorder,streamrecorder_supported_video_resolution_cb foreach_cb, void *user_data); +int _streamrecorder_set_filename(streamrecorder_h recorder, const char *filename); +int _streamrecorder_get_filename(streamrecorder_h recorder, char **filename); +int _streamrecorder_set_file_format(streamrecorder_h recorder, streamrecorder_file_format_e format); +int _streamrecorder_get_file_format(streamrecorder_h recorder, streamrecorder_file_format_e *format); +int _streamrecorder_foreach_supported_file_format(streamrecorder_h recorder, streamrecorder_supported_file_format_cb foreach_cb, void *user_data); +int _streamrecorder_set_size_limit(streamrecorder_h recorder, int kbyte); +int _streamrecorder_set_time_limit(streamrecorder_h recorder, int second); +int _streamrecorder_set_audio_encoder(streamrecorder_h recorder, streamrecorder_audio_codec_e codec); +int _streamrecorder_get_audio_encoder(streamrecorder_h recorder, streamrecorder_audio_codec_e *codec); +int _streamrecorder_set_video_encoder(streamrecorder_h recorder, streamrecorder_video_codec_e codec); +int _streamrecorder_get_video_encoder(streamrecorder_h recorder, streamrecorder_video_codec_e *codec); +int _streamrecorder_set_audio_samplerate(streamrecorder_h recorder, int samplerate); +int _streamrecorder_set_audio_encoder_bitrate(streamrecorder_h recorder, int bitrate); +int _streamrecorder_set_video_encoder_bitrate(streamrecorder_h recorder, int bitrate); +int _streamrecorder_get_size_limit(streamrecorder_h recorder, int *kbyte); +int _streamrecorder_get_time_limit(streamrecorder_h recorder, int *second); +int _streamrecorder_get_audio_samplerate(streamrecorder_h recorder, int *samplerate); +int _streamrecorder_get_audio_encoder_bitrate(streamrecorder_h recorder, int *bitrate); +int _streamrecorder_get_video_encoder_bitrate(streamrecorder_h recorder, int *bitrate); +int _streamrecorder_foreach_supported_audio_encoder(streamrecorder_h recorder, streamrecorder_supported_audio_encoder_cb foreach_cb, void *user_data); +int _streamrecorder_foreach_supported_video_encoder(streamrecorder_h recorder, streamrecorder_supported_video_encoder_cb foreach_cb, void *user_data); +int _streamrecorder_set_audio_channel(streamrecorder_h recorder, int channel_count); +int _streamrecorder_get_audio_channel(streamrecorder_h recorder, int *channel_count); +#ifdef __cplusplus +} +#endif + +#endif //__TIZEN_MEDIA_STREAMRECORDER_PRIVATE_H__ + + diff --git a/packaging/capi-media-streamrecorder.spec b/packaging/capi-media-streamrecorder.spec new file mode 100644 index 0000000..4182c63 --- /dev/null +++ b/packaging/capi-media-streamrecorder.spec @@ -0,0 +1,65 @@ +Name: capi-media-streamrecorder +Summary: A Streamrecorder library in Tizen Native API +Version: 0.0.1 +Release: 0 +Group: Multimedia/Other +License: Apache-2.0 +Source0: %{name}-%{version}.tar.gz +BuildRequires: cmake +BuildRequires: pkgconfig(dlog) +Buildrequires: pkgconfig(mm-streamrecorder) +BuildRequires: pkgconfig(capi-base-common) +BuildRequires: pkgconfig(capi-media-tool) +BuildRequires: pkgconfig(capi-media-audio-io) +BuildRequires: pkgconfig(libtbm) +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%description +A StreamRecorder library in Tizen Native API to record live buffer sent by the application + + +%package devel +Summary: A StreamRecorder library in Tizen Native API (Development) +Requires: %{name} = %{version}-%{release} + + +%description devel +A MediaStreamRecorder library in Tizen Native API Development Package to record live buffer + + +%prep +%setup -q + + +%build +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} +%make_install +mkdir -p %{buildroot}%{_datadir}/license +cp LICENSE.APLv2 %{buildroot}%{_datadir}/license/%{name} + + +%post -p /sbin/ldconfig + + +%postun -p /sbin/ldconfig + +%files +%manifest capi-media-streamrecorder.manifest +%{_libdir}/libcapi-media-streamrecorder.so.* +%{_datadir}/license/%{name} +%{_bindir}/* + +%files devel +%{_includedir}/media/streamrecorder.h +%{_libdir}/pkgconfig/*.pc +%{_libdir}/libcapi-media-streamrecorder.so + diff --git a/src/streamrecorder.c b/src/streamrecorder.c new file mode 100644 index 0000000..380aea9 --- /dev/null +++ b/src/streamrecorder.c @@ -0,0 +1,957 @@ +/* +* Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "TIZEN_N_STREAMRECORDER" + +static int __mm_streamrecorder_msg_cb(int message, void *param, void *user_data); + + +int streamrecorder_create(streamrecorder_h *recorder) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + streamrecorder_s *handle = NULL; + handle = (streamrecorder_s *)malloc(sizeof(streamrecorder_s)); + if (handle == NULL) { + LOGE("[%s] malloc error", __func__); + return STREAMRECORDER_ERROR_OUT_OF_MEMORY; + } + + memset(handle, 0 , sizeof(streamrecorder_s)); + + ret = mm_streamrecorder_create(&handle->mm_handle); + if (ret != MM_ERROR_NONE) { + free(handle); + LOGE("[%s] mm_streamrecorder_create fail", __func__); + return __convert_streamrecorder_error_code(__func__, ret); + } + + mm_streamrecorder_set_message_callback(handle->mm_handle, __mm_streamrecorder_msg_cb, (void *)handle); + + *recorder = (streamrecorder_h)handle; + return ret; +} + +int streamrecorder_get_state(streamrecorder_h recorder, streamrecorder_state_e *state) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + ret = _streamrecorder_get_state(recorder, state); + + return ret; +} + +int streamrecorder_enable_source_buffer(streamrecorder_h recorder, streamrecorder_source_e type) +{ + int ret = STREAMRECORDER_ERROR_NONE; + if (recorder == NULL) { + LOGE("NULL video pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + if (type == STREAMRECORDER_SOURCE_VIDEO) { + ret = _streamrecorder_set_videosource_buffer(recorder); + } else if (type == STREAMRECORDER_SOURCE_AUDIO) { + ret = _streamrecorder_set_audiosource_buffer(recorder); + } else { + ret = _streamrecorder_set_videosource_buffer(recorder); + if (ret == STREAMRECORDER_ERROR_NONE) { + ret = _streamrecorder_set_audiosource_buffer(recorder); + } + } + return ret; +} + +int streamrecorder_push_stream_buffer(streamrecorder_h recorder, media_packet_h packet) +{ + int ret = MM_ERROR_NONE; + uint64_t pts = 0; + bool flag = FALSE; + tbm_surface_h surface = NULL; + int width; + int height; + + if ((recorder == NULL) || (packet == NULL)) { + LOGE("[%s] INVALID_PARAMETER(0x%08x)", __func__, STREAMRECORDER_ERROR_INVALID_PARAMETER); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + /* pts */ + media_packet_get_pts(packet, &pts); + media_packet_is_video(packet, &flag); + if (flag) { + media_format_h fmt = NULL; + media_format_mimetype_e mimetype = 0; + media_packet_get_format(packet, &fmt); + media_format_get_video_info(fmt, &mimetype, &width, &height, NULL, NULL); + media_format_unref(fmt); + + if ((mimetype == MEDIA_FORMAT_NV12) || (mimetype == MEDIA_FORMAT_NV21)) { + MMVideoBuffer *video_buf = NULL; + void *dataPtr = NULL; + video_buf = (MMVideoBuffer *)malloc(sizeof(MMVideoBuffer)); + if (!video_buf) { + LOGE("Failed to alloc MMVideoBuffer"); + return STREAMRECORDER_ERROR_OUT_OF_MEMORY; + } + memset(video_buf, 0x00, sizeof(MMVideoBuffer)); + media_packet_get_buffer_data_ptr(packet, (void **)&dataPtr); + media_packet_get_tbm_surface(packet, &surface); + if (surface == NULL) { + LOGE("Failed to get surface"); + free(video_buf); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + video_buf->handle_num = tbm_surface_internal_get_num_bos(surface); + video_buf->type = MM_VIDEO_BUFFER_TYPE_TBM_BO; + video_buf->handle.paddr[0] = dataPtr; + video_buf->data[0] = dataPtr; + video_buf->width[0] = width; + video_buf->height[0] = height; + video_buf->stride_width[0] = video_buf->width[0]; + video_buf->stride_height[0] = video_buf->height[0]; + video_buf->size[0] = width*height*3/2; + + ret = mm_streamrecorder_push_stream_buffer(handle->mm_handle, MM_STREAM_TYPE_VIDEO, pts, video_buf, video_buf->size[0]); + free(video_buf); + } else if (mimetype == MEDIA_FORMAT_I420) { + void *buf_data = NULL; + uint64_t buf_size = 0; + ret = media_packet_get_buffer_size(packet, &buf_size); + if (ret != MEDIA_PACKET_ERROR_NONE) { + LOGW("buffer size get fail"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + ret = media_packet_get_buffer_data_ptr(packet, (void **)&buf_data); + if (ret != MEDIA_PACKET_ERROR_NONE) { + LOGW("buffer size get fail"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + ret = mm_streamrecorder_push_stream_buffer(handle->mm_handle, MM_STREAM_TYPE_VIDEO, pts, buf_data, buf_size); + } + } else { + media_packet_is_audio(packet, &flag); + if (flag) { + void *buf_data = NULL; + uint64_t buf_size = 0; + ret = media_packet_get_buffer_size(packet, &buf_size); + if (ret != MEDIA_PACKET_ERROR_NONE) { + LOGW("buffer size get fail"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + ret = media_packet_get_buffer_data_ptr(packet, &buf_data); + if (ret != MEDIA_PACKET_ERROR_NONE) { + LOGW("buffer size get fail"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + ret = mm_streamrecorder_push_stream_buffer(handle->mm_handle, MM_STREAM_TYPE_AUDIO, pts, buf_data, buf_size); + } + + } + return __convert_streamrecorder_error_code(__func__, ret); +} + + +int streamrecorder_destroy(streamrecorder_h recorder) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_destroy(recorder); + + return ret; +} + + +int streamrecorder_prepare(streamrecorder_h recorder) +{ + int ret = STREAMRECORDER_ERROR_NONE; + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + ret = _streamrecorder_prepare(recorder); + + return ret; +} + + +int streamrecorder_unprepare(streamrecorder_h recorder) +{ + int ret = STREAMRECORDER_ERROR_NONE; + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + ret = _streamrecorder_unprepare(recorder); + + return ret; + +} + + +int streamrecorder_start(streamrecorder_h recorder) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL startointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_start(recorder); + return ret; +} + + +int streamrecorder_pause(streamrecorder_h recorder) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_pause(recorder); + return ret; +} + + +int streamrecorder_commit(streamrecorder_h recorder) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_commit(recorder); + return ret; +} + + +int streamrecorder_cancel(streamrecorder_h recorder) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_cancel(recorder); + return ret; +} + +int streamrecorder_set_video_framerate(streamrecorder_h recorder, int framerate) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_set_video_framerate(recorder, framerate); + return ret; + +} + +int streamrecorder_get_video_framerate(streamrecorder_h recorder, int *framerate) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_get_video_framerate(recorder, framerate); + return ret; +} + +int streamrecorder_set_video_source_format(streamrecorder_h recorder, streamrecorder_video_source_format_e format) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_set_video_source_format(recorder, format); + return ret; +} + +int streamrecorder_get_video_source_format(streamrecorder_h recorder, streamrecorder_video_source_format_e *format) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_get_video_source_format(recorder, format); + return ret; +} + + +int streamrecorder_set_video_resolution(streamrecorder_h recorder, int width, int height) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_set_video_resolution(recorder, width, height); + return ret; +} + +int streamrecorder_get_video_resolution(streamrecorder_h recorder, int *width, int *height) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_get_video_resolution(recorder, width , height); + return ret; +} + + + +int streamrecorder_foreach_supported_video_resolution(streamrecorder_h recorder, + streamrecorder_supported_video_resolution_cb foreach_cb, void *user_data) +{ + + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + ret = _streamrecorder_foreach_supported_video_resolution(recorder, foreach_cb, user_data); + return ret; + + +} + +int streamrecorder_set_filename(streamrecorder_h recorder, const char *filename) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_set_filename(recorder, filename); + return ret; +} + + +int streamrecorder_get_filename(streamrecorder_h recorder, char **filename) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_get_filename(recorder, filename); + return ret; +} + + +int streamrecorder_set_file_format(streamrecorder_h recorder, streamrecorder_file_format_e format) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_set_file_format(recorder, format); + return ret; +} + + +int streamrecorder_get_file_format(streamrecorder_h recorder, streamrecorder_file_format_e *format) +{ + + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_get_file_format(recorder, format); + return ret; + +} + + +int streamrecorder_set_notify_cb(streamrecorder_h recorder, streamrecorder_notify_cb callback, void *user_data) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + if (callback == NULL) { + LOGE("NULL pointer callback"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + handle->user_cb[_STREAMRECORDER_EVENT_TYPE_NOTIFY] = callback; + handle->user_data[_STREAMRECORDER_EVENT_TYPE_NOTIFY] = user_data; + + return STREAMRECORDER_ERROR_NONE; +} + + +int streamrecorder_unset_notify_cb(streamrecorder_h recorder) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + handle->user_cb[_STREAMRECORDER_EVENT_TYPE_NOTIFY] = NULL; + handle->user_data[_STREAMRECORDER_EVENT_TYPE_NOTIFY] = NULL; + + return STREAMRECORDER_ERROR_NONE; +} + +int streamrecorder_set_buffer_consume_completed_cb(streamrecorder_h recorder, streamrecorder_consume_completed_cb callback, void *user_data) +{ + if (recorder == NULL) + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + if (callback == NULL) + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + + handle->user_cb[_STREAMRECORDER_EVENT_TYPE_CONSUME_COMPLETE] = callback; + handle->user_data[_STREAMRECORDER_EVENT_TYPE_CONSUME_COMPLETE] = user_data; + return STREAMRECORDER_ERROR_NONE; +} + +int streamrecorder_unset_buffer_consume_completed_cb(streamrecorder_h recorder) +{ + if (recorder == NULL) + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + handle->user_cb[_STREAMRECORDER_EVENT_TYPE_CONSUME_COMPLETE] = NULL; + handle->user_data[_STREAMRECORDER_EVENT_TYPE_CONSUME_COMPLETE] = NULL; + return STREAMRECORDER_ERROR_NONE; +} + +int streamrecorder_set_error_cb(streamrecorder_h recorder, streamrecorder_error_cb callback, void *user_data) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + if (callback == NULL) { + LOGE("NULL pointer callback"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + handle->user_cb[_STREAMRECORDER_EVENT_TYPE_ERROR] = callback; + handle->user_data[_STREAMRECORDER_EVENT_TYPE_ERROR] = user_data; + + return STREAMRECORDER_ERROR_NONE; +} + + +int streamrecorder_unset_error_cb(streamrecorder_h recorder) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + handle->user_cb[_STREAMRECORDER_EVENT_TYPE_ERROR] = NULL; + handle->user_data[_STREAMRECORDER_EVENT_TYPE_ERROR] = NULL; + + return STREAMRECORDER_ERROR_NONE; +} + + +int streamrecorder_set_recording_status_cb(streamrecorder_h recorder, streamrecorder_recording_status_cb callback, void *user_data) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + if (callback == NULL) { + LOGE("NULL pointer callback"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + handle->user_cb[_STREAMRECORDER_EVENT_TYPE_RECORDING_STATUS] = callback; + handle->user_data[_STREAMRECORDER_EVENT_TYPE_RECORDING_STATUS] = user_data; + + return STREAMRECORDER_ERROR_NONE; +} + + +int streamrecorder_unset_recording_status_cb(streamrecorder_h recorder) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + handle->user_cb[_STREAMRECORDER_EVENT_TYPE_RECORDING_STATUS] = NULL; + handle->user_data[_STREAMRECORDER_EVENT_TYPE_RECORDING_STATUS] = NULL; + + return STREAMRECORDER_ERROR_NONE; +} + + +int streamrecorder_set_recording_limit_reached_cb(streamrecorder_h recorder, streamrecorder_recording_limit_reached_cb callback, void *user_data) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + if (callback == NULL) { + LOGE("NULL pointer callback"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + handle->user_cb[_STREAMRECORDER_EVENT_TYPE_RECORDING_LIMITED] = callback; + handle->user_data[_STREAMRECORDER_EVENT_TYPE_RECORDING_LIMITED] = user_data; + + return STREAMRECORDER_ERROR_NONE; +} + + +int streamrecorder_unset_recording_limit_reached_cb(streamrecorder_h recorder) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + handle->user_cb[_STREAMRECORDER_EVENT_TYPE_RECORDING_LIMITED] = NULL; + handle->user_data[_STREAMRECORDER_EVENT_TYPE_RECORDING_LIMITED] = NULL; + + return STREAMRECORDER_ERROR_NONE; +} + + +int streamrecorder_foreach_supported_file_format(streamrecorder_h recorder, streamrecorder_supported_file_format_cb foreach_cb, void *user_data) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_foreach_supported_file_format(recorder, foreach_cb, user_data); + return ret; + +} + + +int streamrecorder_set_recording_limit(streamrecorder_h recorder, streamrecorder_recording_limit_type_e type, int limit) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + if (type == STREAMRECORDER_RECORDING_LIMIT_TYPE_TIME) + ret = _streamrecorder_set_size_limit(recorder, limit); + else + ret = _streamrecorder_set_time_limit(recorder, limit); + return ret; +} + +int streamrecorder_get_recording_limit(streamrecorder_h recorder, streamrecorder_recording_limit_type_e type, int *limit) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + if (type == STREAMRECORDER_RECORDING_LIMIT_TYPE_TIME) + ret = _streamrecorder_get_size_limit(recorder, limit); + else + ret = _streamrecorder_get_time_limit(recorder, limit); + return ret; +} + +int streamrecorder_set_audio_encoder(streamrecorder_h recorder, streamrecorder_audio_codec_e codec) +{ + + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_set_audio_encoder(recorder, codec); + return ret; + +} + + +int streamrecorder_get_audio_encoder(streamrecorder_h recorder, streamrecorder_audio_codec_e *codec) +{ + + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_get_audio_encoder(recorder, codec); + return ret; + +} + + +int streamrecorder_set_video_encoder(streamrecorder_h recorder, streamrecorder_video_codec_e codec) +{ + + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_set_video_encoder(recorder, codec); + return ret; + +} + + +int streamrecorder_get_video_encoder(streamrecorder_h recorder, streamrecorder_video_codec_e *codec) +{ + + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_get_video_encoder(recorder, codec); + return ret; + +} + + +int streamrecorder_set_audio_samplerate(streamrecorder_h recorder, int samplerate) +{ + + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_set_audio_samplerate(recorder, samplerate); + return ret; + +} + + +int streamrecorder_set_audio_encoder_bitrate(streamrecorder_h recorder, int bitrate) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_set_audio_encoder_bitrate(recorder, bitrate); + return ret; + +} + +int streamrecorder_set_video_encoder_bitrate(streamrecorder_h recorder, int bitrate) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_set_video_encoder_bitrate(recorder, bitrate); + return ret; +} + +int streamrecorder_get_audio_samplerate(streamrecorder_h recorder, int *samplerate) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_get_audio_samplerate(recorder, samplerate); + return ret; +} + +int streamrecorder_get_audio_encoder_bitrate(streamrecorder_h recorder, int *bitrate) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_get_audio_encoder_bitrate(recorder, bitrate); + return ret; +} + + +int streamrecorder_get_video_encoder_bitrate(streamrecorder_h recorder, int *bitrate) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_get_video_encoder_bitrate(recorder, bitrate); + return ret; +} + + +int streamrecorder_foreach_supported_audio_encoder(streamrecorder_h recorder, streamrecorder_supported_audio_encoder_cb foreach_cb, void *user_data) +{ + + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_foreach_supported_audio_encoder(recorder, foreach_cb, user_data); + return ret; + +} + + +int streamrecorder_foreach_supported_video_encoder(streamrecorder_h recorder, streamrecorder_supported_video_encoder_cb foreach_cb, void *user_data) +{ + + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_foreach_supported_video_encoder(recorder, foreach_cb, user_data); + return ret; + +} + + +int streamrecorder_set_audio_channel(streamrecorder_h recorder, int channel_count) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_set_audio_channel(recorder, channel_count); + return ret; +} + + +int streamrecorder_get_audio_channel(streamrecorder_h recorder, int *channel_count) +{ + int ret = STREAMRECORDER_ERROR_NONE; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = _streamrecorder_get_audio_channel(recorder, channel_count); + return ret; + +} + +static int __mm_streamrecorder_msg_cb(int message, void *param, void *user_data) +{ + streamrecorder_s * handle = (streamrecorder_s *)user_data; + MMMessageParamType *m = (MMMessageParamType *)param; + streamrecorder_notify_e notification = STREAMRECORDER_NOTIFY_NONE; + streamrecorder_state_e previous_state; + streamrecorder_recording_limit_type_e type; + int streamrecorder_error = 0; + switch (message) { + case MM_MESSAGE_READY_TO_RESUME: + LOGW("not supported message"); + break; + case MM_MESSAGE_STREAMRECORDER_STATE_CHANGED: + previous_state = handle->state; + notification = STREAMRECORDER_NOTIFY_STATE_CHANGED; + if (previous_state != handle->state && handle->user_cb[_STREAMRECORDER_EVENT_TYPE_NOTIFY]) + ((streamrecorder_notify_cb)handle->user_cb[_STREAMRECORDER_EVENT_TYPE_NOTIFY])(previous_state, handle->state, notification, handle->user_data[_STREAMRECORDER_EVENT_TYPE_NOTIFY]); + + break; + case MM_MESSAGE_STREAMRECORDER_MAX_SIZE: + case MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE: + case MM_MESSAGE_STREAMRECORDER_TIME_LIMIT: + if (MM_MESSAGE_STREAMRECORDER_MAX_SIZE == message) { + type = STREAMRECORDER_RECORDING_LIMIT_TYPE_SIZE; + } else { + type = STREAMRECORDER_RECORDING_LIMIT_TYPE_TIME; + } + if (handle->user_cb[_STREAMRECORDER_EVENT_TYPE_RECORDING_LIMITED]) { + ((streamrecorder_recording_limit_reached_cb)handle->user_cb[_STREAMRECORDER_EVENT_TYPE_RECORDING_LIMITED])(type, handle->user_data[_STREAMRECORDER_EVENT_TYPE_RECORDING_LIMITED]); + } + break; + case MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS: + if (handle->user_cb[_STREAMRECORDER_EVENT_TYPE_RECORDING_STATUS]) { + ((streamrecorder_recording_status_cb)handle->user_cb[_STREAMRECORDER_EVENT_TYPE_RECORDING_STATUS])(m->recording_status.elapsed, m->recording_status.filesize, handle->user_data[_STREAMRECORDER_EVENT_TYPE_RECORDING_STATUS]); + } + break; + + case MM_MESSAGE_STREAMRECORDER_VIDEO_CAPTURED: + { + MMStreamRecordingReport *report = (MMStreamRecordingReport *)m->data; + if (report != NULL && report->recording_filename) { + free(report->recording_filename); + report->recording_filename = NULL; + } + if (report) { + free(report); + report = NULL; + } + } break; + case MM_MESSAGE_STREAMRECORDER_CONSUME_COMPLETE: + { + void *consume = (m->consumed_mediabuffer).consumed_buffer; + if (handle->user_cb[_STREAMRECORDER_EVENT_TYPE_CONSUME_COMPLETE]) { + ((streamrecorder_consume_completed_cb)handle->user_cb[_STREAMRECORDER_EVENT_TYPE_CONSUME_COMPLETE])(consume, handle->user_data[_STREAMRECORDER_EVENT_TYPE_CONSUME_COMPLETE]); + } + } break; + case MM_MESSAGE_STREAMRECORDER_ERROR: + switch (m->code) { + case MM_ERROR_STREAMRECORDER_GST_CORE: + case MM_ERROR_STREAMRECORDER_GST_LIBRARY: + case MM_ERROR_STREAMRECORDER_GST_RESOURCE: + case MM_ERROR_STREAMRECORDER_GST_STREAM: + case MM_ERROR_STREAMRECORDER_GST_NEGOTIATION: + case MM_ERROR_STREAMRECORDER_GST_FLOW_ERROR: + case MM_ERROR_STREAMRECORDER_ENCODER: + case MM_ERROR_STREAMRECORDER_ENCODER_BUFFER: + case MM_ERROR_STREAMRECORDER_ENCODER_WORKING: + case MM_ERROR_STREAMRECORDER_INTERNAL: + case MM_ERROR_FILE_NOT_FOUND: + case MM_ERROR_FILE_READ: + streamrecorder_error = STREAMRECORDER_ERROR_INVALID_OPERATION; + break; + case MM_ERROR_OUT_OF_STORAGE: + streamrecorder_error = STREAMRECORDER_ERROR_OUT_OF_STORAGE; + break; + default: + streamrecorder_error = STREAMRECORDER_ERROR_INVALID_OPERATION; + break; + } + + if (streamrecorder_error != 0 && handle->user_cb[_STREAMRECORDER_EVENT_TYPE_ERROR]) { + ((streamrecorder_error_cb)handle->user_cb[_STREAMRECORDER_EVENT_TYPE_ERROR])(streamrecorder_error, handle->state, handle->user_data[_STREAMRECORDER_EVENT_TYPE_ERROR]); + } + break; + default: + break; + } + return 1; +} + diff --git a/src/streamrecorder_private.c b/src/streamrecorder_private.c new file mode 100644 index 0000000..4d4d126 --- /dev/null +++ b/src/streamrecorder_private.c @@ -0,0 +1,1038 @@ +/* +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define LOWSET_DECIBEL -300.0 + +int __convert_streamrecorder_error_code(const char *func, int code) +{ + int ret = STREAMRECORDER_ERROR_INVALID_OPERATION; + const char *errorstr = NULL; + + switch (code) { + case STREAMRECORDER_ERROR_INVALID_PARAMETER: + ret = STREAMRECORDER_ERROR_INVALID_PARAMETER; + errorstr = "INVALID_PARAMETER"; + break; + case MM_ERROR_NONE: + ret = STREAMRECORDER_ERROR_NONE; + errorstr = "ERROR_NONE"; + break; + case MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT: + case MM_ERROR_COMMON_INVALID_ATTRTYPE: + ret = STREAMRECORDER_ERROR_INVALID_PARAMETER; + errorstr = "INVALID_PARAMETER"; + break; + case MM_ERROR_COMMON_INVALID_PERMISSION: + ret = STREAMRECORDER_ERROR_PERMISSION_DENIED; + errorstr = "ERROR_PERMISSION_DENIED"; + break; + case MM_ERROR_STREAMRECORDER_NOT_INITIALIZED: + ret = STREAMRECORDER_ERROR_INVALID_STATE; + errorstr = "INVALID_STATE"; + break; + case MM_ERROR_STREAMRECORDER_GST_CORE: + case MM_ERROR_STREAMRECORDER_GST_LIBRARY: + case MM_ERROR_STREAMRECORDER_GST_RESOURCE: + case MM_ERROR_STREAMRECORDER_GST_STREAM: + case MM_ERROR_STREAMRECORDER_GST_STATECHANGE: + case MM_ERROR_STREAMRECORDER_GST_NEGOTIATION: + case MM_ERROR_STREAMRECORDER_GST_LINK: + case MM_ERROR_STREAMRECORDER_GST_FLOW_ERROR: + case MM_ERROR_STREAMRECORDER_ENCODER: + case MM_ERROR_STREAMRECORDER_ENCODER_BUFFER: + case MM_ERROR_STREAMRECORDER_ENCODER_WRONG_TYPE: + case MM_ERROR_STREAMRECORDER_ENCODER_WORKING: + case MM_ERROR_STREAMRECORDER_RESPONSE_TIMEOUT: + case MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING: + ret = STREAMRECORDER_ERROR_INVALID_OPERATION; + errorstr = "INVALID_OPERATION"; + break; + case MM_ERROR_STREAMRECORDER_RESOURCE_CREATION: + case MM_ERROR_COMMON_OUT_OF_MEMORY: + ret = STREAMRECORDER_ERROR_OUT_OF_MEMORY; + errorstr = "OUT_OF_MEMORY"; + break; + case MM_ERROR_OUT_OF_STORAGE: + ret = STREAMRECORDER_ERROR_OUT_OF_STORAGE; + errorstr = "OUT_OF_STORAGE"; + break; + case MM_ERROR_COMMON_OUT_OF_ARRAY: + case MM_ERROR_COMMON_OUT_OF_RANGE: + case MM_ERROR_COMMON_ATTR_NOT_EXIST: + ret = STREAMRECORDER_ERROR_NOT_SUPPORTED; + errorstr = "NOT_SUPPORTED"; + break; + default: + ret = STREAMRECORDER_ERROR_INVALID_OPERATION; + errorstr = "INVALID_OPERATION"; + break; + } + + + LOGE("[%s] %s(0x%08x) : core frameworks error code(0x%08x)", func, errorstr, ret, code); + + return ret; +} + +static streamrecorder_state_e __streamrecorder_state_convert(void *mm_state) +{ + streamrecorder_state_e state = STREAMRECORDER_STATE_NONE; + MMStreamRecorderStateType srstate = (MMStreamRecorderStateType)mm_state; + + switch (srstate) { + case MM_STREAMRECORDER_STATE_NONE: + state = STREAMRECORDER_STATE_NONE; + break; + case MM_STREAMRECORDER_STATE_CREATED: + state = STREAMRECORDER_STATE_CREATED; + break; + case MM_STREAMRECORDER_STATE_PREPARED: + state = STREAMRECORDER_STATE_PREPARED; + break; + case MM_STREAMRECORDER_STATE_RECORDING: + state = STREAMRECORDER_STATE_RECORDING; + break; + case MM_STREAMRECORDER_STATE_PAUSED: + state = STREAMRECORDER_STATE_PAUSED; + break; + default: + state = STREAMRECORDER_STATE_NONE; + break; + } + + return state; +} + +static int _streamrecorder_check_and_set_attribute(streamrecorder_h recorder, const char *attribute_name, int set_value) +{ + int ret = MM_ERROR_NONE; + + MMStreamRecorderStateType mmstate; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + mm_streamrecorder_get_state(handle->mm_handle, &mmstate); + if (mmstate >= MM_STREAMRECORDER_STATE_RECORDING) { + LOGE("invalid state %d", mmstate); + return STREAMRECORDER_ERROR_INVALID_STATE; + } + + ret = mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + attribute_name, set_value, + NULL); + + if (ret != MM_ERROR_NONE) { + LOGE("set [%s] failed 0x%x", attribute_name, ret); + } + + + + return __convert_streamrecorder_error_code(attribute_name, ret); +} + + +int _streamrecorder_set_videosource_buffer(streamrecorder_h recorder) +{ + int ret = STREAMRECORDER_ERROR_NONE; + if (recorder == NULL) + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + MMSTR_RECORDER_MODE, MM_STREAMRECORDER_MODE_MEDIABUFFER, + NULL); + + mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + MMSTR_VIDEO_ENABLE, true, + NULL); + + + return ret; +} + +int _streamrecorder_set_audiosource_buffer(streamrecorder_h recorder) +{ + int ret = STREAMRECORDER_ERROR_NONE; + if (recorder == NULL) + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + + streamrecorder_s *handle; + handle = (streamrecorder_s *) recorder; + mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + MMSTR_RECORDER_MODE, MM_STREAMRECORDER_MODE_MEDIABUFFER, + NULL); + + mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + MMSTR_AUDIO_ENABLE, true, + NULL); + + return ret; +} + +int _streamrecorder_get_state(streamrecorder_h recorder, streamrecorder_state_e *state) +{ + int ret = STREAMRECORDER_ERROR_NONE; + MMStreamRecorderStateType srstate; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + if (state == NULL) { + LOGE("NULL pointer state"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + + ret = mm_streamrecorder_get_state(handle->mm_handle, &srstate); + if (ret != MM_ERROR_NONE) { + return __convert_streamrecorder_error_code(__func__, ret); + } + *state = __streamrecorder_state_convert((void *)srstate); + + return STREAMRECORDER_ERROR_NONE; +} + +int _streamrecorder_destroy(streamrecorder_h recorder) +{ + streamrecorder_s *handle = NULL; + int ret = MM_ERROR_NONE; + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + handle = (streamrecorder_s *)recorder; + + ret = mm_streamrecorder_destroy(handle->mm_handle); + + if (ret == MM_ERROR_NONE) { + free(handle); + } + + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_prepare(streamrecorder_h recorder) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_realize(handle->mm_handle); + if (ret != MM_ERROR_NONE) { + LOGE("prepare fail"); + return __convert_streamrecorder_error_code(__func__, ret); + } + + return STREAMRECORDER_ERROR_NONE; +} + +int _streamrecorder_unprepare(streamrecorder_h recorder) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_unrealize(handle->mm_handle); + if (ret != MM_ERROR_NONE) { + LOGE("stramrecorder_unrealize fail"); + } + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_start(streamrecorder_h recorder) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + return __convert_streamrecorder_error_code(__func__, mm_streamrecorder_record(handle->mm_handle)); +} + +int _streamrecorder_pause(streamrecorder_h recorder) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + return __convert_streamrecorder_error_code(__func__, mm_streamrecorder_pause(handle->mm_handle)); +} + +int _streamrecorder_commit(streamrecorder_h recorder) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + return __convert_streamrecorder_error_code(__func__, mm_streamrecorder_commit(handle->mm_handle)); +} + +int _streamrecorder_cancel(streamrecorder_h recorder) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + return __convert_streamrecorder_error_code(__func__, mm_streamrecorder_cancel(handle->mm_handle)); +} + +int _streamrecorder_set_video_framerate(streamrecorder_h recorder , int framerate) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + ret = mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + MMSTR_VIDEO_FRAMERATE, framerate, + NULL); + + return __convert_streamrecorder_error_code(__func__, ret); + +} + +int _streamrecorder_get_video_framerate(streamrecorder_h recorder, int *framerate) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_VIDEO_FRAMERATE, framerate, + NULL); + + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_set_video_source_format(streamrecorder_h recorder , int format) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + ret = mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + MMSTR_VIDEO_SOURCE_FORMAT, format, + NULL); + + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_get_video_source_format(streamrecorder_h recorder, int *format) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_VIDEO_SOURCE_FORMAT, format, + NULL); + + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_set_video_resolution(streamrecorder_h recorder, int width, int height) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + streamrecorder_state_e state; + + if (handle == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + streamrecorder_get_state(recorder, &state); + if (state > STREAMRECORDER_STATE_CREATED) { + LOGE("STREAMRECORDER_ERROR_INVALID_STATE (state:%d)", state); + return STREAMRECORDER_ERROR_INVALID_STATE; + } + + + ret = mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + MMSTR_VIDEO_RESOLUTION_WIDTH, width, + MMSTR_VIDEO_RESOLUTION_HEIGHT, height, + NULL); + + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_get_video_resolution(streamrecorder_h recorder, int *width, int *height) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (!handle) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + + if (!width || !height) { + LOGE("NULL pointer width = [%p], height = [%p]", width, height); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_VIDEO_RESOLUTION_WIDTH , width, + MMSTR_VIDEO_RESOLUTION_HEIGHT , height, + NULL); + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_foreach_supported_video_resolution(streamrecorder_h recorder, streamrecorder_supported_video_resolution_cb foreach_cb, void *user_data) +{ + int i = 0; + int ret = MM_ERROR_NONE; + streamrecorder_s * handle = (streamrecorder_s *)recorder; + + if (!handle) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + + if (!foreach_cb) { + LOGE("NULL pointer callback"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + MMStreamRecorderAttrsInfo video_width; + MMStreamRecorderAttrsInfo video_height; + ret = mm_streamrecorder_get_attribute_info(handle->mm_handle, MMSTR_VIDEO_RESOLUTION_WIDTH, &video_width); + ret |= mm_streamrecorder_get_attribute_info(handle->mm_handle, MMSTR_VIDEO_RESOLUTION_HEIGHT, &video_height); + + if (ret != MM_ERROR_NONE) { + return __convert_streamrecorder_error_code(__func__, ret); + } + for (i = 0 ; i < video_width.int_array.count ; i++) { + if (!foreach_cb(video_width.int_array.array[i], video_height.int_array.array[i], user_data)) { + break; + } + } + + return STREAMRECORDER_ERROR_NONE; +} + + +int _streamrecorder_set_filename(streamrecorder_h recorder, const char *filename) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + if (filename == NULL) { + LOGE("filename is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + MMStreamRecorderStateType mmstate = MM_STREAMRECORDER_STATE_NONE; + mm_streamrecorder_get_state(handle->mm_handle, &mmstate); + if (mmstate >= MM_STREAMRECORDER_STATE_RECORDING) { + LOGE("invalid state %d", mmstate); + return STREAMRECORDER_ERROR_INVALID_STATE; + } + ret = mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + MMSTR_FILENAME, filename, strlen(filename), + NULL); + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_get_filename(streamrecorder_h recorder, char **filename) +{ + int ret = MM_ERROR_NONE; + char *record_filename = NULL; + int record_filename_size; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + if (filename == NULL) { + LOGE("filename is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_FILENAME, &record_filename, &record_filename_size, + NULL); + if (ret == MM_ERROR_NONE && record_filename) { + *filename = strdup(record_filename); + } else { + LOGE("internal return (0x%08x), get filename p:%p", ret, record_filename); + *filename = NULL; + } + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_set_file_format(streamrecorder_h recorder, streamrecorder_file_format_e format) +{ + int format_table[5] = {MM_FILE_FORMAT_3GP, /* STREAMRECORDER_FILE_FORMAT_3GP */ + MM_FILE_FORMAT_MP4, /* STREAMRECORDER_FILE_FORMAT_MP4 */ + MM_FILE_FORMAT_AMR, /* STREAMRECORDER_FILE_FORMAT_AMR */ + MM_FILE_FORMAT_AAC, /* STREAMRECORDER_FILE_FORMAT_ADTS */ + MM_FILE_FORMAT_WAV, /* STREAMRECORDER_FILE_FORMAT_WAV */ + }; + + if (format < STREAMRECORDER_FILE_FORMAT_3GP || format > STREAMRECORDER_FILE_FORMAT_WAV) { + LOGE("invalid format %d", format); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + return _streamrecorder_check_and_set_attribute(recorder, MMSTR_FILE_FORMAT, format_table[format]); + +} + +int _streamrecorder_get_file_format(streamrecorder_h recorder, streamrecorder_file_format_e *format) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + int mm_format; + + if (recorder == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + if (format == NULL) { + LOGE("format is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_FILE_FORMAT, &mm_format, + NULL); + if (ret == MM_ERROR_NONE) { + switch (mm_format) { + case MM_FILE_FORMAT_3GP: + *format = STREAMRECORDER_FILE_FORMAT_3GP; + break; + case MM_FILE_FORMAT_MP4: + *format = STREAMRECORDER_FILE_FORMAT_MP4; + break; + case MM_FILE_FORMAT_AMR: + *format = STREAMRECORDER_FILE_FORMAT_AMR; + break; + case MM_FILE_FORMAT_AAC: + *format = STREAMRECORDER_FILE_FORMAT_ADTS; + break; + case MM_FILE_FORMAT_WAV: + *format = STREAMRECORDER_FILE_FORMAT_WAV; + break; + default: + ret = MM_ERROR_STREAMRECORDER_INTERNAL; + break; + } + } + + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_foreach_supported_file_format(streamrecorder_h recorder, streamrecorder_supported_file_format_cb foreach_cb, void *user_data) +{ + int i = 0; + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + int format; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + if (foreach_cb == NULL) { + LOGE("NULL pointer foreach_cb"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + MMStreamRecorderAttrsInfo info; + ret = mm_streamrecorder_get_attribute_info(handle->mm_handle, MMSTR_FILE_FORMAT, &info); + if (ret != MM_ERROR_NONE) { + LOGE("mm_streamrecorder_get_attribute_info failed 0x%x", ret); + return __convert_streamrecorder_error_code(__func__, ret); + } + + for (i = 0 ; i < info.int_array.count ; i++) { + switch (info.int_array.array[i]) { + case MM_FILE_FORMAT_3GP: + format = STREAMRECORDER_FILE_FORMAT_3GP; + break; + case MM_FILE_FORMAT_MP4: + format = STREAMRECORDER_FILE_FORMAT_MP4; + break; + case MM_FILE_FORMAT_AMR: + format = STREAMRECORDER_FILE_FORMAT_AMR; + break; + case MM_FILE_FORMAT_AAC: + format = STREAMRECORDER_FILE_FORMAT_ADTS; + break; + case MM_FILE_FORMAT_WAV: + format = STREAMRECORDER_FILE_FORMAT_WAV; + break; + default: + format = -1; + break; + } + + if (format != -1 && !foreach_cb(format, user_data)) { + break; + } + } + + return STREAMRECORDER_ERROR_NONE; +} + +int _streamrecorder_set_size_limit(streamrecorder_h recorder, int kbyte) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + MMSTR_TARGET_MAX_SIZE, kbyte, + NULL); + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_set_time_limit(streamrecorder_h recorder, int second) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("NULL pointer handle"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + MMSTR_TARGET_TIME_LIMIT, second, + NULL); + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_set_audio_encoder(streamrecorder_h recorder, streamrecorder_audio_codec_e codec) +{ + streamrecorder_s *handle = (streamrecorder_s *)recorder; + int audio_table[3] = { MM_AUDIO_CODEC_AMR, /* STREAMRECORDER_AUDIO_CODEC_AMR */ + MM_AUDIO_CODEC_AAC, /* STREAMRECORDER_AUDIO_CODEC_AAC */ + MM_AUDIO_CODEC_WAVE /* STREAMRECORDER_AUDIO_CODEC_PCM */ + }; + + if (recorder == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + if ((codec < STREAMRECORDER_AUDIO_CODEC_AMR || codec > STREAMRECORDER_AUDIO_CODEC_PCM)) { + LOGE("invalid parameter : codec %d", codec); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + return _streamrecorder_check_and_set_attribute(recorder, MMSTR_AUDIO_ENCODER, audio_table[codec]); +} + +int _streamrecorder_get_audio_encoder(streamrecorder_h recorder, streamrecorder_audio_codec_e *codec) +{ + int ret = MM_ERROR_NONE; + int mm_codec = 0; + int audio_enable = 0; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + if (codec == NULL) { + LOGE("codec is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_AUDIO_ENCODER, &mm_codec, + MMSTR_AUDIO_ENABLE, &audio_enable, + NULL); + + if (ret == MM_ERROR_NONE && audio_enable != 0) { + switch (mm_codec) { + case MM_AUDIO_CODEC_AMR: + *codec = STREAMRECORDER_AUDIO_CODEC_AMR; + break; + case MM_AUDIO_CODEC_AAC: + *codec = STREAMRECORDER_AUDIO_CODEC_AAC; + break; + case MM_AUDIO_CODEC_WAVE: + *codec = STREAMRECORDER_AUDIO_CODEC_PCM; + break; + default: + ret = MM_ERROR_STREAMRECORDER_INTERNAL; + break; + } + } else { + ret = MM_ERROR_STREAMRECORDER_INTERNAL; + } + + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_set_video_encoder(streamrecorder_h recorder, streamrecorder_video_codec_e codec) +{ + int ret = MM_ERROR_NONE; + int video_table[2] = {MM_VIDEO_CODEC_H263, /* STREAMRECORDER_VIDEO_CODEC_H263 */ + MM_VIDEO_CODEC_MPEG4, /* STREAMRECORDER_VIDEO_CODEC_MPEG4 */ + }; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (handle == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + + if (codec < STREAMRECORDER_VIDEO_CODEC_H263 || codec > STREAMRECORDER_VIDEO_CODEC_MPEG4) { + LOGE("invalid codec %d", codec); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + MMSTR_VIDEO_ENCODER, video_table[codec], + NULL); + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_get_video_encoder(streamrecorder_h recorder, streamrecorder_video_codec_e *codec) +{ + int ret = MM_ERROR_NONE; + int mm_codec = 0; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (handle == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + if (codec == NULL) { + LOGE("codec is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_VIDEO_ENCODER, &mm_codec, + NULL); + if (ret == MM_ERROR_NONE) { + switch (mm_codec) { + case MM_VIDEO_CODEC_H263: + *codec = STREAMRECORDER_VIDEO_CODEC_H263; + break; + case MM_VIDEO_CODEC_MPEG4: + *codec = STREAMRECORDER_VIDEO_CODEC_MPEG4; + break; + default: + ret = MM_ERROR_STREAMRECORDER_INTERNAL; + break; + } + } + + return __convert_streamrecorder_error_code(__func__, ret); +} + + +int _streamrecorder_set_audio_samplerate(streamrecorder_h recorder, int samplerate) +{ + if (samplerate < 1) { + LOGE("invalid samplerate %d", samplerate); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + return _streamrecorder_check_and_set_attribute(recorder, MMSTR_AUDIO_SAMPLERATE, samplerate); + +} + +int _streamrecorder_set_audio_encoder_bitrate(streamrecorder_h recorder, int bitrate) +{ + if (bitrate < 1) { + LOGE("invalid bitrate %d", bitrate); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + return _streamrecorder_check_and_set_attribute(recorder, MMSTR_AUDIO_BITRATE, bitrate); + +} + +int _streamrecorder_set_video_encoder_bitrate(streamrecorder_h recorder, int bitrate) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (handle == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_set_attributes(handle->mm_handle, NULL, + MMSTR_VIDEO_BITRATE, bitrate, + NULL); + + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_get_size_limit(streamrecorder_h recorder, int *kbyte) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_TARGET_MAX_SIZE, kbyte, + NULL); + + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_get_time_limit(streamrecorder_h recorder, int *second) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_TARGET_TIME_LIMIT, second, + NULL); + + return __convert_streamrecorder_error_code(__func__, ret); +} + + +int _streamrecorder_get_audio_samplerate(streamrecorder_h recorder, int *samplerate) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_AUDIO_SAMPLERATE, samplerate, + NULL); + + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_get_audio_encoder_bitrate(streamrecorder_h recorder, int *bitrate) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_AUDIO_BITRATE, bitrate, + NULL); + + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_get_video_encoder_bitrate(streamrecorder_h recorder, int *bitrate) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (handle == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_VIDEO_BITRATE, bitrate, + NULL); + return __convert_streamrecorder_error_code(__func__, ret); +} + +int _streamrecorder_foreach_supported_audio_encoder(streamrecorder_h recorder, streamrecorder_supported_audio_encoder_cb foreach_cb, void *user_data) +{ + int i = 0; + int ret = MM_ERROR_NONE; + int codec; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + if (foreach_cb == NULL) { + LOGE("foreach_cb is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + MMStreamRecorderAttrsInfo info; + ret = mm_streamrecorder_get_attribute_info(handle->mm_handle, MMSTR_AUDIO_ENCODER, &info); + if (ret != MM_ERROR_NONE) { + return __convert_streamrecorder_error_code(__func__, ret); + } + + for (i = 0 ; i < info.int_array.count ; i++) { + switch (info.int_array.array[i]) { + case MM_AUDIO_CODEC_AMR: + codec = STREAMRECORDER_AUDIO_CODEC_AMR; + break; + case MM_AUDIO_CODEC_AAC: + codec = STREAMRECORDER_AUDIO_CODEC_AAC; + break; + case MM_AUDIO_CODEC_WAVE: + codec = STREAMRECORDER_AUDIO_CODEC_PCM; + break; + default: + codec = -1; + break; + } + if (codec != -1 && !foreach_cb(codec, user_data)) { + break; + } + } + + return STREAMRECORDER_ERROR_NONE; +} + + +int _streamrecorder_foreach_supported_video_encoder(streamrecorder_h recorder, streamrecorder_supported_video_encoder_cb foreach_cb, void *user_data) +{ + int i = 0; + int ret = MM_ERROR_NONE; + int codec; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (handle == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + if (foreach_cb == NULL) { + LOGE("foreach_cb is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + MMStreamRecorderAttrsInfo info; + ret = mm_streamrecorder_get_attribute_info(handle->mm_handle, MMSTR_VIDEO_ENCODER, &info); + if (ret != MM_ERROR_NONE) { + return __convert_streamrecorder_error_code(__func__, ret); + } + + for (i = 0 ; i < info.int_array.count ; i++) { + switch (info.int_array.array[i]) { + case MM_VIDEO_CODEC_H263: + codec = STREAMRECORDER_VIDEO_CODEC_H263; + break; + case MM_VIDEO_CODEC_MPEG4: + codec = STREAMRECORDER_VIDEO_CODEC_MPEG4; + break; + default: + codec = -1; + break; + } + + if (codec != -1 && !foreach_cb(codec, user_data)) { + break; + } + } + + return STREAMRECORDER_ERROR_NONE; +} + + + +int _streamrecorder_set_audio_channel(streamrecorder_h recorder, int channel_count) +{ + if (channel_count < 1) { + LOGE("invalid channel %d", channel_count); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + return _streamrecorder_check_and_set_attribute(recorder, MMSTR_AUDIO_CHANNEL, channel_count); +} + +int _streamrecorder_get_audio_channel(streamrecorder_h recorder, int *channel_count) +{ + int ret = MM_ERROR_NONE; + streamrecorder_s *handle = (streamrecorder_s *)recorder; + + if (recorder == NULL) { + LOGE("handle is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + if (channel_count == NULL) { + LOGE("channel_count is NULL"); + return STREAMRECORDER_ERROR_INVALID_PARAMETER; + } + + ret = mm_streamrecorder_get_attributes(handle->mm_handle, NULL, + MMSTR_AUDIO_CHANNEL, channel_count, + NULL); + + return __convert_streamrecorder_error_code(__func__, ret); +} + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..5d5c0e9 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,24 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_test "${fw_name}-test") + +#INCLUDE_DIRECTORIES(../include) +#link_directories(${CMAKE_SOURCE_DIR}/../) + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_test} REQUIRED mm-streamrecorder) +FOREACH(flag ${${fw_test}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") + MESSAGE(${flag}) +ENDFOREACH() + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -pie -Wall") + +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} ${fw_name} ${${fw_test}_LDFLAGS}) + INSTALL(TARGETS ${src_name} DESTINATION bin) + +ENDFOREACH() diff --git a/test/streamrecorder_test.c b/test/streamrecorder_test.c new file mode 100644 index 0000000..480530c --- /dev/null +++ b/test/streamrecorder_test.c @@ -0,0 +1,827 @@ +/* +* recorder_testsuite +* +* Copyright (c) 2000 - 2011 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 +#include +#include +#include +#include +#include +#include +#include + +#define LOGD g_print +#define LOGE g_print +#define LOGW g_print +/*----------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS: | +-----------------------------------------------------------------------*/ +#define EXPORT_API __attribute__((__visibility__("default"))) + +#define PACKAGE "recorder_testsuite" + +GMainLoop *g_loop; +GIOChannel *stdin_channel; +int resolution_set; +int g_current_state; +int src_w, src_h; +GstCaps *filtercaps; +int recorder_state; +static GTimer *timer = NULL; +void *display; + +/*----------------------------------------------------------------------- +| GLOBAL CONSTANT DEFINITIONS: | +-----------------------------------------------------------------------*/ + + +/*----------------------------------------------------------------------- +| IMPORTED VARIABLE DECLARATIONS: | +-----------------------------------------------------------------------*/ + + +/*----------------------------------------------------------------------- +| IMPORTED FUNCTION DECLARATIONS: | +-----------------------------------------------------------------------*/ + + +/*----------------------------------------------------------------------- +| LOCAL #defines: | +-----------------------------------------------------------------------*/ + + +#define DISPLAY_W_320 320 /*for direct FB*/ +#define DISPLAY_H_240 240 /*for direct FB*/ + + +#define SRC_VIDEO_FRAME_RATE_15 15 /* video input frame rate */ +#define SRC_VIDEO_FRAME_RATE_30 30 /* video input frame rate */ +#define IMAGE_ENC_QUALITY 85 /* quality of jpeg */ + +#define MAX_FILE_SIZE_FOR_MMS (250 * 1024) + +#define EXT_JPEG "jpg" +#define EXT_MP4 "mp4" +#define EXT_3GP "3gp" +#define EXT_AMR "amr" +#define EXT_MKV "mkv" + +#define TARGET_FILENAME_PATH "/opt/usr/media/" +#define IMAGE_CAPTURE_EXIF_PATH TARGET_FILENAME_PATH"exif.raw" +#define TARGET_FILENAME_VIDEO TARGET_FILENAME_PATH"test.mp4" +#define TARGET_FILENAME_AUDIO TARGET_FILENAME_PATH"test_rec_audio.m4a" +#define CAPTURE_FILENAME_LEN 256 + +#define AUDIO_SOURCE_SAMPLERATE_AAC 44100 +#define AUDIO_SOURCE_SAMPLERATE_AMR 8000 +#define AUDIO_SOURCE_FORMAT MM_STREAMRECORDER_AUDIO_FORMAT_PCM_S16_LE +#define AUDIO_SOURCE_CHANNEL_AAC 2 +#define AUDIO_SOURCE_CHANNEL_AMR 1 +#define VIDEO_ENCODE_BITRATE 40000000 /* bps */ + +#define CHECK_MM_ERROR(expr) \ +do {\ + int ret = 0; \ + ret = expr; \ + if (ret != 0) {\ + printf("[%s:%d] error code : %x \n", __func__, __LINE__, ret); \ + return; \ + } \ +} while (0) + + +#ifndef SAFE_FREE +#define SAFE_FREE(x) if (x) { g_free(x); x = NULL; } +#endif + + +GTimeVal previous; +GTimeVal current; +GTimeVal result; +/*temp*/ + +/** +* Enumerations for command +*/ +#define SENSOR_WHITEBALANCE_NUM 10 +#define SENSOR_COLOR_TONE_NUM 31 +#define SENSOR_FLIP_NUM 3 +#define SENSOR_PROGRAM_MODE_NUM 15 +#define SENSOR_FOCUS_NUM 6 +#define SENSOR_INPUT_ROTATION 4 +#define SENSOR_AF_SCAN_NUM 4 +#define SENSOR_ISO_NUM 8 +#define SENSOR_EXPOSURE_NUM 9 +#define SENSOR_IMAGE_FORMAT 9 + + +/*----------------------------------------------------------------------- +| LOCAL CONSTANT DEFINITIONS: | +-----------------------------------------------------------------------*/ +enum { + MODE_LIVE_BUFFER_I420_VIDEO , /*video capturing mode from live buffer I420 using software encoder*/ + MODE_LIVE_BUFFER_NV12_VIDEO_SW , /*video capturing mode from live buffer NV12 using software encoder */ + MODE_LIVE_BUFFER_NV12_VIDEO_HW , /*video capturing mode from live buffer NV12 using hardware encoder*/ + MODE_NUM, +}; + +enum { + MENU_STATE_MAIN, + MENU_STATE_NUM, +}; + +/*----------------------------------------------------------------------- +| LOCAL DATA TYPE DEFINITIONS: | +-----------------------------------------------------------------------*/ +typedef struct _mstreamrecorder_handle { + streamrecorder_h recorder; + int mode; /*video/audio(recording) mode */ + int menu_state; + int fps; + bool isMute; + unsigned long long elapsed_time; +} mstreamrecorder_handle_t; + + +/*--------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS: | +---------------------------------------------------------------------------*/ +static mstreamrecorder_handle_t *hmstreamrecorder ; + +/*--------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------*/ +static void print_menu(); +static gboolean cmd_input(GIOChannel *channel); +static gboolean init(int type); +static gboolean mode_change(); + + +void _recording_status_cb(unsigned long long elapsed_time, unsigned long long file_size, void *user_data) +{ + printf("elapsed time :%d, file_size :%d\n", elapsed_time, file_size); +} + +void _recording_limit_reached_cb(streamrecorder_recording_limit_type_e type, void *user_data) +{ + g_print("limited!! %d\n", type); + int *ischeck = (int *)user_data; + *ischeck = 1; +} +static inline void flush_stdin() +{ + int ch; + while ((ch = getchar()) != EOF && ch != '\n'); +} + + +static void print_menu() +{ + switch (hmstreamrecorder->menu_state) { + case MENU_STATE_MAIN: + if (hmstreamrecorder->mode == MODE_LIVE_BUFFER_I420_VIDEO || hmstreamrecorder->mode == MODE_LIVE_BUFFER_NV12_VIDEO_SW) { + g_print("\n\t=======================================\n"); + if (recorder_state <= STREAMRECORDER_STATE_NONE) { + g_print("\t '1' Start Recording\n"); + g_print("\t 'b' back\n"); + } else if (recorder_state == STREAMRECORDER_STATE_RECORDING) { + g_print("\t 'p' Pause Recording\n"); + g_print("\t 'c' Cancel\n"); + g_print("\t 's' Save\n"); + } else if (recorder_state == STREAMRECORDER_STATE_PAUSED) { + g_print("\t 'r' Resume Recording\n"); + g_print("\t 's' Save\n"); + } + } + break; + + default: + LOGE("unknow menu state !!\n"); + break; + } + return; +} + +media_packet_h streamrecorder_make_media_packet(int video, void *data, int size) +{ + guint8 *pkt_data; + media_packet_h out_pkt; + media_format_h output_fmt; + if (media_format_create(&output_fmt)) { + g_print("media_format_create failed\n"); + return NULL; + } + int i; + int bo_num = 0; + + if (video) { + if (hmstreamrecorder->mode == MODE_LIVE_BUFFER_NV12_VIDEO_SW) { + media_format_set_video_mime(output_fmt, MEDIA_FORMAT_NV12); + } else if (hmstreamrecorder->mode == MODE_LIVE_BUFFER_I420_VIDEO) { + media_format_set_video_mime(output_fmt, MEDIA_FORMAT_I420); + } + media_format_set_video_width(output_fmt, 1280); + media_format_set_video_height(output_fmt, 720); + if (media_format_set_video_frame_rate(output_fmt, 30)) { + g_print("media_format_set_video_frame_rate failed\n"); + return NULL; + } + } else { + media_format_set_audio_mime(output_fmt, MEDIA_FORMAT_PCM); + media_format_set_audio_channel(output_fmt, 1); + media_format_set_audio_samplerate(output_fmt, 44100); + /*media_format_set_audio_bit(core->output_fmt, info->bit);*/ + } + if (media_packet_create(output_fmt, NULL, NULL, &out_pkt)) { + g_print("create video media_packet failed\n"); + return NULL; + } + if (media_packet_alloc(out_pkt)) { + g_print("video media_packet alloc failed\n"); + return NULL; + } + media_packet_get_buffer_data_ptr(out_pkt, (void **)&pkt_data); + memcpy((char *)pkt_data, data, size); + if (media_packet_set_buffer_size(out_pkt, (uint64_t)(size))) { + g_print("video set_buffer_size failed\n"); + return NULL; + } + + return out_pkt; +} + +void feed_video_es(GstElement *element, GstBuffer *buffer, GstPad *pad, gpointer data) +{ + guint n; + GstMemory *mem; + GstMapInfo map = GST_MAP_INFO_INIT; + media_packet_h out_pkt = NULL; + static GstBuffer *buf = NULL; + MMVideoBuffer *m_buf; + + MMHandleType handle = (MMHandleType)data; + + gst_buffer_ref(buffer); + + n = gst_buffer_n_memory(buffer); + + mem = gst_buffer_peek_memory(buffer, n-1); + + gst_memory_map(mem, &map, GST_MAP_READ); + out_pkt = streamrecorder_make_media_packet(1, map.data, map.size); + gst_memory_unmap(mem, &map); + if (out_pkt) { + media_packet_set_pts(out_pkt, buffer->pts); + media_packet_set_extra(out_pkt, buffer); + streamrecorder_push_stream_buffer(hmstreamrecorder->recorder, out_pkt); + } + return; +} + +GstElement *vpipeline, *vconvert, *vsrc, *vfakesink, *vcaps; +void close_pipeline(void) +{ + if (vpipeline) + gst_object_unref(vpipeline); + if (vsrc) + gst_object_unref(vsrc); + if (vfakesink) + gst_object_unref(vfakesink); + if (vcaps) + gst_object_unref(vcaps); + if (vconvert) + gst_object_unref(vconvert); +} + + +int __feed_buffer_test(MMHandleType handle, int mode) +{ + + GstCaps *caps; + g_print("creating __feed_buffer_test pipeline\n"); + if (!handle) + return FALSE; + /* create video pipeline */ + vpipeline = gst_pipeline_new(NULL); + if (!vpipeline) { + g_print("pipeline create fail\n"); + return FALSE; + } + if (mode == MODE_LIVE_BUFFER_NV12_VIDEO_SW) { + vsrc = gst_element_factory_make("videotestsrc", NULL); + if (!vsrc) { + g_print("src element creation failed\n"); + return FALSE; + } + } else { + vsrc = gst_element_factory_make("videotestsrc", NULL); + if (!vsrc) { + g_print("src element creation failed\n"); + return FALSE; + } + } + if (mode == MODE_LIVE_BUFFER_NV12_VIDEO_SW) { + vconvert = gst_element_factory_make("videoconvert", NULL); + if (!vconvert) { + g_print("convert element creation failed\n"); + return FALSE; + } + } + vcaps = gst_element_factory_make("capsfilter", NULL); + if (!vcaps) { + g_print("capsfilter element creation failed\n"); + return FALSE; + } + if (mode == MODE_LIVE_BUFFER_I420_VIDEO) { + caps = gst_caps_new_simple("video/x-raw", + "format", G_TYPE_STRING, "I420", + "width", G_TYPE_INT, 1280, + "height", G_TYPE_INT, 720, NULL); + } else if (mode == MODE_LIVE_BUFFER_NV12_VIDEO_SW) { + caps = gst_caps_new_simple("video/x-raw", + "format", G_TYPE_STRING, "NV12", + "width", G_TYPE_INT, 1280, + "height", G_TYPE_INT, 720, + "framerate", GST_TYPE_FRACTION, 30, 1, NULL); + } + g_object_set(vcaps, "caps", caps, NULL); + gst_caps_unref(caps); + + vfakesink = gst_element_factory_make("fakesink", NULL); + if (!vfakesink) { + g_print("video fakesink creation failed\n"); + return FALSE; + } + g_object_set(GST_OBJECT(vfakesink), "signal-handoffs", TRUE, NULL); + g_signal_connect(vfakesink, "handoff", G_CALLBACK(feed_video_es), handle); + + if (mode == MODE_LIVE_BUFFER_I420_VIDEO) { + gst_bin_add_many(GST_BIN(vpipeline), vsrc, vcaps, vfakesink, NULL); + /* link elements */ + if (!gst_element_link_many(vsrc, vcaps, vfakesink, NULL)) { + GST_WARNING("Can't link elements video pipeline"); + return FALSE; + } + } else if (mode == MODE_LIVE_BUFFER_NV12_VIDEO_SW) { + gst_bin_add_many(GST_BIN(vpipeline), vsrc, vconvert, vcaps, vfakesink, NULL); + /* link elements */ + if (!gst_element_link_many(vsrc , vconvert, vcaps, vfakesink, NULL)) { + GST_WARNING("Can't link elements video pipeline"); + return FALSE; + } + } + g_print("Linking done video pipeline\n"); + +#if 0 + GstElement *a_pipeline, *asrc, *afakesink; + /* create common elements */ + a_pipeline = gst_pipeline_new(NULL); + if (v_pipeline) { + g_print("pipeline create fail\n"); + return FALSE; + } + asrc = gst_element_factory_make("audiotestsrc", NULL); + if (!asrc) { + g_print("src element creation failed\n"); + return FALSE; + } + afakesink = gst_element_factory_make("fakesink", NULL); + if (!afakesink) { + g_print("audio fakesink creation failed\n"); + return FALSE; + } + /* connect handoff */ + g_object_set(GST_OBJECT(afakesink), "signal-handoffs", TRUE, NULL); + g_signal_connect(fakesink, "handoff", G_CALLBACK(feed_audio_es), handle); + + gst_bin_add_many(GST_BIN(v_pipeline), asrc, afakesink, NULL); + + /* link elements */ + if (!gst_element_link_many(asrc, afakesink, NULL)) { + GST_WARNING("Can't link elements audio pipeline"); + return FALSE; + } + g_print("Linking done audio pipeline\n"); + gst_element_set_state(apipeline, GST_STATE_PLAYING); +#endif + gst_element_set_state(vpipeline, GST_STATE_PLAYING); + g_print("feed_task pipeline is playing\n"); + + return 0; +} + + +static void main_menu(gchar buf) +{ + int err = 0; + int current_fps = 0; + int average_fps = 0; + char *err_attr_name = NULL; + + if (hmstreamrecorder->mode == MODE_LIVE_BUFFER_I420_VIDEO || hmstreamrecorder->mode == MODE_LIVE_BUFFER_NV12_VIDEO_SW) { + if (recorder_state == STREAMRECORDER_STATE_NONE) { + switch (buf) { + case '1': /* Start Recording*/ + hmstreamrecorder->elapsed_time = 0; + err = streamrecorder_start(hmstreamrecorder->recorder); + sleep(1); + g_timer_reset(timer); + err = __feed_buffer_test(hmstreamrecorder->recorder, hmstreamrecorder->mode); + if (err != MM_ERROR_NONE) + + g_print("Rec star in live buffer 0x%x", err); + if (err == 0) + LOGE("Rec start live buffer 0x%x", err); + + recorder_state = STREAMRECORDER_STATE_RECORDING; + break; + + case 'b': /* back*/ + hmstreamrecorder->menu_state = MENU_STATE_MAIN; + mode_change(); + break; + + default: + g_print("\t Invalid input \n"); + break; + } + } else if (recorder_state == STREAMRECORDER_STATE_RECORDING || recorder_state == STREAMRECORDER_STATE_PAUSED) { + switch (buf) { + if (recorder_state == STREAMRECORDER_STATE_RECORDING) { + case 'p': /* Pause Recording*/ + g_print("*Pause!\n"); + err = streamrecorder_pause(hmstreamrecorder->recorder); + + if (err < 0) + LOGE("Rec pause streamrecorder_pause = %x", err); + + recorder_state = STREAMRECORDER_STATE_PAUSED; + break; + + } else { + case 'r': /* Resume Recording*/ + g_print("*Resume!\n"); + err = streamrecorder_start(hmstreamrecorder->recorder); + if (err < 0) + LOGE("Rec start streamrecorder_record = %x", err); + + recorder_state = STREAMRECORDER_STATE_RECORDING; + break; + } + + case 'c': /* Cancel*/ + g_print("*Cancel Recording !\n"); + + err = streamrecorder_cancel(hmstreamrecorder->recorder); + + if (err < 0) + LOGE("Cancel recording streamrecorder_cancel = %x", err); + + recorder_state = STREAMRECORDER_STATE_NONE; + break; + + case 's': /* Save*/ + g_print("*Save Recording!\n"); + g_timer_reset(timer); + + err = streamrecorder_commit(hmstreamrecorder->recorder); + + if (err < 0) + LOGE("Save recording streamrecorder_commit = %x", err); + + recorder_state = STREAMRECORDER_STATE_NONE; + break; + + default: + g_print("\t Invalid input \n"); + break; + } /*switch*/ + } else { + LOGE("Wrong streamrecorder state, check status!!"); + } + } else { + g_print("\t Invalid mode, back to upper menu \n"); + hmstreamrecorder->menu_state = MENU_STATE_MAIN; + mode_change(); + } +} + + +/** +* This function is to execute command. +* +* @param channel [in] 1st parameter +* +* @return This function returns TRUE/FALSE +* @remark +* @see +*/ +static gboolean cmd_input(GIOChannel *channel) +{ + gchar *buf = NULL; + gsize read_size; + GError *g_error = NULL; + + LOGD("ENTER"); + + g_io_channel_read_line(channel, &buf, &read_size, NULL, &g_error); + if (g_error) { + LOGD("g_io_channel_read_chars error"); + g_error_free(g_error); + g_error = NULL; + } + + if (buf) { + g_strstrip(buf); + + LOGD("Menu Status : %d", hmstreamrecorder->menu_state); + switch (hmstreamrecorder->menu_state) { + case MENU_STATE_MAIN: + main_menu(buf[0]); + break; + default: + break; + } + + g_free(buf); + buf = NULL; + + print_menu(); + } else { + LOGD("No read input"); + } + + return TRUE; +} + +static gboolean init(int type) +{ + int err; + int size; + int support_zero_copy_format = 0; + int ischeck = 0; + char *err_attr_name = NULL; + + if (!hmstreamrecorder) + return FALSE; + + if (!hmstreamrecorder->recorder) + return FALSE; + + /*================================================================================ + Video capture mode + *=================================================================================*/ + if (type == MODE_LIVE_BUFFER_I420_VIDEO || type == MODE_LIVE_BUFFER_NV12_VIDEO_SW) { + if (type == MODE_LIVE_BUFFER_I420_VIDEO) { + err = streamrecorder_set_video_source_format(hmstreamrecorder->recorder, STREAMRECORDER_VIDEO_SOURCE_FORMAT_I420); + if (err < 0) { + LOGE("Init fail. (%x)", err); + goto ERROR; + } + } else if (type == MODE_LIVE_BUFFER_NV12_VIDEO_SW) { + err = streamrecorder_set_video_source_format(hmstreamrecorder->recorder, STREAMRECORDER_VIDEO_SOURCE_FORMAT_NV12); + if (err < 0) { + LOGE("Init fail. (%x)", err); + goto ERROR; + } + } + err = streamrecorder_set_file_format(hmstreamrecorder->recorder, STREAMRECORDER_FILE_FORMAT_MP4); + if (err < 0) { + LOGE("aInit fail. (%x)", err); + goto ERROR; + } + err = streamrecorder_set_video_encoder(hmstreamrecorder->recorder, STREAMRECORDER_VIDEO_CODEC_MPEG4); + if (err < 0) { + LOGE("bInit fail. (%x)", err); + goto ERROR; + } + err = streamrecorder_set_video_resolution(hmstreamrecorder->recorder, 1280, 720); + if (err < 0) { + LOGE("dInit fail. (%x)", err); + goto ERROR; + } + err = streamrecorder_set_video_framerate(hmstreamrecorder->recorder, 30); + if (err < 0) { + LOGE("dInit fail. (%x)", err); + goto ERROR; + } + err = streamrecorder_set_filename(hmstreamrecorder->recorder, TARGET_FILENAME_VIDEO); + if (err < 0) { + LOGE("dInit fail. (%x)", err); + goto ERROR; + } + } + + streamrecorder_set_recording_status_cb(hmstreamrecorder->recorder, _recording_status_cb, NULL); + streamrecorder_set_recording_limit_reached_cb(hmstreamrecorder->recorder, _recording_limit_reached_cb, &ischeck); + + LOGD("Init DONE."); + + return TRUE; + +ERROR: + LOGE("init failed."); + return FALSE; +} + +static gboolean init_handle() +{ + hmstreamrecorder->mode = 0; /* image(capture)/video(recording) mode */ + hmstreamrecorder->menu_state = MENU_STATE_MAIN; + hmstreamrecorder->isMute = FALSE; + hmstreamrecorder->elapsed_time = 0; + hmstreamrecorder->fps = SRC_VIDEO_FRAME_RATE_15; /*SRC_VIDEO_FRAME_RATE_30;*/ + + return TRUE; +} +/** +* This function is to change streamrecorder mode. +* +* @param type [in] image(capture)/video(recording) mode +* +* @return This function returns TRUE/FALSE +* @remark +* @see other functions +*/ +static gboolean mode_change() +{ + int err = STREAMRECORDER_ERROR_NONE; + int state = STREAMRECORDER_STATE_NONE; + int name_size = 0; + int device_count = 0; + int facing_direction = 0; + char media_type = '\0'; + char *evassink_name = NULL; + bool check = FALSE; + + err = streamrecorder_get_state(hmstreamrecorder->recorder, (streamrecorder_state_e *)&state); + if (state != STREAMRECORDER_STATE_NONE) { + if ((state == STREAMRECORDER_STATE_RECORDING) || (state == STREAMRECORDER_STATE_PAUSED)) { + LOGD("streamrecorder_cancel"); + err = streamrecorder_cancel(hmstreamrecorder->recorder); + + if (err < 0) { + LOGE("exit streamrecorder_cancel = %x", err); + return FALSE; + } + } + + err = streamrecorder_get_state(hmstreamrecorder->recorder, (streamrecorder_state_e *)&state); + if (state == STREAMRECORDER_STATE_PREPARED) { + LOGD("streamrecorder_destroy"); + streamrecorder_unprepare(hmstreamrecorder->recorder); + } + + err = streamrecorder_get_state(hmstreamrecorder->recorder, (streamrecorder_state_e *)&state); + if (state == STREAMRECORDER_STATE_CREATED) { + LOGD("streamrecorder_destroy"); + streamrecorder_destroy(hmstreamrecorder->recorder); + } + } + + init_handle(); + streamrecorder_create(&hmstreamrecorder->recorder); + g_get_current_time(&previous); + g_timer_reset(timer); + while (!check) { + g_print("\n\t=======================================\n"); + g_print("\t RECORDER_TESTSUIT\n"); + g_print("\t=======================================\n"); + g_print("\t '1' i420 sw buffer - Video\n"); + g_print("\t '2' nv12 sw buffer - Video\n"); + g_print("\t 'q' Exit\n"); + g_print("\t=======================================\n"); + + g_print("\t Enter the media type:\n\t"); + + err = scanf("%c", &media_type); + if (err == EOF) { + g_print("\t!!!read input error!!!\n"); + continue; + } + + switch (media_type) { + case '1': + hmstreamrecorder->mode = MODE_LIVE_BUFFER_I420_VIDEO; + streamrecorder_enable_source_buffer(hmstreamrecorder->recorder, STREAMRECORDER_SOURCE_VIDEO); + check = TRUE; + break; + case '2': + hmstreamrecorder->mode = MODE_LIVE_BUFFER_NV12_VIDEO_SW; + streamrecorder_enable_source_buffer(hmstreamrecorder->recorder, STREAMRECORDER_SOURCE_VIDEO); + check = TRUE; + break; + case 'q': + g_print("\t Quit Streamrecorder Testsuite!!\n"); + hmstreamrecorder->mode = -1; + if (g_main_loop_is_running(g_loop)) + g_main_loop_quit(g_loop); + + return FALSE; + default: + g_print("\t Invalid media type(%d)\n", media_type); + continue; + } + } + + g_timer_reset(timer); + + if (!init(hmstreamrecorder->mode)) { + g_print("hmstreamrecorder->mode = %d\n", hmstreamrecorder->mode); + LOGE("testsuite init() failed."); + return -1; + } + + g_timer_reset(timer); + + err = streamrecorder_prepare(hmstreamrecorder->recorder); + LOGD("streamrecorder_start() : %12.6lfs", g_timer_elapsed(timer, NULL)); + + if (err != 0) { + LOGE("streamrecorder_prepare = %x", err); + return -1; + } + + g_get_current_time(¤t); + timersub(¤t, &previous, &result); + LOGD("Streamrecorder Starting Time : %ld.%lds", result.tv_sec, result.tv_usec); + + return TRUE; +} + + +/** +* This function is the example main function for recorder API. +* +* @param +* +* @return This function returns 0. +* @remark +* @see other functions +*/ +int main(int argc, char **argv) +{ + int bret; + + timer = g_timer_new(); + + gst_init(&argc, &argv); + + LOGD("gst_init() : %12.6lfs", g_timer_elapsed(timer, NULL)); + + hmstreamrecorder = (mstreamrecorder_handle_t *) g_malloc0(sizeof(mstreamrecorder_handle_t)); + + recorder_state = STREAMRECORDER_STATE_NONE; + + g_timer_reset(timer); + + bret = mode_change(); + if (!bret) + return bret; + + print_menu(); + + g_loop = g_main_loop_new(NULL, FALSE); + + stdin_channel = g_io_channel_unix_new(fileno(stdin));/* read from stdin */ + g_io_add_watch(stdin_channel, G_IO_IN, (GIOFunc)cmd_input, NULL); + + LOGD("RUN main loop"); + + g_main_loop_run(g_loop); + + LOGD("STOP main loop"); + + if (timer) { + g_timer_stop(timer); + g_timer_destroy(timer); + timer = NULL; + } + + g_free(hmstreamrecorder); + g_main_loop_unref(g_loop); + g_io_channel_unref(stdin_channel); + + return bret; +} + +/*EOF*/ -- 2.7.4