--- /dev/null
+Jeongmo Yang <jm80.yang at samsung dot com>
+Hyuntae Kim <ht1211.kim at samsung dot com>
+Heechul Jeon <heechul.jeon at samsung dot com>
--- /dev/null
+Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.\r
+\r
+ Apache License\r
+ Version 2.0, January 2004\r
+ http://www.apache.org/licenses/\r
+\r
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r
+\r
+ 1. Definitions.\r
+\r
+ "License" shall mean the terms and conditions for use, reproduction,\r
+ and distribution as defined by Sections 1 through 9 of this document.\r
+\r
+ "Licensor" shall mean the copyright owner or entity authorized by\r
+ the copyright owner that is granting the License.\r
+\r
+ "Legal Entity" shall mean the union of the acting entity and all\r
+ other entities that control, are controlled by, or are under common\r
+ control with that entity. For the purposes of this definition,\r
+ "control" means (i) the power, direct or indirect, to cause the\r
+ direction or management of such entity, whether by contract or\r
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the\r
+ outstanding shares, or (iii) beneficial ownership of such entity.\r
+\r
+ "You" (or "Your") shall mean an individual or Legal Entity\r
+ exercising permissions granted by this License.\r
+\r
+ "Source" form shall mean the preferred form for making modifications,\r
+ including but not limited to software source code, documentation\r
+ source, and configuration files.\r
+\r
+ "Object" form shall mean any form resulting from mechanical\r
+ transformation or translation of a Source form, including but\r
+ not limited to compiled object code, generated documentation,\r
+ and conversions to other media types.\r
+\r
+ "Work" shall mean the work of authorship, whether in Source or\r
+ Object form, made available under the License, as indicated by a\r
+ copyright notice that is included in or attached to the work\r
+ (an example is provided in the Appendix below).\r
+\r
+ "Derivative Works" shall mean any work, whether in Source or Object\r
+ form, that is based on (or derived from) the Work and for which the\r
+ editorial revisions, annotations, elaborations, or other modifications\r
+ represent, as a whole, an original work of authorship. For the purposes\r
+ of this License, Derivative Works shall not include works that remain\r
+ separable from, or merely link (or bind by name) to the interfaces of,\r
+ the Work and Derivative Works thereof.\r
+\r
+ "Contribution" shall mean any work of authorship, including\r
+ the original version of the Work and any modifications or additions\r
+ to that Work or Derivative Works thereof, that is intentionally\r
+ submitted to Licensor for inclusion in the Work by the copyright owner\r
+ or by an individual or Legal Entity authorized to submit on behalf of\r
+ the copyright owner. For the purposes of this definition, "submitted"\r
+ means any form of electronic, verbal, or written communication sent\r
+ to the Licensor or its representatives, including but not limited to\r
+ communication on electronic mailing lists, source code control systems,\r
+ and issue tracking systems that are managed by, or on behalf of, the\r
+ Licensor for the purpose of discussing and improving the Work, but\r
+ excluding communication that is conspicuously marked or otherwise\r
+ designated in writing by the copyright owner as "Not a Contribution."\r
+\r
+ "Contributor" shall mean Licensor and any individual or Legal Entity\r
+ on behalf of whom a Contribution has been received by Licensor and\r
+ subsequently incorporated within the Work.\r
+\r
+ 2. Grant of Copyright License. Subject to the terms and conditions of\r
+ this License, each Contributor hereby grants to You a perpetual,\r
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+ copyright license to reproduce, prepare Derivative Works of,\r
+ publicly display, publicly perform, sublicense, and distribute the\r
+ Work and such Derivative Works in Source or Object form.\r
+\r
+ 3. Grant of Patent License. Subject to the terms and conditions of\r
+ this License, each Contributor hereby grants to You a perpetual,\r
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+ (except as stated in this section) patent license to make, have made,\r
+ use, offer to sell, sell, import, and otherwise transfer the Work,\r
+ where such license applies only to those patent claims licensable\r
+ by such Contributor that are necessarily infringed by their\r
+ Contribution(s) alone or by combination of their Contribution(s)\r
+ with the Work to which such Contribution(s) was submitted. If You\r
+ institute patent litigation against any entity (including a\r
+ cross-claim or counterclaim in a lawsuit) alleging that the Work\r
+ or a Contribution incorporated within the Work constitutes direct\r
+ or contributory patent infringement, then any patent licenses\r
+ granted to You under this License for that Work shall terminate\r
+ as of the date such litigation is filed.\r
+\r
+ 4. Redistribution. You may reproduce and distribute copies of the\r
+ Work or Derivative Works thereof in any medium, with or without\r
+ modifications, and in Source or Object form, provided that You\r
+ meet the following conditions:\r
+\r
+ (a) You must give any other recipients of the Work or\r
+ Derivative Works a copy of this License; and\r
+\r
+ (b) You must cause any modified files to carry prominent notices\r
+ stating that You changed the files; and\r
+\r
+ (c) You must retain, in the Source form of any Derivative Works\r
+ that You distribute, all copyright, patent, trademark, and\r
+ attribution notices from the Source form of the Work,\r
+ excluding those notices that do not pertain to any part of\r
+ the Derivative Works; and\r
+\r
+ (d) If the Work includes a "NOTICE" text file as part of its\r
+ distribution, then any Derivative Works that You distribute must\r
+ include a readable copy of the attribution notices contained\r
+ within such NOTICE file, excluding those notices that do not\r
+ pertain to any part of the Derivative Works, in at least one\r
+ of the following places: within a NOTICE text file distributed\r
+ as part of the Derivative Works; within the Source form or\r
+ documentation, if provided along with the Derivative Works; or,\r
+ within a display generated by the Derivative Works, if and\r
+ wherever such third-party notices normally appear. The contents\r
+ of the NOTICE file are for informational purposes only and\r
+ do not modify the License. You may add Your own attribution\r
+ notices within Derivative Works that You distribute, alongside\r
+ or as an addendum to the NOTICE text from the Work, provided\r
+ that such additional attribution notices cannot be construed\r
+ as modifying the License.\r
+\r
+ You may add Your own copyright statement to Your modifications and\r
+ may provide additional or different license terms and conditions\r
+ for use, reproduction, or distribution of Your modifications, or\r
+ for any such Derivative Works as a whole, provided Your use,\r
+ reproduction, and distribution of the Work otherwise complies with\r
+ the conditions stated in this License.\r
+\r
+ 5. Submission of Contributions. Unless You explicitly state otherwise,\r
+ any Contribution intentionally submitted for inclusion in the Work\r
+ by You to the Licensor shall be under the terms and conditions of\r
+ this License, without any additional terms or conditions.\r
+ Notwithstanding the above, nothing herein shall supersede or modify\r
+ the terms of any separate license agreement you may have executed\r
+ with Licensor regarding such Contributions.\r
+\r
+ 6. Trademarks. This License does not grant permission to use the trade\r
+ names, trademarks, service marks, or product names of the Licensor,\r
+ except as required for reasonable and customary use in describing the\r
+ origin of the Work and reproducing the content of the NOTICE file.\r
+\r
+ 7. Disclaimer of Warranty. Unless required by applicable law or\r
+ agreed to in writing, Licensor provides the Work (and each\r
+ Contributor provides its Contributions) on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r
+ implied, including, without limitation, any warranties or conditions\r
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r
+ PARTICULAR PURPOSE. You are solely responsible for determining the\r
+ appropriateness of using or redistributing the Work and assume any\r
+ risks associated with Your exercise of permissions under this License.\r
+\r
+ 8. Limitation of Liability. In no event and under no legal theory,\r
+ whether in tort (including negligence), contract, or otherwise,\r
+ unless required by applicable law (such as deliberate and grossly\r
+ negligent acts) or agreed to in writing, shall any Contributor be\r
+ liable to You for damages, including any direct, indirect, special,\r
+ incidental, or consequential damages of any character arising as a\r
+ result of this License or out of the use or inability to use the\r
+ Work (including but not limited to damages for loss of goodwill,\r
+ work stoppage, computer failure or malfunction, or any and all\r
+ other commercial damages or losses), even if such Contributor\r
+ has been advised of the possibility of such damages.\r
+\r
+ 9. Accepting Warranty or Additional Liability. While redistributing\r
+ the Work or Derivative Works thereof, You may choose to offer,\r
+ and charge a fee for, acceptance of support, warranty, indemnity,\r
+ or other liability obligations and/or rights consistent with this\r
+ License. However, in accepting such obligations, You may act only\r
+ on Your own behalf and on Your sole responsibility, not on behalf\r
+ of any other Contributor, and only if You agree to indemnify,\r
+ defend, and hold each Contributor harmless for any liability\r
+ incurred by, or claims asserted against, such Contributor by reason\r
+ of your accepting any such warranty or additional liability.\r
+\r
+ END OF TERMS AND CONDITIONS\r
+\r
+ APPENDIX: How to apply the Apache License to your work.\r
+\r
+ To apply the Apache License to your work, attach the following\r
+ boilerplate notice, with the fields enclosed by brackets "[]"\r
+ replaced with your own identifying information. (Don't include\r
+ the brackets!) The text should be enclosed in the appropriate\r
+ comment syntax for the file format. We also recommend that a\r
+ file or class name and description of purpose be included on the\r
+ same "printed page" as the copyright notice for easier\r
+ identification within third-party archives.\r
+\r
+ Copyright [yyyy] [name of copyright owner]\r
+\r
+ Licensed under the Apache License, Version 2.0 (the "License");\r
+ you may not use this file except in compliance with the License.\r
+ You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+\r
+\r
--- /dev/null
+ACLOCAL_AMFLAGS='-I m4'
+
+SUBDIRS = src test
+
+pcfiles = mm-streamrecorder.pc
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = $(pcfiles)
+EXTRA_DIST = $(pcfiles)
--- /dev/null
+Copyright (c) Samsung Electronics Co., Ltd. All rights reserved.
+Except as noted, this software is licensed under Apache License, Version 2.
+Please, see the LICENSE.APLv2 file for Apache License terms and conditions.
--- /dev/null
+#! /bin/sh
+
+libtoolize --copy --force
+aclocal -I m4
+autoheader
+autoconf
+automake -a -c
--- /dev/null
+AC_PREREQ(2.52)
+
+AC_INIT([libmm-streamrecorder], [1.0])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign])
+AC_CONFIG_HEADERS([config.h:config.hin])
+AC_CONFIG_MACRO_DIR([m4])
+
+m4_pattern_allow([AM_PROG_AR])
+AM_PROG_AR
+
+# Checks for programs.
+AC_PROG_CC
+AC_C_CONST
+dnl AC_FUNC_MALLOC
+AC_FUNC_MMAP
+AC_FUNC_REALLOC
+AC_FUNC_SELECT_ARGTYPES
+AC_FUNC_STAT
+AC_FUNC_VPRINTF
+AC_HEADER_STDBOOL
+AC_HEADER_STDC
+AC_HEADER_TIME
+AC_PROG_GCC_TRADITIONAL
+AC_PROG_LIBTOOL
+
+# Checks for libraries.
+PKG_CHECK_MODULES(GST, gstreamer-1.0 >= 1.2.0)
+AC_SUBST(GST_CFLAGS)
+AC_SUBST(GST_LIBS)
+
+PKG_CHECK_MODULES(GST_PLUGIN_BASE, gstreamer-base-1.0 >= 1.2.0)
+AC_SUBST(GST_PLUGIN_BASE_CFLAGS)
+AC_SUBST(GST_PLUGIN_BASE_LIBS)
+
+PKG_CHECK_MODULES(GST_VIDEO, gstreamer-video-1.0 >= 1.2.0)
+AC_SUBST(GST_VIDEO_CFLAGS)
+AC_SUBST(GST_VIDEO_LIBS)
+
+PKG_CHECK_MODULES(MM_COMMON, mm-common)
+AC_SUBST(MM_COMMON_CFLAGS)
+AC_SUBST(MM_COMMON_LIBS)
+
+PKG_CHECK_MODULES(MM_LOG, mm-log)
+AC_SUBST(MM_LOG_CFLAGS)
+AC_SUBST(MM_LOG_LIBS)
+
+PKG_CHECK_MODULES(GLIB, glib-2.0)
+AC_SUBST(GLIB_CFLAGS)
+AC_SUBST(GLIB_LIBS)
+
+PKG_CHECK_MODULES(GST_APP, gstreamer-app-1.0 >= 1.2.0)
+AC_SUBST(GST_APP_CFLAGS)
+AC_SUBST(GST_APP_LIBS)
+
+PKG_CHECK_MODULES(INIPARSER, iniparser)
+AC_SUBST(INIPARSER_CFLAGS)
+AC_SUBST(INIPARSER_LIBS)
+
+# Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS([fcntl.h memory.h stdlib.h string.h sys/time.h unistd.h])
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+
+# Checks for library functions.
+AC_FUNC_ALLOCA
+AC_FUNC_FORK
+AC_FUNC_MALLOC
+AC_FUNC_MEMCMP
+AC_FUNC_SELECT_ARGTYPES
+AC_TYPE_SIGNAL
+AC_CHECK_FUNCS([memset select])
+AC_CONFIG_FILES([
+Makefile
+src/Makefile
+test/Makefile
+mm-streamrecorder.pc
+])
+AC_OUTPUT
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+ <assign>
+ <filesystem path="/usr/bin/mm_streamrecorder_testsuite" label="_" exec_label="none" />
+ </assign>
+</manifest>
--- /dev/null
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 4 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else. This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_RC], [AC_DEFUN([AC_LIBTOOL_RC])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
--- /dev/null
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: mm-streamrecorder
+Description: Multimedia Framework Stream Recorder Library
+Requires: gstreamer-1.0 gstreamer-base-1.0 mm-common mm-log
+Version: $VERSION
+Libs: -L${libdir} -lmmfstreamrecorder
+Cflags: -I${includedir}/ -I${includedir}/mmf
--- /dev/null
+Name: libmm-streamrecorder
+Summary: Media Stream Recorder library
+Version: 0.0.1
+Release: 0
+Group: Multimedia/Other
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+BuildRequires: pkgconfig(mm-common)
+BuildRequires: pkgconfig(mm-log)
+BuildRequires: pkgconfig(gstreamer-base-1.0)
+BuildRequires: pkgconfig(gstreamer-video-1.0)
+BuildRequires: pkgconfig(gstreamer-app-1.0)
+BuildRequires: pkgconfig(iniparser)
+
+%description
+This library is for making video/audio files with gstreamer
+
+
+%package devel
+Summary: Common recorder development library
+Group: libdevel
+Version: %{version}
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+Media Stream Recorder development library
+
+
+%prep
+%setup -q
+
+
+%build
+#export CFLAGS+=" -DGST_EXT_TIME_ANALYSIS"
+export CFLAGS+=" -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"
+./autogen.sh
+%configure --disable-static
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+mkdir -p %{buildroot}/usr/share/license
+cp LICENSE.APLv2 %{buildroot}/usr/share/license/%{name}
+%make_install
+
+%clean
+rm -rf %{buildroot}
+
+%post
+/sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%manifest libmm-streamrecorder.manifest
+%defattr(-,root,root,-)
+%{_bindir}/*
+%{_libdir}/*.so.*
+%{_datadir}/license/%{name}
+
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/mmf/mm_streamrecorder.h
+%{_libdir}/pkgconfig/mm-streamrecorder.pc
+%{_libdir}/*.so
--- /dev/null
+ACLOCAL_AMFLAGS='-I m4'
+
+lib_LTLIBRARIES = libmmfstreamrecorder.la
+
+includelibmmfstreamrecorderdir = $(includedir)/mmf
+
+includelibmmfstreamrecorder_HEADERS = include/mm_streamrecorder.h
+
+noinst_HEADERS = include/mm_streamrecorder.h \
+ include/mm_streamrecorder_internal.h \
+ include/mm_streamrecorder_fileinfo.h \
+ include/mm_streamrecorder_util.h \
+ include/mm_streamrecorder_gstdispatch.h \
+ include/mm_streamrecorder_attribute.h \
+ include/mm_streamrecorder_video.h \
+ include/mm_streamrecorder_gstcommon.h \
+ include/mm_streamrecorder_recorder.h \
+ include/mm_streamrecorder_audio.h \
+ include/mm_streamrecorder_buffer_manager.h\
+ include/mm_streamrecorder_ini.h
+
+libmmfstreamrecorder_la_SOURCES = mm_streamrecorder.c \
+ mm_streamrecorder_internal.c \
+ mm_streamrecorder_fileinfo.c \
+ mm_streamrecorder_util.c \
+ mm_streamrecorder_gstdispatch.c \
+ mm_streamrecorder_attribute.c \
+ mm_streamrecorder_video.c \
+ mm_streamrecorder_gstcommon.c \
+ mm_streamrecorder_recorder.c \
+ mm_streamrecorder_audio.c \
+ mm_streamrecorder_buffer_manager.c\
+ mm_streamrecorder_ini.c
+
+libmmfstreamrecorder_la_CFLAGS = -I$(srcdir)/include \
+ $(GST_CFLAGS) \
+ $(GST_PLUGIN_BASE_CFLAGS) \
+ $(GST_VIDEO_CFLAGS) \
+ $(GST_INTERFACES_CFLAGS) \
+ $(MM_LOG_CFLAGS) \
+ $(MM_COMMON_CFLAGS) \
+ $(GST_APP_CFLAGS)
+
+libmmfstreamrecorder_la_LIBADD = \
+ $(GST_LIBS) \
+ $(GST_PLUGIN_BASE_LIBS) \
+ $(GST_VIDEO_LIBS) \
+ $(GST_INTERFACES_LIBS) \
+ $(MM_COMMON_LIBS) \
+ $(MM_LOG_LIBS) \
+ $(VCONF_LIBS) \
+ $(GST_APP_LIBS) \
+ $(INIPARSER_LIBS)
+
+libmmfstreamrecorder_la_CFLAGS += $(MMLOGSVR_CFLAGS) -DMMF_LOG_OWNER=0x00400000 -DMMF_DEBUG_PREFIX=\"MMF-STREAMRECORDER\"
+libmmfstreamrecorder_la_LIBADD += $(MMLOGSVR_LIBS)
+
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 __MM_STREAMRECORDER_H__
+#define __MM_STREAMRECORDER_H__
+
+/*=======================================================================================
+| INCLUDE FILES |
+========================================================================================*/
+#include <glib.h>
+
+#include <mm_types.h>
+#include <mm_error.h>
+#include <mm_message.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=======================================================================================
+| GLOBAL DEFINITIONS AND DECLARATIONS FOR STREAMRECORDER |
+========================================================================================*/
+
+/*=======================================================================================
+| MACRO DEFINITIONS |
+========================================================================================*/
+
+/* Attributes Macros */
+
+#define MMSTR_VIDEO_ENABLE "video-enable"
+
+#define MMSTR_VIDEO_BUFFER_TYPE "videobuffer-type"
+
+#define MMSTR_VIDEO_SOURCE_FORMAT "videosource-format"
+
+#define MMSTR_VIDEO_FRAMERATE "video-framerate"
+
+#define MMSTR_VIDEO_BITRATE "video-bitrate"
+
+#define MMSTR_VIDEO_RESOLUTION_WIDTH "video-resolution-width"
+
+#define MMSTR_VIDEO_RESOLUTION_HEIGHT "video-resolution-height"
+
+/**
+ * Disable Audio stream when record.
+ */
+#define MMSTR_AUDIO_ENABLE "audio-enable"
+
+#define MMSTR_AUDIO_SOURCE_FORMAT "audio-source-format"
+
+#define MMSTR_AUDIO_BITRATE "audio-bitrate"
+
+#define MMSTR_AUDIO_SAMPLERATE "audio-samplerate"
+
+#define MMSTR_VIDEO_ENCODER "video-encoder"
+
+#define MMSTR_AUDIO_ENCODER "audio-encoder"
+
+#define MMSTR_AUDIO_CHANNEL "audio-channel-count"
+
+#define MMSTR_FILE_FORMAT "file-format"
+
+#define MMSTR_FILENAME "filename"
+
+#define MMSTR_RECORDER_MODE "recorder-mode"
+
+#define MMSTR_TARGET_MAX_SIZE "target-max-size"
+
+#define MMSTR_TARGET_TIME_LIMIT "target-time-limit"
+
+/*=======================================================================================
+| ENUM DEFINITIONS |
+========================================================================================*/
+/**
+ * An enumeration for streamrecorder states.
+ */
+typedef enum {
+ MM_STREAMRECORDER_STATE_NONE, /**< Streamrecorder is not created yet */
+ MM_STREAMRECORDER_STATE_CREATED, /**< Streamrecorder is created, but not initialized yet */
+ MM_STREAMRECORDER_STATE_PREPARED, /**< Streamrecorder is prepared to record */
+ MM_STREAMRECORDER_STATE_RECORDING, /**< Streamrecorder is now recording */
+ MM_STREAMRECORDER_STATE_PAUSED, /**< Streamrecorder is paused while recording */
+ MM_STREAMRECORDER_STATE_NUM, /**< Number of streamrecorder states */
+} MMStreamRecorderStateType;
+
+/**
+ * An enumeration of Audio Format.
+ */
+typedef enum {
+ MM_STREAMRECORDER_AUDIO_FORMAT_PCM_U8 = 0, /**< unsigned 8bit audio */
+ MM_STREAMRECORDER_AUDIO_FORMAT_PCM_S16_LE = 2, /**< signed 16bit audio. Little endian. */
+} MMStreamRecorderAudioFormat;
+
+/**********************************
+* Stream data *
+**********************************/
+
+typedef enum {
+ MM_STREAM_TYPE_NONE,
+ MM_STREAM_TYPE_VIDEO,
+ MM_STREAM_TYPE_AUDIO,
+} MMStreamRecorderStreamType;
+
+/*=======================================================================================
+| STRUCTURE DEFINITIONS |
+========================================================================================*/
+
+/* General Structure */
+/**
+ * An enumeration for streamrecorder mode.
+ */
+
+typedef enum {
+ MM_STREAMRECORDER_MODE_MEDIABUFFER = 0, /**< Recording with mediabuffer */
+ MM_STREAMRECORDER_MODE_SCREENRECORD, /**< Recording with screenrecord */
+} MMStreamRecorderModeType;
+
+typedef enum {
+ MM_STREAMRECORDER_VIDEO_TYPE_TBM_BO, /**< TBM BO type */
+ MM_STREAMRECORDER_VIDEO_TYPE_NORMAL_BUFFER, /**< Normal Raw data buffer */
+} MMStreamRecorderVideoBufType;
+
+typedef enum {
+ MM_STREAMRECORDER_INPUT_FORMAT_INVALID = -1,/**< Invalid pixel format */
+ MM_STREAMRECORDER_INPUT_FORMAT_NV12, /**< NV12 pixel format */
+ MM_STREAMRECORDER_INPUT_FORMAT_NV21, /**< NV21 pixel format */
+ MM_STREAMRECORDER_INPUT_FORMAT_I420, /**< I420 pixel format */
+ MM_STREAMRECORDER_INPUT_FORMAT_UYVY, /**< UYVY pixel format */
+ MM_STREAMRECORDER_INPUT_FORMAT_YUYV, /**< YUYV pixel format */
+ MM_STREAMRECORDER_INPUT_FORMAT_BGRA8888, /**< BGRA8888 pixel format */
+ MM_STREAMRECORDER_INPUT_FORMAT_NUM /**< Number of the pixel format */
+} MMStreamRecorderVideoSourceFormat;
+
+/**********************************
+* Attribute info *
+**********************************/
+
+/**
+ * Report structure of recording file
+ */
+typedef struct {
+ char *recording_filename; /**< File name of stored recording file. Please free after using. */
+} MMStreamRecordingReport; /**< report structure definition of recording file */
+
+/**
+* An enumeration for attribute values types.
+*/
+typedef enum {
+ MM_STR_REC_ATTRS_TYPE_INVALID = -1, /**< Type is invalid */
+ MM_STR_REC_ATTRS_TYPE_INT, /**< Integer type attribute */
+ MM_STR_REC_ATTRS_TYPE_DOUBLE, /**< Double type attribute */
+ MM_STR_REC_ATTRS_TYPE_STRING, /**< UTF-8 String type attribute */
+ MM_STR_REC_ATTRS_TYPE_DATA, /**< Pointer type attribute */
+} MMStreamRecorderAttrsType;
+
+/**
+* An enumeration for attribute validation type.
+*/
+typedef enum {
+ MM_STR_REC_ATTRS_VALID_TYPE_INVALID = -1, /**< Invalid validation type */
+ MM_STR_REC_ATTRS_VALID_TYPE_NONE, /**< Do not check validity */
+ MM_STR_REC_ATTRS_VALID_TYPE_INT_ARRAY, /**< validity checking type of integer array */
+ MM_STR_REC_ATTRS_VALID_TYPE_INT_RANGE, /**< validity checking type of integer range */
+ MM_STR_REC_ATTRS_VALID_TYPE_DOUBLE_ARRAY, /**< validity checking type of double array */
+ MM_STR_REC_ATTRS_VALID_TYPE_DOUBLE_RANGE, /**< validity checking type of double range */
+} MMStreamRecorderAttrsValidType;
+
+/**
+* An enumeration for attribute access flag.
+*/
+typedef enum {
+ MM_STR_REC_ATTRS_FLAG_DISABLED = 0, /**< None flag is set. This means the attribute is not allowed to use. */
+ MM_STR_REC_ATTRS_FLAG_READABLE = 1 << 0,/**< Readable */
+ MM_STR_REC_ATTRS_FLAG_WRITABLE = 1 << 1,/**< Writable */
+ MM_STR_REC_ATTRS_FLAG_MODIFIED = 1 << 2,/**< Modified */
+ MM_STR_REC_ATTRS_FLAG_RW = MM_STR_REC_ATTRS_FLAG_READABLE | MM_STR_REC_ATTRS_FLAG_WRITABLE,
+ /**< Readable and Writable */
+} MMStreamRecorderAttrsFlag;
+
+/**
+* A structure for attribute information
+*/
+typedef struct {
+ MMStreamRecorderAttrsType type;
+ MMStreamRecorderAttrsFlag flag;
+ MMStreamRecorderAttrsValidType validity_type;
+
+/**
+* A union that describes validity of the attribute.
+*/
+ union {
+ /**
+ * Validity structure for integer array.
+ */
+ struct {
+ int *array; /**< a pointer of array */
+ int count; /**< size of array */
+ int def; /**< default value. Real value not index of array */
+ } int_array;
+
+ /**
+ * Validity structure for integer range.
+ */
+ struct {
+ int min; /**< minimum range */
+ int max; /**< maximum range */
+ int def; /**< default value */
+ } int_range;
+
+ /**
+ * Validity structure for double array.
+ */
+ struct {
+ double *array; /**< a pointer of array */
+ int count; /**< size of array */
+ double def; /**< default value. Real value not index of array */
+ } double_array;
+
+ /**
+ * Validity structure for double range.
+ */
+ struct {
+ double min; /**< minimum range */
+ double max; /**< maximum range */
+ double def; /**< default value */
+ } double_range;
+ };
+} MMStreamRecorderAttrsInfo;
+
+
+/*=======================================================================================
+| TYPE DEFINITIONS |
+========================================================================================*/
+/*=======================================================================================
+| GLOBAL FUNCTION PROTOTYPES |
+========================================================================================*/
+/**
+ * mm_streamrecorder_create:\n
+ * Create streamrecorder object. This is the function that an user who wants to use mm_streamrecorder calls first.
+ * This function creates handle structure and initialize mutex, attributes, gstreamer.
+ * When this function success, it will return a handle of newly created object.
+ * A user have to put the handle when he calls every function of mm_streamrecorder. \n
+ *
+ * @param[out] streamrecorder A handle of streamrecorder.
+ * @param[in] info Information for devices
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @see mm_streamrecorder_destroy
+ * @pre None
+ * @post Next state of mm-streamrecorder will be MM_STREAMRECORDER_STATE_CREATED
+ * @remarks You can create multiple handles on a context at the same time. However,
+ * streamrecordercorder cannot guarantee proper operation because of limitation of resources.
+ * @par example
+ * @code
+
+#include <mm_streamrecorder.h>
+
+gboolean initialize_streamrecorder()
+{
+ int err;
+
+ err = mm_streamrecorder_create(&hstream);
+
+ if (err != MM_ERROR_NONE) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ * @endcode
+ */
+
+//INITIAL GSTREAMER
+int mm_streamrecorder_create(MMHandleType *streamrecorder);
+
+/**
+ * mm_streamrecorder_destroy:\n
+ * Destroy streamrecorder object. Release handle and all of the resources that were created in mm_streamrecorder_create().\n
+ * This is the finalizing function of mm_streamrecorder. If this function is not called or fails to call, the handle isn't released fully.
+ * This function releases attributes, mutexes, sessions, and handle itself. This function also removes all of remaining messages.
+ * So if your application should wait a certain message of mm_streamrecorder, please wait to call this function till getting the message.
+ *
+ *
+ * @param[in] streamrecorder A handle of streamrecorder.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @see mm_streamrecorder_create
+ * @pre Previous state of mm-streamrecorder should be MM_STREAMRECORDER_STATE_CREATED
+ * @post Because the handle is not valid, you can't check the state.
+ * @remarks None
+ * @par example
+ * @code
+
+#include <mm_streamrecorder.h>
+
+gboolean destroy_streamrecorder()
+{
+ int err;
+
+ //Destroy streamrecorder handle
+ err = mm_streamrecorder_destroy(hstreamrecorder);
+ if (err < 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ * @endcode
+ */
+
+// DESTROY GSTREAMER
+int mm_streamrecorder_destroy(MMHandleType streamrecorder);
+
+/**
+ * mm_streamrecorder_realize:\n
+ * Allocate resources for streamrecorder and initialize it.
+ * This also creates streamer pipeline. So you have to set attributes that are pivotal to create
+ * the pipeline before calling this function. This function also takes a roll to manage confliction
+ * between different applications which use streamrecorder. For example, if you try to use streamrecorder when
+ * other application that is more important such as call application, this function will return
+ * 'MM_ERROR_POLICY_BLOCKED'. On the contrary, if your application that uses streamrecorder starts to launch
+ * while another application that uses speaker and has lower priority, your application will kick
+ * another application.
+ *
+ * @param[in] streamrecorder A handle of streamrecorder.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @see mm_streamrecorder_unrealize
+ * @pre Previous state of mm-streamrecorder should be MM_STREAMRECORDER_STATE_CREATED
+ * @post Next state of mm-streamrecorder will be MM_STREAMRECORDER_STATE_READY
+ * @remarks None
+ */
+
+// CONSTRUCT PIPLINE
+int mm_streamrecorder_realize(MMHandleType streamrecorder);
+
+/**
+ * mm_streamrecorder_unrealize:\n
+ * Uninitialize streamrecoder resources and free allocated memory.
+ * Most important resource that is released here is gstreamer pipeline of mm_streamrecorder.
+ * Because most of resources are operating on the gstreamer pipeline,
+ * this function should be called to release its resources.
+ * Moreover, mm_streamrecorder is controlled by audio session manager. If an user doesn't call this function when he want to release mm_streamrecorder,
+ * other multimedia frameworks may face session problem. For more detail information, please refer mm_session module.
+ *
+ * @param[in] streamrecorder A handle of streamrecorder.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @see mm_streamrecorder_realize
+ * @pre Previous state of mm-streamrecorder should be MM_STREAMRECORDER_STATE_READY
+ * @post Next state of mm-streamrecorder will be MM_STREAMRECORDER_STATE_CREATED
+ * @remarks None
+ */
+
+// DESTROY PIPELINE
+int mm_streamrecorder_unrealize(MMHandleType streamrecorder);
+
+/**
+ * mm_streamrecorder_start:\n
+ * Start previewing. (Image/Video mode)
+ *
+ * @param[in] streamrecorder A handle of streamrecorder.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @see mm_streamrecorder_stop
+ * @pre Previous state of mm-streamrecorder should be MM_STREAMRECORDER_STATE_READY
+ * @post Next state of mm-streamrecorder will be MM_STREAMRECORDER_STATE_PREPARED
+ * @remarks None
+ */
+
+// START ENCODE
+int mm_streamrecorder_record(MMHandleType streamrecorder);
+
+/**
+ * mm_streamrecorder_pause:\n
+ * Pause A/V recording or Audio recording. (Audio/Video mode only)
+ *
+ * @param[in] streamrecorder A handle of streamrecorder.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @see mm_streamrecorder_record
+ * @pre Previous state of mm-streamrecorder should be MM_STREAMRECORDER_STATE_RECORDING
+ * @post Next state of mm-streamrecorder will be MM_STREAMRECORDER_STATE_PAUSED
+ * @remarks Even though this function is for pausing recording, small amount of buffers could be recorded after pause().
+ * Because the buffers which are existed in the queue were created before pause(), the buffers should be recorded.
+ */
+int mm_streamrecorder_pause(MMHandleType streamrecorder);
+
+/**
+ * mm_streamrecorder_stop:\n
+ * Stop previewing. (Image/Video mode)
+ * This function will change the status of pipeline.
+ *
+ * @param[in] streamrecorder A handle of streamrecorder.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @see mm_streamrecorder_start
+ * @pre Previous state of mm-streamrecorder should be MM_STREAMRECORDER_STATE_PREPARED
+ * @post Next state of mm-streamrecorder will be MM_STREAMRECORDER_STATE_READY
+ * @remarks None
+ * @par example
+ * @code
+
+#include <mm_streamrecorder.h>
+
+gboolean stop_streamrecorder()
+{
+ int err;
+
+ //Stop preview
+ err = mm_streamrecorder_stop(hstreamrecorder);
+ if (err < 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ * @endcode
+ */
+int mm_streamrecorder_commit(MMHandleType streamrecorder);
+
+int mm_streamrecorder_cancel(MMHandleType streamrecorder);
+
+int mm_streamrecorder_push_stream_buffer(MMHandleType streamrecorder, MMStreamRecorderStreamType streamtype, unsigned long timestamp, void *buffer, int size);
+
+/**
+ * mm_streamrecorder_commit:\n
+ * Stop recording and save results. (Audio/Video mode only)\n
+ * After starting recording, encoded data frame will be stored in the location specified in MMSTR_FILENAME.
+ * Some encoder or muxer require a certain type of finalizing such as adding some information to header.
+ * This function takes that roll. So if you don't call this function after recording, the result file may not be playable.\n
+ * Because this is the function for saving the recording result, the operation is available
+ *
+ * @param[in] streamrecorder A handle of streamrecorder.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @see mm_streamrecorder_cancel
+ * @pre Previous state of mm-streamrecorder should be MM_STREAMRECORDER_STATE_RECORDING
+ * @post Next state of mm-streamrecorder will be MM_STREAMRECORDER_STATE_PREPARED
+ * @remarks This function can take a few second when recording time is long.
+ * and if there are only quite few input buffer from video src or audio src,
+ * committing could be failed.
+ * @par example
+ * @code
+
+#include <mm_streamrecorder.h>
+
+gboolean record_and_save_video_file()
+{
+ int err;
+
+ // Start recording
+ err = mm_streamrecorder_record(hstreamrecorder);
+ if (err < 0) {
+ return FALSE;
+ }
+
+ // Wait while recording for test...
+ // In normal case, mm_streamrecorder_record() and mm_streamrecorder_commit() aren't called in the same function.
+
+ // Save file
+ err = mm_streamrecorder_commit(hstreamrecorder);
+ if (err < 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ * @endcode
+ */
+int mm_streamrecorder_commit(MMHandleType streamrecorder);
+
+/**
+ * mm_streamrecorder_cancel:\n
+ * Stop recording and discard the result. (Audio/Video mode only)
+ * When a user want to finish recording without saving the result file, this function can be used.
+ * Like mm_streamrecorder_commit(), this function also stops recording, release related resources(like codec) ,and goes back to preview status.
+ * However, instead of saving file, this function unlinks(delete) the result.\n
+ * Because this is the function for canceling recording, the operation is available
+ *
+ * @param[in] streamrecorder A handle of streamrecorder.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @see mm_streamrecorder_commit
+ * @pre Previous state of mm-streamrecorder should be MM_STREAMRECORDER_STATE_RECORDING
+ * @post Next state of mm-streamrecorder will be MM_STREAMRECORDER_STATE_PREPARED
+ * @remarks None
+ * @par example
+ * @code
+
+#include <mm_streamrecorder.h>
+
+gboolean record_and_cancel_video_file()
+{
+ int err;
+
+ // Start recording
+ err = mm_streamrecorder_record(hstreamrecorder);
+ if (err < 0) {
+ return FALSE;
+ }
+
+ // Wait while recording...
+
+ // Cancel recording
+ err = mm_streamrecorder_cancel(hstreamrecorder);
+ if (err < 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ * @endcode
+ */
+int mm_streamrecorder_cancel(MMHandleType streamrecorder);
+
+/**
+ * mm_streamrecorder_set_message_callback:\n
+ * Set callback for receiving messages from streamrecorder. Through this callback function, streamrecorder
+ * sends various message including status changes, asynchronous error, capturing, and limitations.
+ * One thing you have to know is that message callback is working on the main loop of application.
+ * So until releasing the main loop, message callback will not be called.
+ *
+ * @param[in] streamrecorder A handle of streamrecorder.
+ * @param[in] callback Function pointer of callback function. Please refer 'MMMessageCallback'.
+ * @param[in] user_data User parameter for passing to callback function.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @see MMMessageCallback
+ * @pre None
+ * @post None
+ * @remarks registered 'callback' is called on main loop of the application. So until the main loop is released, 'callback' will not be called.
+ * @par example
+ * @code
+
+#include <mm_streamrecorder.h>
+
+gboolean setting_msg_callback()
+{
+ //set callback
+ mm_streamrecorder_set_message_callback(hstreamrecorder,(MMMessageCallback)msg_callback, (void*)hstreamrecorder);
+
+ return TRUE;
+}
+
+ * @endcode
+ */
+int mm_streamrecorder_set_message_callback(MMHandleType streamrecorder, MMMessageCallback callback, void *user_data);
+
+/**
+ * mm_streamrecorder_get_attributes:\n
+ * Get attributes of streamrecorder with given attribute names. This function can get multiple attributes
+ * simultaneously. If one of attribute fails, this function will stop at the point.
+ * 'err_attr_name' let you know the name of the attribute.
+ *
+ * @param[in] streamrecorder Specifies the streamrecorder handle.
+ * @param[out] err_attr_name Specifies the name of attributes that made an error. If the function doesn't make an error, this will be null. @n
+ * Free this variable after using.
+ * @param[in] attribute_name attribute name that user want to get.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @pre None
+ * @post None
+ * @remarks You can retrieve multiple attributes at the same time. @n
+ * This function must finish with 'NULL' argument. @n
+ * ex) mm_streamrecorder_get_attributes(....... , NULL);
+ * @see mm_streamrecorder_set_attributes
+ */
+int mm_streamrecorder_get_attributes(MMHandleType streamrecorder, char **err_attr_name, const char *attribute_name, ...) G_GNUC_NULL_TERMINATED;
+
+/**
+ * mm_streamrecorder_set_attributes:\n
+ * Set attributes of streamrecorder with given attribute names. This function can set multiple attributes
+ * simultaneously. If one of attribute fails, this function will stop at the point.
+ * 'err_attr_name' let you know the name of the attribute.
+ *
+ * @param[in] streamrecorder Specifies the streamrecorder handle.
+ * @param[out] err_attr_name Specifies the name of attributes that made an error. If the function doesn't make an error, this will be null. @n
+ * Free this variable after using.
+ * @param[in] attribute_name attribute name that user want to set.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @pre None
+ * @post None
+ * @remarks You can put multiple attributes to streamrecorder at the same time. @n
+ * This function must finish with 'NULL' argument. @n
+ * ex) mm_streamrecorder_set_attributes(....... , NULL);
+ * @see mm_streamrecorder_get_attributes
+ */
+int mm_streamrecorder_set_attributes(MMHandleType streamrecorder, char **err_attr_name, const char *attribute_name, ...) G_GNUC_NULL_TERMINATED;
+
+/**
+ * mm_streamrecorder_get_state:\n
+ * Get the current state of streamreccorder.
+ * mm_streamrecorderr is working on the base of its state. An user should check the state of mm_streamrecorder before calling its functions.
+ * If the handle is avaiable, user can retrieve the value.
+ *
+ * @param[in] streamrecorder A handle of streamrecorder.
+ * @param[out] state On return, it contains current state of streamrecorder.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @see MMStreamRecorderStateType
+ * @pre None
+ * @post None
+ * @remarks None
+ */
+int mm_streamrecorder_get_state(MMHandleType streamrecorder, MMStreamRecorderStateType *status);
+
+/**
+ @}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MM_STREAMRECORDER_H__ */
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 __MM_STREAMRECORDER_ATTRIBUTE_H__
+#define __MM_STREAMRECORDER_ATTRIBUTE_H__
+
+/*=======================================================================================
+| INCLUDE FILES |
+========================================================================================*/
+#include <mm_types.h>
+#include <mm_attrs.h>
+#include <mm_attrs_private.h>
+#include <stdarg.h>
+#include "mm_streamrecorder_internal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=======================================================================================
+| GLOBAL DEFINITIONS AND DECLARATIONS FOR STREAMRECORDER |
+========================================================================================*/
+/* Disabled
+#define GET_AND_STORE_ATTRS_AFTER_SCENE_MODE
+*/
+
+/*=======================================================================================
+| MACRO DEFINITIONS |
+========================================================================================*/
+/**
+ * Caster of attributes handle
+ */
+#define MMF_STREAMRECORDER_ATTRS(h) (((mmf_streamrecorder_t *)(h))->attributes)
+
+/*=======================================================================================
+| ENUM DEFINITIONS |
+========================================================================================*/
+/**
+ * Enumerations for streamrecorder attribute ID.
+ */
+typedef enum {
+ MM_STR_VIDEO_BUFFER_TYPE, /* 0 */
+ MM_STR_VIDEO_FORMAT,
+ MM_STR_VIDEO_FRAMERATE,
+ MM_STR_VIDEO_ENCODER_BITRATE,
+ MM_STR_VIDEO_RESOLUTION_WIDTH,
+ MM_STR_VIDEO_RESOLUTION_HEIGHT,
+ MM_STR_AUDIO_FORMAT,
+ MM_STR_AUDIO_ENCODER_BITRATE,
+ MM_STR_AUDIO_SAMPLERATE,
+ MM_STR_VIDEO_ENCODER,
+ MM_STR_AUDIO_ENCODER, /* 10 */
+ MM_STR_AUDIO_CHENNEL_COUNT,
+ MM_STR_FILE_FORMAT,
+ MM_STR_TARGET_FILE_NAME,
+ MM_STR_VIDEO_ENABLE,
+ MM_STR_AUDIO_ENABLE,
+ MM_STR_MODE,
+ MM_STR_TARGET_MAX_SIZE,
+ MM_STR_TARGET_TIME_LIMIT,
+ MM_STR_NUM
+} MMStreamRecorderAttrsID;
+
+
+/*=======================================================================================
+| TYPE DEFINITIONS |
+========================================================================================*/
+typedef bool(*mmf_streamrecorder_commit_func_t) (MMHandleType handle, int attr_idx, const mmf_value_t *value);
+
+/*=======================================================================================
+| STRUCTURE DEFINITIONS |
+========================================================================================*/
+typedef struct {
+ MMStreamRecorderAttrsID attrid;
+ const char *name;
+ int value_type;
+ int flags;
+ union {
+ void *value_void;
+ char *value_string;
+ int value_int;
+ double value_double;
+ } default_value; /* default value */
+ MMStreamRecorderAttrsValidType validity_type;
+ int validity_value1; /* can be int min, int *array, double *array, or cast to double min. */
+ int validity_value2; /* can be int max, int count, int count, or cast to double max. */
+ mmf_streamrecorder_commit_func_t attr_commit;
+} mm_streamrecorder_attr_construct_info;
+
+/*=======================================================================================
+| CONSTANT DEFINITIONS |
+========================================================================================*/
+
+/*=======================================================================================
+| STATIC VARIABLES |
+========================================================================================*/
+
+/*=======================================================================================
+| EXTERN GLOBAL VARIABLE |
+========================================================================================*/
+
+/*=======================================================================================
+| GLOBAL FUNCTION PROTOTYPES |
+========================================================================================*/
+/**
+ * This function allocates structure of attributes and sets initial values.
+ *
+ * @param[in] handle Handle of streamrecorder.
+ * @param[in] info Preset information of streamrecorder.
+ * @return This function returns allocated structure of attributes.
+ * @remarks
+ * @see _mmstreamrecorder_dealloc_attribute()
+ *
+ */
+MMHandleType _mmstreamrecorder_alloc_attribute(MMHandleType handle);
+
+/**
+ * This function release structure of attributes.
+ *
+ * @param[in] attrs Handle of streamrecorder attribute.
+ * @return void
+ * @remarks
+ * @see _mmstreamrecorder_alloc_attribute()
+ *
+ */
+void _mmstreamrecorder_dealloc_attribute(MMHandleType attrs);
+
+/**
+ * This is a meta function to get attributes of streamrecorder with given attribute names.
+ *
+ * @param[in] handle Handle of streamrecorder.
+ * @param[out] err_attr_name Specifies the name of attributes that made an error. If the function doesn't make an error, this will be null.
+ * @param[in] attribute_name attribute name that user want to get.
+ * @param[in] var_args Specifies variable arguments.
+ * @return This function returns MM_ERROR_NONE on Success, minus on Failure.
+ * @remarks You can retrieve multiple attributes at the same time. @n
+ * @see _mmstreamrecorder_set_attributes
+ */
+int _mmstreamrecorder_get_attributes(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list var_args);
+
+/**
+ * This is a meta function to set attributes of steamrecorder with given attribute names.
+ *
+ * @param[in] handle Handle of streamrecorder.
+ * @param[out] err_attr_name Specifies the name of attributes that made an error. If the function doesn't make an error, this will be null.
+ * @param[in] attribute_name attribute name that user want to set.
+ * @param[in] var_args Specifies variable arguments.
+ * @return This function returns MM_ERROR_NONE on Success, minus on Failure.
+ * @remarks You can put multiple attributes to streamrecorder at the same time. @n
+ * @see _mmstreamrecorder_get_attributes
+ */
+int _mmstreamrecorder_set_attributes(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list var_args);
+
+/**
+ * This is a meta function to get detail information of the attribute.
+ *
+ * @param[in] handle Handle of streamrecorder.
+ * @param[in] attr_name attribute name that user want to get information.
+ * @param[out] info a structure that holds information related with the attribute.
+ * @return This function returns MM_ERROR_NONE on Success, minus on Failure.
+ * @remarks If the function succeeds, 'info' holds detail information about the attribute, such as type, flag, validity_type, validity_values @n
+ * @see _mmstreamrecorder_get_attributes, _mmstreamrecorder_set_attributes
+ */
+int _mmstreamrecorder_get_attribute_info(MMHandleType handle, const char *attr_name, MMStreamRecorderAttrsInfo * info);
+
+/*=======================================================================================
+| STREAMRECORDER INTERNAL LOCAL |
+========================================================================================*/
+/**
+ * A commit function to set streamrecorder attributes
+ * If the attribute needs actual setting, this function handles that activity.
+ * When application sets an attribute, setting function in MSL common calls this function.
+ * If this function fails, original value will not change.
+ *
+ * @param[in] attr_idx Attribute index of subcategory.
+ * @param[in] attr_name Attribute name.
+ * @param[in] value Handle of streamrecorder.
+ * @param[in] commit_param Allocation type of streamrecorder context.
+ * @return This function returns TRUE on success, or FALSE on failure
+ * @remarks
+ * @see
+ *
+ */
+bool _mmstreamrecorder_commit_streamrecorder_attrs(int attr_idx, const char *attr_name, const mmf_value_t *value, void *commit_param);
+
+bool _mmstreamrecorder_commit_video_enable(MMHandleType handle, int attr_idx, const mmf_value_t *value);
+
+bool _mmstreamrecorder_commit_video_encoder(MMHandleType handle, int attr_idx, const mmf_value_t *value);
+
+bool _mmstreamrecorder_commit_audio_enable(MMHandleType handle, int attr_idx, const mmf_value_t *value);
+
+bool _mmstreamrecorder_commit_audio_encoder(MMHandleType handle, int attr_idx, const mmf_value_t *value);
+
+bool _mmstreamrecorder_commit_audio_samplingrate(MMHandleType handle, int attr_idx, const mmf_value_t *value);
+
+bool _mmstreamrecorder_commit_audio_bitformat(MMHandleType handle, int attr_idx, const mmf_value_t *value);
+
+bool _mmstreamrecorder_commit_audio_channel(MMHandleType handle, int attr_idx, const mmf_value_t *value);
+
+bool _mmstreamrecorder_commit_audio_bitrate(MMHandleType handle, int attr_idx, const mmf_value_t *value);
+
+/**
+ * check whether supported or not
+ *
+ * @param[in] handle Handle of streamrecorder.
+ * @param[in] attr_index index of attribute to check.
+ * @return bool TRUE if supported or FALSE
+ */
+bool _mmstreamrecorder_check_supported_attribute(MMHandleType handle, int attr_index);
+
+/**
+ * mm_streamrecorder_get_attribute_info:\n
+ * Get detail information of the attribute. To manager attributes, an user may want to know the exact character of the attribute,
+ * such as type, flag, and validity. This is the function to provide such information.
+ * Depending on the 'validity_type', validity union would be different. To know about the type of union, please refer 'MMStreamRecorderAttrsInfo'.
+ *
+ * @param[in] streamrecorder Specifies the streamrecorder handle.
+ * @param[in] attribute_name attribute name that user want to get information.
+ * @param[out] info a structure that holds information related with the attribute.
+ * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n
+ * Please refer 'mm_error.h' to know the exact meaning of the error.
+ * @pre None
+ * @post None
+ * @remarks If the function succeeds, 'info' holds detail information about the attribute, such as type,
+ * flag, validity_type, validity_values, and default values.
+ * @see mm_streamrecorder_get_attributes, mm_streamrecorder_set_attributes
+ */
+
+int mm_streamrecorder_get_attribute_info(MMHandleType streamrecorder, const char *attribute_name, MMStreamRecorderAttrsInfo *info);
+
+bool _mmstreamrecorder_commit_video_bitrate(MMHandleType handle, int attr_idx, const mmf_value_t *value);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MM_STREAMRECORDER_ATTRIBUTE_H__ */
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 __MM_STREAMRECORDER_AUDIO_H__
+#define __MM_STREAMRECORDER_AUDIO_H__
+
+/*=======================================================================================
+| INCLUDE FILES |
+========================================================================================*/
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=======================================================================================
+| STRUCTURE DEFINITIONS |
+========================================================================================*/
+/**
+ * MMStreamRecorder information for audio mode
+ */
+typedef struct {
+ int iAudioEncoder; /**<Encoder */
+ int iSamplingRate; /**< Sampling rate */
+ int iBitDepth; /**< Bit depth */
+ int iBitrate; /**< audio bitrate */
+ int iChannels; /**< audio channels */
+ gboolean b_commiting; /**< Is it commiting now? */
+ gboolean bMuxing; /**< whether muxing */
+ guint64 filesize; /**< current recorded file size */
+ guint64 max_size; /**< max recording size */
+ guint64 max_time; /**< max recording time */
+ int audio_encode_depth; /**< audio depth */
+ guint64 audio_frame_count; /**< current audio frame */
+} _MMStreamRecorderAudioInfo;
+
+/**
+* Enumerations for AMR bitrate
+*/
+typedef enum _MMStreamRecorderAMRBitRate {
+ MM_STREAMRECORDER_MR475, /**< MR475 : 4.75 kbit/s */
+ MM_STREAMRECORDER_MR515, /**< MR515 : 5.15 kbit/s */
+ MM_STREAMRECORDER_MR59, /**< MR59 : 5.90 kbit/s */
+ MM_STREAMRECORDER_MR67, /**< MR67 : 6.70 kbit/s */
+ MM_STREAMRECORDER_MR74, /**< MR74 : 7.40 kbit/s */
+ MM_STREAMRECORDER_MR795, /**< MR795 : 7.95 kbit/s */
+ MM_STREAMRECORDER_MR102, /**< MR102 : 10.20 kbit/s */
+ MM_STREAMRECORDER_MR122, /**< MR122 : 12.20 kbit/s */
+ MM_STREAMRECORDER_MRDTX /**< MRDTX */
+} MMStreamRecorderAMRBitRate;
+
+/*=======================================================================================
+| GLOBAL FUNCTION PROTOTYPES |
+========================================================================================*/
+
+int _mmstreamrecorder_check_audiocodec_fileformat_compatibility(unsigned int audio_codec, unsigned int file_format);
+
+int _mmstreamrecorder_get_amrnb_bitrate_mode(int bitrate);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MM_STREAMRECORDER_AUDIO_H__ */
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 __MM_STREAMRECORDER_BUFFER_MANAGER_H__
+#define __MM_STREAMRECORDER_BUFFER_MANAGER_H__
+
+/*=======================================================================================
+| INCLUDE FILES |
+========================================================================================*/
+#include <glib.h>
+#include <gst/gst.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=======================================================================================
+| GLOBAL DEFINITIONS AND DECLARATIONS FOR STREAMRECORDER |
+========================================================================================*/
+
+/*=======================================================================================
+| ENUM DEFINITIONS |
+========================================================================================*/
+
+/*=======================================================================================
+| STRUCTURE DEFINITIONS |
+========================================================================================*/
+
+typedef struct _GstStreamRecorderBuffer GstStreamRecorderBuffer;
+
+struct _GstStreamRecorderBuffer {
+ GstBuffer *buffer;
+ MMHandleType str_handle;
+ void *user_buffer;
+};
+
+/*=======================================================================================
+| CONSTANT DEFINITIONS |
+========================================================================================*/
+
+/*=======================================================================================
+| STATIC VARIABLES |
+========================================================================================*/
+
+/*=======================================================================================
+| EXTERN GLOBAL VARIABLE |
+========================================================================================*/
+
+/*=======================================================================================
+| GLOBAL FUNCTION PROTOTYPES |
+========================================================================================*/
+void _mmstreamrecorder_buffer_destroy(gpointer stream_buffer);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MM_STREAMRECORDER_BUFFER_MANAGER_H__ */
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 __MM_STREAMRECORDER_FILEINFO_H__
+#define __MM_STREAMRECORDER_FILEINFO_H__
+
+/*=======================================================================================
+| INCLUDE FILES |
+========================================================================================*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=======================================================================================
+| GLOBAL DEFINITIONS AND DECLARATIONS FOR STREAMRECORDER |
+========================================================================================*/
+
+/*=======================================================================================
+| MACRO DEFINITIONS |
+========================================================================================*/
+
+#define MMSTREAMRECORDER_FOURCC(a,b,c,d) (guint32)((a)|(b)<<8|(c)<<16|(d)<<24)
+#define MMSTREAMRECORDER_FOURCC_ARGS(fourcc) \
+ ((gchar)((fourcc)&0xff)), \
+ ((gchar)(((fourcc)>>8)&0xff)), \
+ ((gchar)(((fourcc)>>16)&0xff)), \
+ ((gchar)(((fourcc)>>24)&0xff))
+
+/*=======================================================================================
+| ENUM DEFINITIONS |
+========================================================================================*/
+/**
+ *Type define of util.
+ */
+#define _OFFSET_COMPOSITION_MATRIX 40L
+
+/*=======================================================================================
+| STRUCTURE DEFINITIONS |
+========================================================================================*/
+
+typedef struct {
+ char *filename; /**< recorded filename */
+ guint64 filesize; /**< current file size */
+ guint64 max_size; /**< max recording size */
+ guint64 max_time; /**< max recording time */
+ int fileformat; /**< recording file format */
+} _MMStreamRecorderFileInfo;
+
+/**
+ * Structure of location info
+ */
+typedef struct {
+ gint32 longitude;
+ gint32 latitude;
+ gint32 altitude;
+} _MMStreamRecorderLocationInfo;
+
+enum MMStreamReorderTagVideoOrientation {
+ MM_STREAMRECORDER_TAG_VIDEO_ORT_NONE = 0, /**< No Orientation.*/
+ MM_STREAMRECORDER_TAG_VIDEO_ORT_90, /**< 90 degree */
+ MM_STREAMRECORDER_TAG_VIDEO_ORT_180, /**< 180 degree */
+ MM_STREAMRECORDER_TAG_VIDEO_ORT_270, /**< 270 degree */
+};
+
+/*=======================================================================================
+| CONSTANT DEFINITIONS |
+========================================================================================*/
+
+/**
+ *
+ */
+#define MMFILE_FOURCC(a,b,c,d) (guint32)((a)|(b)<<8|(c)<<16|(d)<<24)
+#define MMFILE_FOURCC_ARGS(fourcc) \
+ ((gchar)((fourcc)&0xff)), \
+ ((gchar)(((fourcc)>>8)&0xff)), \
+ ((gchar)(((fourcc)>>16)&0xff)), \
+ ((gchar)(((fourcc)>>24)&0xff))
+
+/*=======================================================================================
+| GLOBAL FUNCTION PROTOTYPES |
+========================================================================================*/
+
+/* Recording */
+/* find top level tag only, do not use this function for finding sub level tags.
+ tag_fourcc is Four-character-code (FOURCC) */
+
+// READER
+gboolean _mmstreamrecorder_find_fourcc(FILE *f, guint32 tag_fourcc, gboolean do_rewind);
+gboolean _mmstreamrecorder_update_size(FILE *f, gint64 prev_pos, gint64 curr_pos);
+guint64 _mmstreamrecorder_get_container_size(const guchar *size);
+
+// WRITER
+// COMMON
+gboolean _mmstreamrecorder_write_udta(FILE *f, _MMStreamRecorderLocationInfo info);
+gboolean _mmstreamrecorder_update_size(FILE *f, gint64 prev_pos, gint64 curr_pos);
+
+// VIDEO FOURCC
+gboolean _mmstreamrecorder_write_udta(FILE *f, _MMStreamRecorderLocationInfo info);
+
+// AUDIO FOURCC
+gboolean _mmstreamrecorder_write_udta_m4a(FILE *f);
+gboolean _mmstreamrecorder_audio_add_metadata_info_m4a(MMHandleType handle);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MM_STREAMRECORDER_FILEINFO_H__ */
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 __MM_STREAMRECORDER_GSTCOMMON_H__
+#define __MM_STREAMRECORDER_GSTCOMMON_H__
+
+/*=======================================================================================
+| INCLUDE FILES |
+========================================================================================*/
+#include <mm_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=======================================================================================
+| GLOBAL DEFINITIONS AND DECLARATIONS FOR STREAMRECORDER |
+========================================================================================*/
+
+/*=======================================================================================
+| MACRO DEFINITIONS |
+========================================================================================*/
+
+/* gstreamer element creation macro */
+#define _MMSTREAMRECORDER_PIPELINE_MAKE(sub_context, element, eid, name /*char* */, err) \
+ if (element[eid].gst != NULL) { \
+ _mmstreamrec_dbg_err("The element(Pipeline) is existed. element_id=[%d], name=[%s]", eid, name); \
+ gst_object_unref(element[eid].gst); \
+ } \
+ element[eid].id = eid; \
+ element[eid].gst = gst_pipeline_new(name); \
+ if (element[eid].gst == NULL) { \
+ _mmstreamrec_dbg_err("Pipeline creation fail. element_id=[%d], name=[%s]", eid, name); \
+ err = MM_ERROR_STREAMRECORDER_RESOURCE_CREATION; \
+ goto pipeline_creation_error; \
+ } else { \
+ g_object_weak_ref(G_OBJECT(element[eid].gst), (GWeakNotify)_mmstreamrecorder_element_release_noti/*NULL*/, sub_context); \
+ }
+
+#define _MMSTREAMRECORDER_BIN_MAKE(sub_context, element, eid, name /*char* */, err) \
+ if (element[eid].gst != NULL) { \
+ _mmstreamrec_dbg_err("The element(Bin) is existed. element_id=[%d], name=[%s]", eid, name); \
+ gst_object_unref(element[eid].gst); \
+ } \
+ element[eid].id = eid; \
+ element[eid].gst = gst_bin_new(name); \
+ if (element[eid].gst == NULL) { \
+ _mmstreamrec_dbg_err("Bin creation fail. element_id=[%d], name=[%s]\n", eid, name); \
+ err = MM_ERROR_STREAMRECORDER_RESOURCE_CREATION; \
+ goto pipeline_creation_error; \
+ } else { \
+ g_object_weak_ref(G_OBJECT(element[eid].gst), (GWeakNotify)_mmstreamrecorder_element_release_noti/*NULL*/, sub_context); \
+ }
+
+#define _MMSTREAMRECORDER_ELEMENT_MAKE(sub_context, element, eid, name /*char* */, nickname /*char* */, elist, err) \
+ if (element[eid].gst != NULL) { \
+ _mmstreamrec_dbg_err("The element is existed. element_id=[%d], name=[%s]", eid, name); \
+ gst_object_unref(element[eid].gst); \
+ } \
+ element[eid].gst = gst_element_factory_make(name, nickname); \
+ if (element[eid].gst == NULL) { \
+ _mmstreamrec_dbg_err("Element creation fail. element_id=[%d], name=[%s]", eid, name); \
+ err = MM_ERROR_STREAMRECORDER_RESOURCE_CREATION; \
+ goto pipeline_creation_error; \
+ } else { \
+ _mmstreamrec_dbg_err("Element creation done. element_id=[%d], name=[%s]", eid, name); \
+ element[eid].id = eid; \
+ g_object_weak_ref(G_OBJECT(element[eid].gst), (GWeakNotify)_mmstreamrecorder_element_release_noti/*NULL*/, sub_context); \
+ err = MM_ERROR_NONE; \
+ } \
+ elist = g_list_append(elist, &(element[eid]));
+
+#define _MMSTREAMRECORDER_ELEMENT_MAKE_IGNORE_ERROR(sub_context, element, eid, name /*char* */, nickname /*char* */, elist) \
+ if (element[eid].gst != NULL) { \
+ _mmstreamrec_dbg_err("The element is existed. element_id=[%d], name=[%s]", eid, name); \
+ gst_object_unref(element[eid].gst); \
+ } \
+ element[eid].gst = gst_element_factory_make(name, nickname); \
+ if (element[eid].gst == NULL) { \
+ _mmstreamrec_dbg_err("Element creation fail. element_id=[%d], name=[%s], but keep going...", eid, name); \
+ } else { \
+ _mmstreamrec_dbg_err("Element creation done. element_id=[%d], name=[%s]", eid, name); \
+ element[eid].id = eid; \
+ g_object_weak_ref(G_OBJECT(element[eid].gst), (GWeakNotify)_mmstreamrecorder_element_release_noti/*NULL*/, sub_context); \
+ elist = g_list_append(elist, &(element[eid])); \
+ }
+
+#define _MMSTREAMRECORDER_ENCODEBIN_ELMGET(sub_context, eid, name /*char* */, err) \
+ if (sub_context->encode_element[eid].gst != NULL) { \
+ _mmstreamrec_dbg_err("The element is existed. element_id=[%d], name=[%s]", eid, name); \
+ gst_object_unref(sub_context->encode_element[eid].gst); \
+ } \
+ sub_context->encode_element[eid].id = eid; \
+ g_object_get(G_OBJECT(sub_context->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst), name, &(sub_context->encode_element[eid].gst), NULL); \
+ if (sub_context->encode_element[eid].gst == NULL) { \
+ _mmstreamrec_dbg_err("Encode Element get fail. element_id=[%d], name=[%s]", eid, name); \
+ err = MM_ERROR_STREAMRECORDER_RESOURCE_CREATION; \
+ goto pipeline_creation_error; \
+ } else{ \
+ gst_object_unref(sub_context->encode_element[eid].gst); \
+ g_object_weak_ref(G_OBJECT(sub_context->encode_element[eid].gst), (GWeakNotify)_mmstreamrecorder_element_release_noti/*NULL*/, sub_context); \
+ }
+
+/* GStreamer element remove macro */
+#define _MMSTREAMRECORDER_ELEMENT_REMOVE(element, eid) \
+ if (element[eid].gst != NULL) { \
+ gst_object_unref(element[eid].gst); \
+ }
+
+#define _MM_GST_ELEMENT_LINK_MANY gst_element_link_many
+#define _MM_GST_ELEMENT_LINK gst_element_link
+#define _MM_GST_PAD_LINK gst_pad_link
+
+#define _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, if_fail_goto)\
+{\
+ GstPadLinkReturn ret = _MM_GST_PAD_LINK(srcpad, sinkpad);\
+ if (ret != GST_PAD_LINK_OK) {\
+ GstObject *src_parent = gst_pad_get_parent(srcpad);\
+ GstObject *sink_parent = gst_pad_get_parent(sinkpad);\
+ char *src_name = NULL;\
+ char *sink_name = NULL;\
+ g_object_get((GObject *)src_parent, "name", &src_name, NULL);\
+ g_object_get((GObject *)sink_parent, "name", &sink_name, NULL);\
+ _mmstreamrec_dbg_err("src[%s] - sink[%s] link failed", src_name, sink_name);\
+ gst_object_unref(src_parent); src_parent = NULL;\
+ gst_object_unref(sink_parent); sink_parent = NULL;\
+ if (src_name) {\
+ free(src_name); src_name = NULL;\
+ }\
+ if (sink_name) {\
+ free(sink_name); sink_name = NULL;\
+ }\
+ gst_object_unref(srcpad); srcpad = NULL;\
+ gst_object_unref(sinkpad); sinkpad = NULL;\
+ err = MM_ERROR_STREAMRECORDER_GST_LINK;\
+ goto if_fail_goto;\
+ }\
+ gst_object_unref(srcpad); srcpad = NULL;\
+ gst_object_unref(sinkpad); sinkpad = NULL;\
+}
+
+#define _MM_GST_PAD_UNLINK_UNREF( srcpad, sinkpad) \
+ if (srcpad && sinkpad) { \
+ gst_pad_unlink(srcpad, sinkpad); \
+ } else { \
+ _mmstreamrec_dbg_warn("some pad(srcpad:%p,sinkpad:%p) is NULL", srcpad, sinkpad); \
+ } \
+ if (srcpad) { \
+ gst_object_unref(srcpad); srcpad = NULL; \
+ } \
+ if (sinkpad) { \
+ gst_object_unref(sinkpad); sinkpad = NULL; \
+ }
+
+/*=======================================================================================
+| ENUM DEFINITIONS |
+========================================================================================*/
+
+/**
+* Encodebin profile
+*/
+typedef enum _MMStreamRecorderEncodebinProfile {
+ MM_STREAMRECORDER_ENCBIN_PROFILE_VIDEO = 0, /**< Video recording profile */
+ MM_STREAMRECORDER_ENCBIN_PROFILE_AUDIO, /**< Audio recording profile */
+ MM_STREAMRECORDER_ENCBIN_PROFILE_IMAGE, /**< Image capture profile */
+ MM_STREAMRECORDER_ENCBIN_PROFILE_NUM
+} MMStreamRecorderEncodebinProfile;
+
+#define __MMSTREAMRECORDER_SET_GST_STATE_TIMEOUT 5
+
+/*=======================================================================================
+| STRUCTURE DEFINITIONS |
+========================================================================================*/
+/**
+ * Element name table.
+ * @note if name is NULL, not supported.
+ */
+typedef struct {
+ unsigned int prof_id; /**< id of mmstreamrecorder_profile_attrs_id */
+ unsigned int id; /**< id of value id */
+ char *name; /**< gstreamer element name*/
+} _MMStreamRecorderElementName;
+
+/**
+ * MMstreamrecorder Gstreamer Element
+ */
+typedef struct {
+ unsigned int id; /**< Gstreamer piplinem element name */
+ GstElement *gst; /**< Gstreamer element */
+} _MMStreamRecorderGstElement;
+
+/*=======================================================================================
+| CONSTANT DEFINITIONS |
+========================================================================================*/
+
+/*=======================================================================================
+| STATIC VARIABLES |
+========================================================================================*/
+
+/*=======================================================================================
+| EXTERN GLOBAL VARIABLE |
+========================================================================================*/
+
+/*=======================================================================================
+| GLOBAL FUNCTION PROTOTYPES |
+========================================================================================*/
+
+gboolean _mmstreamrecorder_gstreamer_init();
+
+/* etc */
+int _mmstreamrecorder_get_eos_message(MMHandleType handle);
+void _mmstreamrecorder_remove_element_handle(MMHandleType handle, void *element, int first_elem, int last_elem);
+gboolean _mmstreamrecorder_add_elements_to_bin(GstBin *bin, GList *element_list);
+gboolean _mmstreamrecorder_link_elements(GList *element_list);
+
+/**
+ * This function sets gstreamer element status.
+ * If the gstreamer fails to set status or returns asynchronous mode,
+ * this function waits for state changed until timeout expired.
+ *
+ * @param[in] pipeline Pointer of pipeline
+ * @param[in] target_state newly setting status
+ * @return This function returns zero on success, or negative value with error code.
+ * @remarks
+ * @see
+ *
+ */
+int _mmstreamrecorder_gst_set_state(MMHandleType handle, GstElement *pipeline, GstState target_state);
+GstCaps *gst_set_videosrcpad_caps(gint srcfmt, gint width, gint height, gint rate, gint scale);
+GstCaps *gst_set_audiosrcpad_caps(gint samplerate, gint channel, gint depth, gint width, gint datatype);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MM_STREAMRECORDER_GSTCOMMON_H__ */
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 __MM_STREAMRECORDER_GSTDISPATCH_H__
+#define __MM_STREAMRECORDER_GSTDISPATCH_H__
+
+/*=======================================================================================
+| INCLUDE FILES |
+========================================================================================*/
+#include "mm_streamrecorder_util.h"
+#include <gst/gst.h>
+#include <gst/gstutils.h>
+#include <gst/gstpad.h>
+#include <mm_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=======================================================================================
+| GLOBAL DEFINITIONS AND DECLARATIONS FOR STREAMRECORDER |
+========================================================================================*/
+
+/*=======================================================================================
+| MACRO DEFINITIONS |
+========================================================================================*/
+
+#define MMSTREAMRECORDER_ADD_BUFFER_PROBE(x_pad, x_category, x_callback, x_hstreamrecorder) \
+do { \
+ MMStreamRecorderHandlerItem *item = NULL; \
+ item = (MMStreamRecorderHandlerItem *)g_malloc(sizeof(MMStreamRecorderHandlerItem)); \
+ if (!item) {\
+ _mmstreamrec_dbg_err("Cannot connect buffer probe [malloc fail] \n"); \
+ } else if (x_category == 0 || !(x_category & _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL)) { \
+ _mmstreamrec_dbg_err("Invalid handler category : %x \n", x_category); \
+ } else { \
+ item->object = G_OBJECT(x_pad); \
+ item->category = x_category; \
+ item->handler_id = gst_pad_add_probe(x_pad,GST_PAD_PROBE_TYPE_BUFFER,x_callback, x_hstreamrecorder,NULL); \
+ x_hstreamrecorder->buffer_probes = g_list_append(x_hstreamrecorder->buffer_probes, item); \
+ _mmstreamrec_dbg_log("Adding buffer probe on [%s:%s] - [ID : %lu], [Category : %x] ", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category); \
+ } \
+} while (0);
+
+#define MMSTREAMRECORDER_ADD_EVENT_PROBE(x_pad, x_category, x_callback, x_hstreamrecorder) \
+do { \
+ MMStreamRecorderHandlerItem *item = NULL; \
+ item = (MMStreamRecorderHandlerItem *) g_malloc(sizeof(MMStreamRecorderHandlerItem)); \
+ if (!item) { \
+ _mmstreamrec_dbg_err("Cannot connect buffer probe [malloc fail] \n"); \
+ } \
+ else if (x_category == 0 || !(x_category & _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL)) { \
+ _mmstreamrec_dbg_err("Invalid handler category : %x \n", x_category); \
+ } else { \
+ item->object =G_OBJECT(x_pad); \
+ item->category = x_category; \
+ item->handler_id = gst_pad_add_probe(x_pad,GST_PAD_PROBE_TYPE_EVENT_BOTH,x_callback, x_hstreamrecorder,NULL); \
+ x_hstreamrecorder->event_probes = g_list_append(x_hstreamrecorder->event_probes, item); \
+ _mmstreamrec_dbg_log("Adding event probe on [%s:%s] - [ID : %lu], [Category : %x] ", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category); \
+ } \
+} while (0);
+
+#define MMSTREAMRECORDER_ADD_DATA_PROBE(x_pad, x_category, x_callback, x_hstreamrecorder) \
+do { \
+ MMStreamRecorderHandlerItem *item = NULL; \
+ item = (MMStreamRecorderHandlerItem *) g_malloc(sizeof(MMStreamRecorderHandlerItem)); \
+ if (!item) { \
+ _mmstreamrec_dbg_err("Cannot connect buffer probe [malloc fail] \n"); \
+ } else if (x_category == 0 || !(x_category & _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL)) { \
+ _mmstreamrec_dbg_err("Invalid handler category : %x \n", x_category); \
+ } else { \
+ item->object =G_OBJECT(x_pad); \
+ item->category = x_category; \
+ item->handler_id = gst_pad_add_data_probe(x_pad, G_CALLBACK(x_callback), x_hstreamrecorder); \
+ x_hstreamrecorder->data_probes = g_list_append(x_hstreamrecorder->data_probes, item); \
+ _mmstreamrec_dbg_log("Adding data probe on [%s:%s] - [ID : %lu], [Category : %x] ", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category); \
+ } \
+} while (0);
+
+#define MMSTREAMRECORDER_SIGNAL_CONNECT( x_object, x_category, x_signal, x_callback, x_hstreamrecorder) \
+do { \
+ MMStreamRecorderHandlerItem* item = NULL; \
+ item = (MMStreamRecorderHandlerItem *) g_malloc(sizeof(MMStreamRecorderHandlerItem)); \
+ if (!item) { \
+ _mmstreamrec_dbg_err("Cannot connect signal [%s]\n", x_signal ); \
+ } else if (x_category == 0 || !(x_category & _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL)) { \
+ _mmstreamrec_dbg_err("Invalid handler category : %x \n", x_category); \
+ } else { \
+ item->object = G_OBJECT(x_object); \
+ item->category = x_category; \
+ item->handler_id = g_signal_connect(G_OBJECT(x_object), x_signal,\
+ G_CALLBACK(x_callback), x_hstreamrecorder ); \
+ x_hstreamrecorder->signals = g_list_append(x_hstreamrecorder->signals, item); \
+ _mmstreamrec_dbg_log("Connecting signal on [%s] - [ID : %lu], [Category : %x] ", GST_OBJECT_NAME(item->object), item->handler_id, item->category); \
+ } \
+} while (0);
+
+#define MMSTREAMRECORDER_G_OBJECT_GET(obj, name, value) \
+do { \
+ if (obj) { \
+ if(g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(obj)), name)) { \
+ g_object_get(G_OBJECT(obj), name, value, NULL); \
+ } else { \
+ _mmstreamrec_dbg_warn ("The object doesn't have a property named(%s)", name); \
+ } \
+ } else { \
+ _mmstreamrec_dbg_err("Null object"); \
+ } \
+} while(0);
+
+#define MMSTREAMRECORDER_G_OBJECT_SET(obj, name, value) \
+do { \
+ if (obj) { \
+ if(g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(obj)), name)) { \
+ g_object_set(G_OBJECT(obj), name, value, NULL); \
+ } else { \
+ _mmstreamrec_dbg_warn ("The object doesn't have a property named(%s)", name); \
+ } \
+ } else { \
+ _mmstreamrec_dbg_err("Null object"); \
+ } \
+} while(0);
+
+#define MMSTREAMRECORDER_SEND_MESSAGE(handle, msg_id, msg_code) \
+{\
+ _MMStreamRecorderMsgItem msg;\
+ msg.id = msg_id;\
+ msg.param.code = msg_code;\
+ _mmstreamrec_dbg_log("msg id : %x, code : %x", msg_id, msg_code);\
+ _mmstreamrecorder_send_message((MMHandleType)handle, &msg);\
+}
+
+/*=======================================================================================
+| ENUM DEFINITIONS |
+========================================================================================*/
+/**
+ *Type define of util.
+ */
+typedef enum {
+ _MMSTREAMRECORDER_HANDLER_VIDEOREC = (1 << 0),
+ _MMSTREAMRECORDER_HANDLER_AUDIOREC = (1 << 1),
+} _MMStreamRecorderHandlerCategory;
+
+/*=======================================================================================
+| STRUCTURE DEFINITIONS |
+========================================================================================*/
+
+/**
+ * Structure of handler item
+ */
+typedef struct {
+ GObject *object;
+ _MMStreamRecorderHandlerCategory category;
+ gulong handler_id;
+} MMStreamRecorderHandlerItem;
+
+/**
+ * Structure of message item
+ */
+typedef struct {
+ MMHandleType handle; /**< handle */
+ int id; /**< message id */
+ MMMessageParamType param;
+ /**< message parameter */
+} _MMStreamRecorderMsgItem;
+
+/*=======================================================================================
+| CONSTANT DEFINITIONS |
+========================================================================================*/
+#define _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL \
+ (_MMSTREAMRECORDER_HANDLER_VIDEOREC | _MMSTREAMRECORDER_HANDLER_AUDIOREC)
+
+/*=======================================================================================
+| GLOBAL FUNCTION PROTOTYPES |
+========================================================================================*/
+/* GStreamer */
+void _mmstreamrecorder_remove_buffer_probe(MMHandleType handle, _MMStreamRecorderHandlerCategory category);
+void _mmstreamrecorder_remove_event_probe(MMHandleType handle, _MMStreamRecorderHandlerCategory category);
+void _mmstreamrecorder_remove_data_probe(MMHandleType handle, _MMStreamRecorderHandlerCategory category);
+void _mmstreamrecorder_disconnect_signal(MMHandleType handle, _MMStreamRecorderHandlerCategory category);
+void _mmstreamrecorder_element_release_noti(gpointer data, GObject *where_the_object_was);
+
+/* Message */
+gboolean _mmstreamrecorder_msg_callback(void *data);
+gboolean _mmstreamrecorder_send_message(MMHandleType handle, _MMStreamRecorderMsgItem *data);
+gboolean _mmstreamrecorder_remove_message_all(MMHandleType handle);
+
+gboolean _mmstreamrecorder_handle_gst_error(MMHandleType handle, GstMessage *message, GError *error);
+gint _mmstreamrecorder_gst_handle_stream_error(MMHandleType handle, int code, GstMessage *message);
+gint _mmstreamrecorder_gst_handle_resource_error(MMHandleType handle, int code, GstMessage *message);
+gint _mmstreamrecorder_gst_handle_library_error(MMHandleType handle, int code, GstMessage *message);
+gint _mmstreamrecorder_gst_handle_core_error(MMHandleType handle, int code, GstMessage *message);
+gboolean _mmstreamrecorder_handle_gst_warning(MMHandleType handle, GstMessage *message, GError *error);
+void _mmstreamrecorder_remove_all_handlers(MMHandleType handle, _MMStreamRecorderHandlerCategory category);
+
+/**
+ * This function is callback function of main pipeline.
+ * Once this function is registered with certain pipeline using gst_bus_add_watch(),
+ * this callback will be called every time when there is upcomming message from pipeline.
+ * Basically, this function is used as error handling function, now.
+ *
+ * @param[in] bus pointer of buf that called this function.
+ * @param[in] message callback message from pipeline.
+ * @param[in] data user data.
+ * @return This function returns true on success, or false value with error
+ * @remarks
+ * @see __mmstreamrecorder_create_preview_pipeline()
+ *
+ */
+gboolean _mmstreamrecorder_pipeline_cb_message(GstBus *bus, GstMessage *message, gpointer data);
+
+GstPadProbeReturn __mmstreamrecorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
+
+GstPadProbeReturn __mmstreamrecorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
+
+GstPadProbeReturn __mmstreamrecorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
+
+GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
+
+GstPadProbeReturn __mmstreamrecorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
+
+GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
+void __mmstreamrecorder_audiorec_pad_added_cb(GstElement *element, GstPad *pad, MMHandleType handle);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MM_STREAMRECORDER_GSTDISPATCH_H__ */
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 __MM_STREAMRECORDER_INI_H__
+#define __MM_STREAMRECORDER_INI_H__
+
+#include <glib.h>
+#include "mm_debug.h"
+#include "mm_streamrecorder.h"
+#include "mm_streamrecorder_util.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MM_STREAMRECORDER_INI_DEFAULT_PATH "/usr/etc/mmfw_streamrecorder.ini"
+
+#define STREAMRECORDER_INI_MAX_STRLEN 256
+#define STREAMRECORDER_INI_MAX_ELEMENT 10
+#define STREAMRECORDER_ATTRIBUTE_NUM_MAX 8
+
+enum keyword_type {
+ KEYWORD_VIDEO_WIDTH,
+ KEYWORD_VIDEO_HEIGHT,
+ KEYWORD_AUDIO_ENCODERS,
+ KEYWORD_VIDEO_ENCODERS,
+ KEYWORD_FILE_FORMATS,
+};
+
+typedef struct __mm_streamrecorder_ini {
+ /* general */
+ gboolean encsink_src_islive;
+ guint retrial_count;
+ guint minimum_frame;
+ guint convert_output_buffer_num;
+ guint reset_pause_time;
+ guint screen_record;
+
+ /*encodebin */
+ guint encsink_bin_profile;
+ gboolean encsink_bin_auto_audio_resample;
+ gboolean encsink_bin_auto_colorspace;
+ gboolean encsink_bin_auto_audio_convert;
+ gboolean encsink_bin_use_video_toggle;
+
+ /* pipeline */
+ gchar name_of_encsink_src[STREAMRECORDER_INI_MAX_STRLEN];
+ gchar name_of_audio_src[STREAMRECORDER_INI_MAX_STRLEN];
+ gchar h264_video_encoder[STREAMRECORDER_INI_MAX_STRLEN];
+ gchar h263_video_encoder[STREAMRECORDER_INI_MAX_STRLEN];
+ gchar mpeg4_video_encoder[STREAMRECORDER_INI_MAX_STRLEN];
+ gchar name_of_encsink_bin_audio_encoder[STREAMRECORDER_INI_MAX_STRLEN];
+ gchar name_of_encsink_bin_video_converter[STREAMRECORDER_INI_MAX_STRLEN];
+ gchar encsink_bin_use_parser[STREAMRECORDER_INI_MAX_STRLEN];
+ gchar name_of_encsink_bin_3GPMUXER[STREAMRECORDER_INI_MAX_STRLEN];
+ gchar name_of_encsink_bin_MP4MUXER[STREAMRECORDER_INI_MAX_STRLEN];
+ gchar name_of_encsink_sink[STREAMRECORDER_INI_MAX_STRLEN];
+
+ /* audio parameter */
+ guint audio_frame_minimum_space;
+ guint audio_frame_wait_time;
+
+ /* video parameter */
+ guint video_frame_wait_time;
+
+ /*list attributed*/
+ gint supported_video_width[STREAMRECORDER_ATTRIBUTE_NUM_MAX];
+ gint supported_video_height[STREAMRECORDER_ATTRIBUTE_NUM_MAX];
+ gchar supported_audio_encoders[STREAMRECORDER_ATTRIBUTE_NUM_MAX][STREAMRECORDER_INI_MAX_STRLEN];
+ gchar supported_video_encoders[STREAMRECORDER_ATTRIBUTE_NUM_MAX][STREAMRECORDER_INI_MAX_STRLEN];
+ gchar supported_file_formats[STREAMRECORDER_ATTRIBUTE_NUM_MAX][STREAMRECORDER_INI_MAX_STRLEN];
+
+} mm_streamrecorder_ini_t;
+
+/*Default sink ini values*/
+/* General*/
+#define DEFAULT_ENCSINK_SRC_IS_LIVE FALSE
+#define DEFAULT_RETRIAL_COUNT 10
+#define DEFAULT_MINIMUM_FRAME 5
+#define DEFAULT_CONVERT_OUTPUT_BUFFER_NUM 6
+#define DEFAULT_RESET_PAUSE_TIME 0
+#define DEFAULT_SCREEN_RECORD 1
+
+/*encodebin*/
+#define DEFAULT_ENCSINK_BIN_PROFILE 0
+#define DEFAULT_ENCSINK_BIN_AUTO_AUDIO_RESAMPLE FALSE
+#define DEFAULT_ENCSINK_BIN_AUTO_COLORSPACE TRUE
+#define DEFAULT_ENCSINK_BIN_AUTO_CONVERT TRUE
+#define DEFAULT_ENCSINK_BIN_USE_VIDEO_TOGGLE FALSE
+
+/* Pipeline */
+#define DEFAULT_VIDEO_SOURCE "appsrc"
+#define DEFAULT_AUDIO_SRC "pulsesrc"
+#define DEFAULT_NAME_OF_H264_VIDEO_ENCODER "omx_h264enc"
+#define DEFAULT_NAME_OF_H263_VIDEO_ENCODER "avenc_h263p"
+#define DEFAULT_NAME_OF_MPEG4_VIDEO_ENCODER "avenc_mpeg4"
+#define DEFAULT_NAME_OF_AUDIO_ENCODER "avenc_aac"
+#define DEFAULT_USE_PARSER ""
+#define DEFAULT_NAME_OF_3GP_MUXER "avmux_3gp"
+#define DEFAULT_NAME_OF_MP4_MUXER "avmux_mp4"
+#define DEFAULT_NAME_OF_VIDEO_CONVERTER "videoconvet"
+#define DEFAULT_NAME_OF_BIN_SINK "filesink"
+
+/*audio param*/
+#define DEFAULT_AUDIO_FRAME_MINIMUM_SPACE 102400
+#define DEFAULT_AUDIO_FRAME_WAIT_TIME 20000
+
+/*video param*/
+#define DEFAULT_VIDEO_FRAME_WAIT_TIME 200000
+
+/*supported attribute*/
+#define DEFAULT_SUPPORTED_WIDTH ""
+#define DEFAULT_SUPPORTED_HEIGHT ""
+#define DEFAULT_SUPPORTED_AUDIO_ENCODERS ""
+#define DEFAULT_SUPPORTED_VIDEO_ENCODERS ""
+#define DEFAULT_SUPPORTED_FILE_FORMATS ""
+
+#define MM_STREAMRECORDER_DEFAULT_INI \
+" \
+[general]\n\
+\n\
+retrialcount =10\n\
+\n\
+minimum frame =5\n\
+\n\
+reset pause time = 0 \n\
+\n\
+screen record =0 \n\
+\n\
+convert output buffer num =6\n\
+\n\
+[encodebin]\n\
+\n\
+encsink bin profile = 0 \n\
+\n\
+encsink source auto audio resample = 0\n\
+\n\
+encsink source auto audio colorsapce = 0 \n\
+\n\
+encsink source auto audio convert =1\n\
+\n\
+encsink source use video toggle = 1\n\
+\n\
+[pipeline]\n\
+\n\
+encsink bin source = xvimagesrc\n\
+\n\
+name of audio src \n\
+\n\
+h264 encoder = omx_h264enc\n\
+\n\
+h263 encoder = omx_h263enc\n\
+\n\
+mpeg4 encoder = omx_mpeg4enc\n\
+\n\
+name of audio encoder =savsenc_aac\n\
+\n\
+name of 3GP muxer =ffmux_3gp\n\
+\n\
+use parser= \n\
+\n\
+name of MP4 muxer =ffmux_mp4\n\
+\n\
+name of video converter\n\
+\n\
+name of sink = filesink \n\
+\n\
+[video param]\n\
+\n\
+video frame wait time = 200000\n\
+\n\
+[audio param]\n\
+\n\
+audio frame minimum space = 102400\n\
+\n\
+audio frame wait time = 20000\n\
+\n\
+supported width = ""\n\
+\n\
+supported height = ""\n\
+\n\
+supported audio encoders = ""\n\
+\n\
+supported video encoders = ""\n\
+\n\
+supported file formats = ""\n\
+\n\
+"
+
+int
+ _mm_streamrecorder_ini_load(mm_streamrecorder_ini_t * ini);
+
+int
+ _mm_streamrecorder_ini_unload(mm_streamrecorder_ini_t * ini);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 __MM_STREAMRECORDER_INTERNAL_H__
+#define __MM_STREAMRECORDER_INTERNAL_H__
+
+/*=======================================================================================
+| INCLUDE FILES |
+========================================================================================*/
+#include <malloc.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include <mm_types.h>
+#include <mm_attrs.h>
+#include <mm_attrs_private.h>
+#include <mm_message.h>
+
+#include "mm_streamrecorder.h"
+#include <gst/gst.h>
+
+/* streamrecorder sub module */
+#include "mm_streamrecorder_util.h"
+#include "mm_streamrecorder_video.h"
+#include "mm_streamrecorder_audio.h"
+#include "mm_streamrecorder_fileinfo.h"
+#include "mm_streamrecorder_gstcommon.h"
+#include "mm_streamrecorder_ini.h"
+#include "mm_streamrecorder_buffer_manager.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=======================================================================================
+| MACRO DEFINITIONS |
+========================================================================================*/
+
+#ifndef ARRAY_SIZE
+/**
+ * Macro for getting array size
+ */
+#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
+#endif
+
+#define _MMSTREAMRECORDER_STATE_SET_COUNT 3 /* checking interval */
+#define _MMSTREAMRECORDER_STATE_CHECK_INTERVAL 1000 //5000 /* checking interval */
+
+/**
+ * Functions related with LOCK and WAIT
+ */
+#define _MMSTREAMRECORDER_CAST_MTSAFE(handle) (((mmf_streamrecorder_t*)handle)->mtsafe)
+#define _MMSTREAMRECORDER_LOCK_FUNC(mutex) pthread_mutex_lock(&mutex)
+#define _MMSTREAMRECORDER_TRYLOCK_FUNC(mutex) (!pthread_mutex_trylock(&mutex))
+#define _MMSTREAMRECORDER_UNLOCK_FUNC(mutex) pthread_mutex_unlock(&mutex)
+
+#define _MMSTREAMRECORDER_GET_LOCK(handle) (_MMSTREAMRECORDER_CAST_MTSAFE(handle).lock)
+#define _MMSTREAMRECORDER_LOCK(handle) _MMSTREAMRECORDER_LOCK_FUNC(_MMSTREAMRECORDER_GET_LOCK(handle))
+#define _MMSTREAMRECORDER_TRYLOCK(handle) _MMSTREAMRECORDER_TRYLOCK_FUNC(_MMSTREAMRECORDER_GET_LOCK(handle))
+#define _MMSTREAMRECORDER_UNLOCK(handle) _MMSTREAMRECORDER_UNLOCK_FUNC(_MMSTREAMRECORDER_GET_LOCK(handle))
+
+#define _MMSTREAMRECORDER_GET_COND(handle) (_MMSTREAMRECORDER_CAST_MTSAFE(handle).cond)
+#define _MMSTREAMRECORDER_WAIT(handle) pthread_cond_wait(&_MMSTREAMRECORDER_GET_COND(handle), _MMSTREAMRECORDER_GET_LOCK(handle))
+#define _MMSTREAMRECORDER_TIMED_WAIT(handle, timeout) pthread_cond_timedwait(&_MMSTREAMRECORDER_GET_COND(handle), _MMSTREAMRECORDER_GET_LOCK(handle),&timeout)
+
+/* for command */
+#define _MMSTREAMRECORDER_GET_CMD_LOCK(handle) (_MMSTREAMRECORDER_CAST_MTSAFE(handle).cmd_lock)
+#define _MMSTREAMRECORDER_LOCK_CMD(handle) _MMSTREAMRECORDER_LOCK_FUNC(_MMSTREAMRECORDER_GET_CMD_LOCK(handle))
+#define _MMSTREAMRECORDER_TRYLOCK_CMD(handle) _MMSTREAMRECORDER_TRYLOCK_FUNC(_MMSTREAMRECORDER_GET_CMD_LOCK(handle))
+#define _MMSTREAMRECORDER_UNLOCK_CMD(handle) _MMSTREAMRECORDER_UNLOCK_FUNC(_MMSTREAMRECORDER_GET_CMD_LOCK(handle))
+
+/* for state change */
+#define _MMSTREAMRECORDER_GET_STATE_LOCK(handle) (_MMSTREAMRECORDER_CAST_MTSAFE(handle).state_lock)
+#define _MMSTREAMRECORDER_LOCK_STATE(handle) _MMSTREAMRECORDER_LOCK_FUNC(_MMSTREAMRECORDER_GET_STATE_LOCK(handle))
+#define _MMSTREAMRECORDER_TRYLOCK_STATE(handle) _MMSTREAMRECORDER_TRYLOCK_FUNC(_MMSTREAMRECORDER_GET_STATE_LOCK(handle))
+#define _MMSTREAMRECORDER_UNLOCK_STATE(handle) _MMSTREAMRECORDER_UNLOCK_FUNC(_MMSTREAMRECORDER_GET_STATE_LOCK(handle))
+
+/* for gstreamer state change */
+#define _MMSTREAMRECORDER_GET_GST_STATE_LOCK(handle) (_MMSTREAMRECORDER_CAST_MTSAFE(handle).gst_state_lock)
+#define _MMSTREAMRECORDER_LOCK_GST_STATE(handle) _MMSTREAMRECORDER_LOCK_FUNC(_MMSTREAMRECORDER_GET_GST_STATE_LOCK(handle))
+#define _MMSTREAMRECORDER_TRYLOCK_GST_STATE(handle) _MMSTREAMRECORDER_TRYLOCK_FUNC(_MMSTREAMRECORDER_GET_GST_STATE_LOCK(handle))
+#define _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle) _MMSTREAMRECORDER_UNLOCK_FUNC(_MMSTREAMRECORDER_GET_GST_STATE_LOCK(handle))
+
+/* for setting/calling callback */
+#define _MMSTREAMRECORDER_GET_MESSAGE_CALLBACK_LOCK(handle) (_MMSTREAMRECORDER_CAST_MTSAFE(handle).message_cb_lock)
+#define _MMSTREAMRECORDER_LOCK_MESSAGE_CALLBACK(handle) _MMSTREAMRECORDER_LOCK_FUNC(_MMSTREAMRECORDER_GET_MESSAGE_CALLBACK_LOCK(handle))
+#define _MMSTREAMRECORDER_TRYLOCK_MESSAGE_CALLBACK(handle) _MMSTREAMRECORDER_TRYLOCK_FUNC(_MMSTREAMRECORDER_GET_MESSAGE_CALLBACK_LOCK(handle))
+#define _MMSTREAMRECORDER_UNLOCK_MESSAGE_CALLBACK(handle) _MMSTREAMRECORDER_UNLOCK_FUNC(_MMSTREAMRECORDER_GET_MESSAGE_CALLBACK_LOCK(handle))
+
+/**
+ * Caster of main handle (streamrecorder)
+ */
+#define MMF_STREAMRECORDER(h) (mmf_streamrecorder_t *)(h)
+
+/**
+ * Caster of subcontext
+ */
+#define MMF_STREAMRECORDER_SUBCONTEXT(h) (((mmf_streamrecorder_t *)(h))->sub_context)
+
+/* LOCAL CONSTANT DEFINITIONS */
+
+/*=======================================================================================
+| ENUM DEFINITIONS |
+========================================================================================*/
+
+/**
+ * streamrecorder Pipeline's Element name.
+ * @note index of element.
+ */
+typedef enum {
+ _MMSTREAMRECORDER_ENCODE_NONE = (-1),
+
+ /* Main Pipeline Element */
+ _MMSTREAMRECORDER_ENCODE_MAIN_PIPE = 0x00,
+
+ /* Pipeline element of Audio input */
+ _MMSTREAMRECORDER_AUDIOSRC_BIN,
+ _MMSTREAMRECORDER_AUDIOSRC_SRC, /* appsrc */
+ _MMSTREAMRECORDER_AUDIOSRC_FILT,
+
+ /* Pipeline element of Encodebin */
+ _MMSTREAMRECORDER_ENCSINK_BIN,
+ _MMSTREAMRECORDER_ENCSINK_SRC, /* video appsrc */
+ _MMSTREAMRECORDER_ENCSINK_FILT,
+ _MMSTREAMRECORDER_ENCSINK_ENCBIN,
+ _MMSTREAMRECORDER_ENCSINK_AQUE,
+ _MMSTREAMRECORDER_ENCSINK_CONV,
+ _MMSTREAMRECORDER_ENCSINK_AENC,
+ _MMSTREAMRECORDER_ENCSINK_AENC_QUE,
+ _MMSTREAMRECORDER_ENCSINK_VQUE,
+ _MMSTREAMRECORDER_ENCSINK_VCONV,
+ _MMSTREAMRECORDER_ENCSINK_VENC,
+ _MMSTREAMRECORDER_ENCSINK_VENC_QUE,
+ _MMSTREAMRECORDER_ENCSINK_PARSER,
+ _MMSTREAMRECORDER_ENCSINK_ITOG,
+ _MMSTREAMRECORDER_ENCSINK_ICROP,
+ _MMSTREAMRECORDER_ENCSINK_ISCALE,
+ _MMSTREAMRECORDER_ENCSINK_IFILT,
+ _MMSTREAMRECORDER_ENCSINK_IQUE,
+ _MMSTREAMRECORDER_ENCSINK_IENC,
+ _MMSTREAMRECORDER_ENCSINK_MUX,
+ _MMSTREAMRECORDER_ENCSINK_SINK,
+
+ _MMSTREAMRECORDER_ENCODE_PIPELINE_ELEMENT_NUM,
+} _MMSTREAMRECORDER_ENCODE_PIPELINE_ELELMENT;
+
+/**
+ * Command type for streamrecorder.
+ */
+
+typedef enum {
+ _MM_STREAMRECORDER_CMD_CREATE,
+ _MM_STREAMRECORDER_CMD_DESTROY,
+ _MM_STREAMRECORDER_CMD_REALIZE,
+ _MM_STREAMRECORDER_CMD_UNREALIZE,
+ _MM_STREAMRECORDER_CMD_START,
+ _MM_STREAMRECORDER_CMD_STOP,
+ _MM_STREAMRECORDER_CMD_RECORD,
+ _MM_STREAMRECORDER_CMD_PAUSE,
+ _MM_STREAMRECORDER_CMD_COMMIT,
+ _MM_STREAMRECORDER_CMD_CANCEL,
+ _MM_STREAMRECORDER_CMD_QUIT,
+} _MMstreamrecorderCommandType;
+
+/**
+ * System state change cause
+ */
+typedef enum {
+ _MMSTREAMRECORDER_STATE_CHANGE_NORMAL = 0,
+} _MMstreamrecorderStateChange;
+
+
+/*=======================================================================================
+| STRUCTURE DEFINITIONS |
+========================================================================================*/
+
+/**
+ * MMstreamrecorder information for Multi-Thread Safe
+ */
+typedef struct {
+ pthread_mutex_t lock; /**< Mutex (for general use) */
+ pthread_cond_t cond; /**< Condition (for general use) */
+ pthread_mutex_t cmd_lock; /**< Mutex (for command) */
+ pthread_mutex_t state_lock; /**< Mutex (for state change) */
+ pthread_mutex_t gst_state_lock; /**< Mutex (for state change) */
+ pthread_mutex_t message_cb_lock;/**< Mutex (for message callback) */
+} _MMStreamRecorderMTSafe;
+
+/**
+ * MMstreamrecorder information for command loop
+ */
+
+/**
+ * MMstreamrecorder Sub Context
+ */
+typedef struct {
+ bool isMaxsizePausing; /**< Because of size limit, pipeline is paused. */
+ bool isMaxtimePausing; /**< Because of time limit, pipeline is paused. */
+ int encode_element_num; /**< count of encode element */
+ GstClockTime pipeline_time; /**< current time of Gstreamer Pipeline */
+ GstClockTime pause_time; /**< amount of time while pipeline is in PAUSE state.*/
+ gboolean error_occurs; /**< flag for error */
+ int error_code; /**< error code for internal gstreamer error */
+ gboolean ferror_send; /**< file write/seek error **/
+ guint ferror_count; /**< file write/seek error count **/
+ gboolean bget_eos; /**< Whether getting EOS */
+ gboolean video_enable; /**< whether video is disabled or not when record */
+ gboolean audio_enable; /**< whether audio is disabled or not when record */
+
+ /* INI information */
+ unsigned int fourcc; /**< Get fourcc value */
+ _MMStreamRecorderVideoInfo *info_video; /**< extra information for video recording */
+ _MMStreamRecorderAudioInfo *info_audio; /**< extra information for audio recording */
+ _MMStreamRecorderFileInfo *info_file; /**< extra information for audio recording */
+ _MMStreamRecorderGstElement *encode_element;
+ /**< array of encode element */
+
+// type_element *VideosinkElement; /**< configure data of videosink element */
+} _MMStreamRecorderSubContext;
+
+/**
+ * _MMstreamrecorderContext
+ */
+typedef struct mmf_streamrecorder {
+ /* information */
+ // int type; /**< mmstreamrecorder_mode_type */
+ int state; /**< state of streamrecorder */
+ // int target_state; /**< Target state that want to set. This is a flag that
+ // * stands for async state changing. If this value differ from state,
+ // * it means state is changing now asychronously. */
+
+ /* handles */
+ MMHandleType attributes; /**< Attribute handle */
+ _MMStreamRecorderSubContext *sub_context; /**< sub context */
+ GList *buffer_probes; /**< a list of buffer probe handle */
+ GList *event_probes; /**< a list of event probe handle */
+ GList *data_probes; /**< a list of data probe handle */
+ GList *signals; /**< a list of signal handle */
+ GList *msg_data; /**< a list of msg data */
+ guint pipeline_cb_event_id; /**< Event source ID of pipeline message callback */
+ guint encode_pipeline_cb_event_id; /**< Event source ID of encode pipeline message callback */
+
+ /* callback handlers */
+ MMMessageCallback msg_cb; /**< message callback */
+ void *msg_cb_param; /**< message callback parameter */
+ int (*command) (MMHandleType, int); /**< streamrecorder's command */
+
+ /* etc */
+ _MMStreamRecorderMTSafe mtsafe; /**< Thread safe */
+ mm_streamrecorder_ini_t ini;
+
+ int reserved[4]; /**< reserved */
+} mmf_streamrecorder_t;
+
+/*=======================================================================================
+| EXTERN GLOBAL VARIABLE |
+========================================================================================*/
+
+/*=======================================================================================
+| GLOBAL FUNCTION PROTOTYPES |
+========================================================================================*/
+/**
+ * This function creates streamrecorder for capturing still image and recording.
+ *
+ * @param[out] handle Specifies the streamrecorder handle
+ * @param[in] info Preset information of streamrecorder
+ * @return This function returns zero on success, or negative value with error code.
+ * @remarks When this function calls successfully, streamrecorder handle will be filled with a @n
+ * valid value and the state of the streamrecorder will become MM_streamrecorder_STATE_NULL.@n
+ * Note that it's not ready to working streamrecorder. @n
+ * You should call mmstreamrecorder_realize before starting streamrecorder.
+ * @see _mmstreamrecorder_create
+ */
+int _mmstreamrecorder_create(MMHandleType *handle);
+
+/**
+* This function gets the current state of streamreccorder.
+* mm_streamrecorderr is working on the base of its state. An user should check the state of mm_streamrecorder before calling its functions.
+* If the handle is avaiable, user can retrieve the value.
+*
+* @param[in] streamrecorder A handle of streamrecorder.
+* @param[out] state On return, it contains current state of streamrecorder.
+* @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.
+* Please refer 'mm_error.h' to know the exact meaning of the error.
+* @see MMStreamRecorderStateType
+* @pre None
+* @post None
+* @remarks None
+*/
+
+MMStreamRecorderStateType _mmstreamrecorder_get_state(MMHandleType handle);
+
+/**
+ * This function destroys instance of streamrecorder.
+ *
+ * @param[in] hstreamrecorder Specifies the streamrecorder handle
+ * @return This function returns zero on success, or negative value with error code.
+ * @see _mmstreamrecorder_create
+ */
+int _mmstreamrecorder_destroy(MMHandleType handle);
+
+/**
+ * This function allocates memory for streamrecorder.
+ *
+ * @param[in] hstreamrecorder Specifies the streamrecorder handle
+ * @return This function returns zero on success, or negative value with error code.
+ * @remarks This function can be called successfully when current state is MM_streamrecorder_STATE_NULL @n
+ * and the state of the streamrecorder will become MM_streamrecorder_STATE_READY. @n
+ * Otherwise, this function will return MM_ERROR_streamrecorder_INVALID_CONDITION.
+ * @see _mmstreamrecorder_unrealize
+ * @pre MM_streamrecorder_STATE_NULL
+ * @post MM_streamrecorder_STATE_READY
+ */
+int _mmstreamrecorder_realize(MMHandleType hstreamrecorder);
+
+/**
+ * This function free allocated memory for streamrecorder.
+ *
+ * @param[in] hstreamrecorder Specifies the streamrecorder handle
+ * @return This function returns zero on success, or negative value with error code.
+ * @remarks This function release all resources which are allocated for the streamrecorder engine.@n
+ * This function can be called successfully when current state is MM_streamrecorder_STATE_READY and @n
+ * the state of the streamrecorder will become MM_streamrecorder_STATE_NULL. @n
+ * Otherwise, this function will return MM_ERROR_streamrecorder_INVALID_CONDITION.
+ * @see _mmstreamrecorder_realize
+ * @pre MM_streamrecorder_STATE_READY
+ * @post MM_streamrecorder_STATE_NULL
+ */
+int _mmstreamrecorder_unrealize(MMHandleType hstreamrecorder);
+
+/**
+ * This function is to start previewing.
+ *
+ * @param[in] hstreamrecorder Specifies the streamrecorder handle
+ * @return This function returns zero on success, or negative value with error code.
+ * @remarks This function can be called successfully when current state is MM_streamrecorder_STATE_READY and @n
+ * the state of the streamrecorder will become MM_streamrecorder_STATE_PREPARE. @n
+ * Otherwise, this function will return MM_ERROR_streamrecorder_INVALID_CONDITION.
+ * @see _mmstreamrecorder_stop
+ */
+int _mmstreamrecorder_record(MMHandleType hstreamrecorder);
+
+int _mmstreamrecorder_push_stream_buffer(MMHandleType handle, MMStreamRecorderStreamType streamtype, unsigned long timestamp, void *buffer, int size);
+
+/**
+ * This function is to pause video and audio recording
+ *
+ * @param[in] hstreamrecorder Specifies the streamrecorder handle
+ * @return This function returns zero on success, or negative value with error code.
+ * @remarks This function can be called successfully when current state is MM_streamrecorder_STATE_RECORDING and @n
+ * the state of the streamrecorder will become MM_streamrecorder_STATE_PAUSED.@n
+ * Otherwise, this function will return MM_ERROR_streamrecorder_INVALID_CONDITION.@n
+ * @see _mmstreamrecorder_record
+ */
+int _mmstreamrecorder_pause(MMHandleType hstreamrecorder);
+
+/**
+ * This function is to stop video and audio recording and save results.
+ *
+ * @param[in] hstreamrecorder Specifies the streamrecorder handle
+ * @return This function returns zero on success, or negative value with error code.
+ * @remarks This function can be called successfully when current state is @n
+ * MM_streamrecorder_STATE_PAUSED or MM_streamrecorder_STATE_RECORDING and @n
+ * the state of the streamrecorder will become MM_streamrecorder_STATE_PREPARE. @n
+ * Otherwise, this function will return MM_ERROR_streamrecorder_INVALID_CONDITION
+ * @see _mmstreamrecorder_cancel
+ */
+int _mmstreamrecorder_commit(MMHandleType hstreamrecorder);
+
+/**
+ * This function is to stop video and audio recording and do not save results.
+ *
+ * @param[in] hstreamrecorder Specifies the streamrecorder handle
+ * @return This function returns zero on success, or negative value with error code.
+ * @remarks This function can be called successfully when current state is @n
+ * MM_streamrecorder_STATE_PAUSED or MM_streamrecorder_STATE_RECORDING and @n
+ * the state of the streamrecorder will become MM_streamrecorder_STATE_PREPARE. @n
+ * Otherwise, this function will return MM_ERROR_streamrecorder_INVALID_CONDITION.
+ * @see _mmstreamrecorder_commit
+ */
+int _mmstreamrecorder_cancel(MMHandleType hstreamrecorder);
+
+/**
+ * This function is to set callback for receiving messages from streamrecorder.
+ *
+ * @param[in] hstreamrecorder Specifies the streamrecorder handle
+ * @param[in] callback Specifies the function pointer of callback function
+ * @param[in] user_data Specifies the user poiner for passing to callback function
+ *
+ * @return This function returns zero on success, or negative value with error code.
+ * @remarks typedef bool (*mm_message_callback) (int msg, mm_messageType *param, void *user_param);@n
+ * @n
+ * typedef union @n
+ * { @n
+ * int code; @n
+ * struct @n
+ * { @n
+ * int total; @n
+ * int elapsed; @n
+ * } time; @n
+ * struct @n
+ * { @n
+ * int previous; @n
+ * int current; @n
+ * } state; @n
+ * } mm_message_type; @n
+ * @n
+ * If a message value for mm_message_callback is MM_MESSAGE_STATE_CHANGED, @n
+ * state value in mm_message_type will be a mmstreamrecorder_state_type enum value;@n
+ * @n
+ * If a message value for mm_message_callback is MM_MESSAGE_ERROR, @n
+ * the code value in mm_message_type will be a mmplayer_error_type enum value;
+ *
+ * @see mm_message_type, mmstreamrecorder_state_type, mmstreamrecorder_error_type
+ */
+int _mmstreamrecorder_set_message_callback(MMHandleType hstreamrecorder, MMMessageCallback callback, void *user_data);
+
+/**
+ * This function allocates structure of subsidiary attributes.
+ *
+ * @param[in] type Allocation type of streamrecorder context.
+ * @return This function returns structure pointer on success, NULL value on failure.
+ * @remarks
+ * @see _mmstreamrecorder_dealloc_subcontext()
+ *
+ */
+int _mmstreamrecorder_alloc_subcontext(MMHandleType handle);
+
+int _mmstreamrecorder_alloc_subcontext_videoinfo(MMHandleType handle);
+
+int _mmstreamrecorder_alloc_subcontext_audioinfo(MMHandleType handle);
+
+int _mmstreamrecorder_alloc_subcontext_fileinfo(MMHandleType handle);
+
+/**
+ * This function releases structure of subsidiary attributes.
+ *
+ * @param[in] sc Handle of streamrecorder subcontext.
+ * @return void
+ * @remarks
+ * @see _mmstreamrecorder_alloc_subcontext()
+ *
+ */
+void _mmstreamrecorder_dealloc_subcontext(MMHandleType handle);
+
+/**
+ * This function sets command function according to the type.
+ *
+ * @param[in] handle Handle of streamrecorder context.
+ * @param[in] type Allocation type of streamrecorder context.
+ * @return This function returns MM_ERROR_NONE on success, or other values with error code.
+ * @remarks
+ * @see __mmstreamrecorder_video_command(), __mmstreamrecorder_audio_command(), __mmstreamrecorder_image_command()
+ *
+ */
+void _mmstreamrecorder_set_functions(MMHandleType handle);
+
+void _mmstreamrecorder_unset_functions(MMHandleType handle);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MM_streamrecorder_INTERNAL_H__ */
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 __MM_STREAMRECORDER_RECORDER_H__
+#define __MM_STREAMRECORDER_RECORDER_H__
+
+/*=======================================================================================
+| INCLUDE FILES |
+========================================================================================*/
+#include <mm_types.h>
+#include "mm_streamrecorder_gstdispatch.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=======================================================================================
+| GLOBAL DEFINITIONS AND DECLARATIONS FOR STREAMCORDER |
+========================================================================================*/
+
+/*=======================================================================================
+| MACRO DEFINITIONS |
+========================================================================================*/
+
+/*=======================================================================================
+| ENUM DEFINITIONS |
+========================================================================================*/
+
+/*=======================================================================================
+| STRUCTURE DEFINITIONS |
+========================================================================================*/
+
+/*=======================================================================================
+| CONSTANT DEFINITIONS |
+========================================================================================*/
+
+/*=======================================================================================
+| STATIC VARIABLES |
+========================================================================================*/
+
+/*=======================================================================================
+| EXTERN GLOBAL VARIABLE |
+========================================================================================*/
+
+/*=======================================================================================
+| GLOBAL FUNCTION PROTOTYPES |
+========================================================================================*/
+
+/**
+ * This function create main pipeline according to type.
+ *
+ * @param[in] handle Handle of streamrecorder context.
+ * @param[in] type Allocation type of streamrecorder context.
+ * @return This function returns zero on success, or negative value with error code.
+ * @remarks
+ * @see _mmstreamrecorder_destroy_pipeline()
+ *
+ */
+int _mmstreamrecorder_create_pipeline(MMHandleType handle);
+
+/**
+ * This function release all element of main pipeline according to type.
+ *
+ * @param[in] handle Handle of streamrecorder context.
+ * @param[in] type Allocation type of streamrecorder context.
+ * @return void
+ * @remarks
+ * @see _mmstreamrecorder_create_pipeline()
+ *
+ */
+void _mmstreamrecorder_destroy_pipeline(MMHandleType handle);
+
+/**
+ * This function creates recorder pipeline.
+ * When application creates initial pipeline, there are only bins for preview.
+ * If application wants to record, recorder pipeline should be created.
+ *
+ * @param[in] handle Handle of streamrecorder context.
+ * @return This function returns MM_ERROR_NONE on success, or the other values on error.
+ * @remarks
+ */
+int _mmstreamrecorder_create_recorder_pipeline(MMHandleType handle);
+
+/**
+ * This function creates bin of audio source.
+ * Basically, main pipeline of streamrecorder is composed of several bin(a bundle
+ * of elements). Each bin operates its own function. This bin has a roll
+ * inputting audio data from audio source(such as mike).
+ *
+ * @param[in] handle Handle of streamrecorder context.
+ * @return This function returns MM_ERROR_NONE on success, or the other values on error.
+ * @remarks
+ */
+int _mmstreamrecorder_create_audiosrc_bin(MMHandleType handle);
+
+int _mmstreamrecorder_destroy_audiosrc_bin(MMHandleType handle);
+
+/**
+ * This function creates outputsink bin.
+ *
+ * @param[in] handle Handle of streamrecorder context.
+ * @param[in] profile profile of encodesinkbin.
+ * @return This function returns MM_ERROR_NONE on success, or the other values on error.
+ * @remarks
+ */
+int _mmstreamrecorder_create_encodesink_bin(MMHandleType handle, MMStreamRecorderEncodebinProfile profile);
+
+int _mmstreamrecorder_destroy_encodesink_bin(MMHandleType handle);
+
+/**
+ * This function handles EOS(end of stream) when commit video recording.
+ *
+ * @param[in] handle Handle of streamrecorder context.
+ * @return This function returns TRUE on success, or FALSE on failure.
+ * @remarks
+ * @see _mmstreamrecorder_set_functions()
+ */
+int _mmstreamrecorder_video_handle_eos(MMHandleType handle);
+
+int _mmstreamrecorder_destroy_recorder_pipeline(MMHandleType handle);
+
+// COMMAND
+int _mmstreamrecorder_video_command(MMHandleType handle, int command);
+
+/**
+ * This function creates audio pipeline for audio recording.
+ *
+ * @param[in] handle Handle of streamrecorder.
+ * @return This function returns MM_ERROR_NONE on success, or others on failure.
+ * @remarks
+ * @see _mmstreamrecorder_destroy_audio_pipeline()
+ *
+ */
+int _mmstreamrecorder_create_audio_pipeline(MMHandleType handle);
+
+/**
+ * This function destroy audio pipeline.
+ *
+ * @param[in] handle Handle of streamrecorder.
+ * @return void
+ * @remarks
+ * @see _mmstreamrecorder_destroy_pipeline()
+ *
+ */
+void _mmstreamrecorder_destroy_audio_pipeline(MMHandleType handle);
+
+/**
+ * This function runs command for audio recording.
+ *
+ * @param[in] handle Handle of streamrecorder.
+ * @param[in] command audio recording command.
+ * @return This function returns MM_ERROR_NONE on success, or others on failure.
+ * @remarks
+ * @see
+ *
+ */
+int _mmstreamrecorder_audio_command(MMHandleType handle, int command);
+
+/**
+ * This function handles EOS(end of stream) when audio recording is finished.
+ *
+ * @param[in] handle Handle of streamrecorder.
+ * @return This function returns TRUE on success, or FALSE on failure.
+ * @remarks
+ * @see
+ *
+ */
+int _mmstreamrecorder_audio_handle_eos(MMHandleType handle);
+
+int _mmstreamrecorder_create_audiop_with_encodebin(MMHandleType handle);
+
+int _mmstreamrecorder_push_videostream_buffer(MMHandleType handle, unsigned long timestamp, GstBuffer *buffer, int size);
+int _mmstreamrecorder_push_audiostream_buffer(MMHandleType handle, unsigned long timestamp, GstBuffer *buffer, int size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MM_STREAMRECORDER_RECORDER_H__ */
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 __MM_STREAMRECORDER_UTIL_H__
+#define __MM_STREAMRECORDER_UTIL_H__
+
+/*=======================================================================================
+| INCLUDE FILES |
+========================================================================================*/
+#include <gst/gst.h>
+#include <gst/gstutils.h>
+#include <gst/gstpad.h>
+#include "mm_debug.h"
+#include <glib.h>
+#include<stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=======================================================================================
+| GLOBAL DEFINITIONS AND DECLARATIONS FOR STREAMRECORDER |
+========================================================================================*/
+
+/*=======================================================================================
+| MACRO DEFINITIONS |
+========================================================================================*/
+#ifndef CLEAR
+#define CLEAR(x) memset (&(x), 0, sizeof (x))
+#endif
+
+#define SAFE_FREE(x) \
+ if (x) {\
+ g_free(x); \
+ x = NULL; \
+ }
+
+#define _mmstreamrec_dbg_verb(fmt, args...) debug_verbose(" "fmt"\n", ##args);
+#define _mmstreamrec_dbg_log(fmt, args...) debug_log(" "fmt"\n", ##args);
+#define _mmstreamrec_dbg_warn(fmt, args...) debug_warning(" "fmt"\n", ##args);
+#define _mmstreamrec_dbg_err(fmt, args...) debug_error(" "fmt"\n", ##args);
+#define _mmstreamrec_dbg_crit(fmt, args...) debug_critical(" "fmt"\n", ##args);
+
+/**
+ * Macro for checking validity and debugging
+ */
+#define mmf_return_if_fail( expr ) \
+ if( expr ){} \
+ else \
+ { \
+ _mmstreamrec_dbg_err( "failed [%s]", #expr); \
+ return; \
+ };
+
+/**
+ * Macro for checking validity and debugging
+ */
+#define mmf_return_val_if_fail( expr, val ) \
+ if( expr ){} \
+ else \
+ { \
+ _mmstreamrec_dbg_err("failed [%s]", #expr); \
+ return( val ); \
+ };
+
+/**
+ * Minimum integer value
+ */
+#define _MMSTREAMRECORDER_MIN_INT (INT_MIN)
+
+/**
+ * Maximum integer value
+ */
+#define _MMSTREAMRECORDER_MAX_INT (INT_MAX)
+
+/**
+ * Minimum double value
+ */
+#define _MMSTREAMRECORDER_MIN_DOUBLE (DBL_MIN)
+
+/**
+ * Maximum integer value
+ */
+#define _MMSTREAMRECORDER_MAX_DOUBLE (DBL_MAX)
+
+// TODO : MOVE OTHERS
+enum {
+ PUSH_ENCODING_BUFFER_INIT = 0,
+ PUSH_ENCODING_BUFFER_RUN,
+ PUSH_ENCODING_BUFFER_STOP,
+};
+
+#define FPUTC_CHECK(x_char, x_file)\
+{\
+ if (fputc(x_char, x_file) == EOF) \
+ {\
+ _mmstreamrec_dbg_err("[Critical] fputc() returns fail.\n"); \
+ return FALSE;\
+ }\
+}
+
+#define FPUTS_CHECK(x_str, x_file)\
+{\
+ if (fputs(x_str, x_file) == EOF) \
+ {\
+ _mmstreamrec_dbg_err("[Critical] fputs() returns fail.\n");\
+ SAFE_FREE(str); \
+ return FALSE;\
+ }\
+}
+
+#if 0
+#define MM_STREAMRECORDER_INI_DEFAULT_PATH "/usr/etc/mmfw_transcode.ini"
+#define STREAMRECORDER_INI_MAX_STRLEN 100
+#endif
+/*=======================================================================================
+| ENUM DEFINITIONS |
+========================================================================================*/
+#define MAX_ERROR_MESSAGE_LEN 128
+#define MM_STREAMRECORDER_MIN_LOG_COUNT 10
+
+/*=======================================================================================
+| STRUCTURE DEFINITIONS |
+========================================================================================*/
+#if 0
+ typedef struct __mm_streamrecorder_ini {
+ /* video converter element */
+ gchar video_converter_element[STREAMRECORDER_INI_MAX_STRLEN];
+ } mm_streamrecorder_ini_t;
+#endif
+
+/*=======================================================================================
+| CONSTANT DEFINITIONS |
+========================================================================================*/
+
+/*=======================================================================================
+| GLOBAL FUNCTION PROTOTYPES |
+========================================================================================*/
+
+/* Pixel format */
+
+int _mmstreamrecorder_get_pixel_format(GstCaps *caps);
+int _mmstreamrecorder_get_pixtype(unsigned int fourcc);
+unsigned int _mmstreamrecorder_get_fourcc(int pixtype, int codectype, int use_zero_copy_format);
+
+/* Recording */
+/* find top level tag only, do not use this function for finding sub level tags. tag_fourcc is Four-character-code (FOURCC) */
+gint32 _mmstreamrecorder_double_to_fix(gdouble d_number);
+
+/* File system */
+int _mmstreamrecorder_get_freespace(const gchar *path, guint64 *free_space);
+int _mmstreamrecorder_get_file_size(const char *filename, guint64 *size);
+
+/* Debug */
+void _mmstreamrecorder_err_trace_write(char *str_filename, char *func_name, int line_num, char *fmt, ...);
+
+guint16 get_language_code(const char *str);
+gchar *str_to_utf8(const gchar *str);
+inline gboolean write_tag(FILE *f, const gchar *tag);
+inline gboolean write_to_32(FILE *f, guint val);
+inline gboolean write_to_16(FILE *f, guint val);
+inline gboolean write_to_24(FILE *f, guint val);
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MM_STREAMRECORDER_UTIL_H__ */
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 __MM_STREAMRECORDER_VIDEO_H__
+#define __MM_STREAMRECORDER_VIDEO_H__
+
+/*=======================================================================================
+| INCLUDE FILES |
+========================================================================================*/
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*=======================================================================================
+| STRUCTURE DEFINITIONS |
+========================================================================================*/
+/**
+ * StreamRecorder VideoInfo information for video mode
+ */
+typedef struct {
+ int iVideoEncoder; /**< Video Encoder */
+ gboolean b_commiting; /**< Is it commiting now? */
+ guint64 video_frame_count;
+ /**< current video frame */
+ guint64 filesize; /**< current file size */
+ guint64 max_size; /**< max recording size */
+ guint64 max_time; /**< max recording time */
+} _MMStreamRecorderVideoInfo;
+
+/*=======================================================================================
+| GLOBAL FUNCTION PROTOTYPES |
+========================================================================================*/
+
+int _mmstreamrecorder_check_videocodec_fileformat_compatibility(unsigned int video_codec, unsigned int file_format);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __MM_STREAMRECORDER_VIDEO_H__ */
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+
+#include <mm_error.h>
+
+#include <mm_attrs_private.h>
+#include "mm_streamrecorder.h"
+#include "mm_streamrecorder_internal.h"
+#include "mm_streamrecorder_attribute.h"
+
+/*===============================================================================
+| FUNCTION DEFINITIONS |
+===============================================================================*/
+/*-------------------------------------------------------------------------------
+| GLOBAL FUNCTION DEFINITIONS: |
+-------------------------------------------------------------------------------*/
+int mm_streamrecorder_create(MMHandleType *streamrecorder)
+{
+ int error = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail((void *)streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ _mmstreamrec_dbg_log("");
+
+ error = _mmstreamrecorder_create(streamrecorder);
+
+ _mmstreamrec_dbg_log("END");
+
+ return error;
+}
+
+
+int mm_streamrecorder_get_state(MMHandleType streamrecorder, MMStreamRecorderStateType *status)
+{
+ int ret = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail((void *)streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ mmf_return_val_if_fail((void *)status, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ _mmstreamrec_dbg_err("");
+
+ *status = _mmstreamrecorder_get_state(streamrecorder);
+
+ return ret;
+
+}
+
+int mm_streamrecorder_destroy(MMHandleType streamrecorder)
+{
+ int error = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail((void *)streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ _mmstreamrec_dbg_log("");
+
+ error = _mmstreamrecorder_destroy(streamrecorder);
+
+ _mmstreamrec_dbg_log("END!!!");
+
+ return error;
+}
+
+int mm_streamrecorder_realize(MMHandleType streamrecorder)
+{
+ int error = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail((void *)streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ _mmstreamrec_dbg_log("");
+
+ error = _mmstreamrecorder_realize(streamrecorder);
+
+ _mmstreamrec_dbg_log("END");
+
+ return error;
+}
+
+int mm_streamrecorder_pause(MMHandleType streamrecorder)
+{
+ int error = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail((void *)streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ _mmstreamrec_dbg_err("");
+
+ error = _mmstreamrecorder_pause(streamrecorder);
+
+ _mmstreamrec_dbg_err("END");
+
+ return error;
+}
+
+
+int mm_streamrecorder_unrealize(MMHandleType streamrecorder)
+{
+ int error = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail((void *)streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ _mmstreamrec_dbg_log("");
+
+ error = _mmstreamrecorder_unrealize(streamrecorder);
+
+ _mmstreamrec_dbg_log("END");
+
+ return error;
+}
+
+int mm_streamrecorder_record(MMHandleType streamrecorder)
+{
+ int error = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail((void *)streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ _mmstreamrec_dbg_log("");
+
+ error = _mmstreamrecorder_record(streamrecorder);
+
+ _mmstreamrec_dbg_log("END");
+
+ return error;
+}
+
+int mm_streamrecorder_push_stream_buffer(MMHandleType streamrecorder, MMStreamRecorderStreamType streamtype, unsigned long timestamp, void *buffer, int size)
+{
+ int error = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail((void *)streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ _mmstreamrec_dbg_log("");
+
+ error = _mmstreamrecorder_push_stream_buffer(streamrecorder, streamtype, timestamp, buffer, size);
+
+ _mmstreamrec_dbg_log("END");
+
+ return error;
+}
+
+int mm_streamrecorder_commit(MMHandleType streamrecorder)
+{
+ int error = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail((void *)streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ _mmstreamrec_dbg_log("");
+
+ error = _mmstreamrecorder_commit(streamrecorder);
+
+ _mmstreamrec_dbg_log("END");
+
+ return error;
+}
+
+int mm_streamrecorder_cancel(MMHandleType streamrecorder)
+{
+ int error = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail((void *)streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ _mmstreamrec_dbg_log("");
+
+ error = _mmstreamrecorder_cancel(streamrecorder);
+
+ _mmstreamrec_dbg_log("END");
+
+ return error;
+}
+
+int mm_streamrecorder_set_message_callback(MMHandleType streamrecorder, MMMessageCallback callback, void *user_data)
+{
+ int error = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail((void *)streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ error = _mmstreamrecorder_set_message_callback(streamrecorder, callback, user_data);
+
+ return error;
+}
+
+int mm_streamrecorder_get_attributes(MMHandleType streamrecorder, char **err_attr_name, const char *attribute_name, ...)
+{
+ va_list var_args;
+ int ret = MM_ERROR_NONE;
+
+ return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT);
+
+ va_start(var_args, attribute_name);
+ ret = _mmstreamrecorder_get_attributes(streamrecorder, err_attr_name, attribute_name, var_args);
+ va_end(var_args);
+
+ return ret;
+}
+
+int mm_streamrecorder_set_attributes(MMHandleType streamrecorder, char **err_attr_name, const char *attribute_name, ...)
+{
+ va_list var_args;
+ int ret = MM_ERROR_NONE;
+
+ return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT);
+
+ va_start(var_args, attribute_name);
+ ret = _mmstreamrecorder_set_attributes(streamrecorder, err_attr_name, attribute_name, var_args);
+ va_end(var_args);
+
+ return ret;
+}
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 <mm_error.h>
+
+#include "mm_streamrecorder_util.h"
+#include "mm_streamrecorder_attribute.h"
+#include "mm_streamrecorder_gstdispatch.h"
+
+/*-----------------------------------------------------------------------
+| MACRO DEFINITIONS: |
+-----------------------------------------------------------------------*/
+#define MM_STREAMRECORDER_ATTRIBUTE_MAX_VALUE 15
+#define MM_STREAMRECORDER_RESOLUTION_MAX_VALUE 4080
+
+/*---------------------------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS for internal |
+---------------------------------------------------------------------------------------*/
+
+/* basic attributes' info */
+mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = {
+ /* 0 */
+ {
+ MM_STR_VIDEO_BUFFER_TYPE, /* ID */
+ "videobuffer-type", /* Name */
+ MMF_VALUE_TYPE_INT, /* Type */
+ MM_ATTRS_FLAG_RW, /* Flag */
+ {(void *)MM_STREAMRECORDER_VIDEO_TYPE_TBM_BO}, /* Default value */
+ MM_ATTRS_VALID_TYPE_INT_RANGE, /* Validity type */
+ MM_STREAMRECORDER_VIDEO_TYPE_TBM_BO, /* Validity val1 (min, *array,...) */
+ MM_STREAMRECORDER_VIDEO_TYPE_NORMAL_BUFFER, /* Validity val2 (max, count, ...) */
+ NULL, /* Runtime setting function of the attribute */
+ },
+ /* 1 */
+ {MM_STR_VIDEO_FORMAT,
+ "videosource-format",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)MM_STREAMRECORDER_INPUT_FORMAT_NV12},
+ MM_ATTRS_VALID_TYPE_INT_RANGE,
+ MM_STREAMRECORDER_INPUT_FORMAT_INVALID,
+ MM_STREAMRECORDER_INPUT_FORMAT_NUM,
+ NULL,
+ },
+ /* 2 */
+ {
+ MM_STR_VIDEO_FRAMERATE,
+ "video-framerate",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)0},
+ MM_ATTRS_VALID_TYPE_INT_RANGE,
+ 0,
+ _MMSTREAMRECORDER_MAX_INT,
+ NULL,
+ },
+ /* 3 */
+ {
+ MM_STR_VIDEO_ENCODER_BITRATE,
+ "video-bitrate",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)0},
+ MM_ATTRS_VALID_TYPE_INT_RANGE,
+ 0,
+ _MMSTREAMRECORDER_MAX_INT,
+ NULL, /*_mmstreamrecorder_commit_video_bitrate, */
+ },
+ /* 4 */
+ {
+ MM_STR_VIDEO_RESOLUTION_WIDTH,
+ "video-resolution-width",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)0},
+ MM_ATTRS_VALID_TYPE_INT_ARRAY,
+ 0,
+ 0,
+ NULL,
+ },
+ /* 5 */
+ {
+ MM_STR_VIDEO_RESOLUTION_HEIGHT,
+ "video-resolution-height",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)0},
+ MM_ATTRS_VALID_TYPE_INT_ARRAY,
+ 0,
+ 0,
+ NULL,
+ },
+ /* 6 */
+ {
+ MM_STR_AUDIO_FORMAT,
+ "audio-source-format",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)MM_STREAMRECORDER_AUDIO_FORMAT_PCM_S16_LE},
+ MMF_VALUE_TYPE_INT,
+ MM_STREAMRECORDER_AUDIO_FORMAT_PCM_U8,
+ MM_STREAMRECORDER_AUDIO_FORMAT_PCM_S16_LE,
+ _mmstreamrecorder_commit_audio_bitformat,
+ },
+ /* 7 */
+ {
+ MM_STR_AUDIO_ENCODER_BITRATE,
+ "audio-bitrate",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)128000},
+ MM_ATTRS_VALID_TYPE_INT_RANGE,
+ 0,
+ _MMSTREAMRECORDER_MAX_INT,
+ _mmstreamrecorder_commit_audio_bitrate,
+ },
+ /* 8 */
+ {
+ MM_STR_AUDIO_SAMPLERATE,
+ "audio-samplerate",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)0},
+ MM_ATTRS_VALID_TYPE_INT_RANGE,
+ 0,
+ _MMSTREAMRECORDER_MAX_INT,
+ _mmstreamrecorder_commit_audio_samplingrate,
+ },
+ /* 9 */
+ {
+ MM_STR_VIDEO_ENCODER,
+ "video-encoder",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)0},
+ MM_ATTRS_VALID_TYPE_INT_ARRAY,
+ 0,
+ 0,
+ _mmstreamrecorder_commit_video_encoder,
+ },
+ /* 10 */
+ {
+ MM_STR_AUDIO_ENCODER,
+ "audio-encoder",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)0},
+ MM_ATTRS_VALID_TYPE_INT_ARRAY,
+ 0,
+ 0,
+ _mmstreamrecorder_commit_audio_encoder,
+ },
+ /* 11 */
+ {
+ MM_STR_AUDIO_CHENNEL_COUNT,
+ "audio-channel-count",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)2},
+ MM_ATTRS_VALID_TYPE_INT_RANGE,
+ 0,
+ _MMSTREAMRECORDER_MAX_INT,
+ _mmstreamrecorder_commit_audio_channel,
+ },
+ /* 12 */
+ {
+ MM_STR_FILE_FORMAT,
+ "file-format",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)0},
+ MM_ATTRS_VALID_TYPE_INT_ARRAY,
+ 0,
+ 0,
+ NULL,
+ },
+ /* 13 */
+ {
+ MM_STR_TARGET_FILE_NAME,
+ "filename",
+ MMF_VALUE_TYPE_STRING,
+ MM_ATTRS_FLAG_RW,
+ {NULL},
+ MM_ATTRS_VALID_TYPE_NONE,
+ 0,
+ 0,
+ NULL,
+ },
+ /* 14 */
+ {
+ MM_STR_VIDEO_ENABLE,
+ "video-enable",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)FALSE},
+ MM_ATTRS_VALID_TYPE_NONE,
+ 0,
+ _MMSTREAMRECORDER_MAX_INT,
+ _mmstreamrecorder_commit_video_enable,
+ },
+ /* 15 */
+ {
+ MM_STR_AUDIO_ENABLE,
+ "audio-enable",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)FALSE},
+ MM_ATTRS_VALID_TYPE_NONE,
+ 0,
+ _MMSTREAMRECORDER_MAX_INT,
+ _mmstreamrecorder_commit_audio_enable,
+ },
+ /* 16 */
+ {
+ MM_STR_MODE,
+ "recorder-mode",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)MM_STREAMRECORDER_MODE_MEDIABUFFER},
+ MM_ATTRS_VALID_TYPE_NONE,
+ 0,
+ _MMSTREAMRECORDER_MAX_INT,
+ NULL,
+ },
+ /*17*/
+ {
+ MM_STR_TARGET_MAX_SIZE,
+ "target-max-size",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)0},
+ MM_ATTRS_VALID_TYPE_INT_RANGE,
+ 0,
+ _MMSTREAMRECORDER_MAX_INT,
+ NULL,
+ },
+ /*18*/
+ {
+ MM_STR_TARGET_TIME_LIMIT,
+ "target-time-limit",
+ MMF_VALUE_TYPE_INT,
+ MM_ATTRS_FLAG_RW,
+ {(void *)0},
+ MM_ATTRS_VALID_TYPE_INT_RANGE,
+ 0,
+ _MMSTREAMRECORDER_MAX_INT,
+ NULL,
+ },
+
+};
+
+/*-----------------------------------------------------------------------
+| LOCAL VARIABLE DEFINITIONS for internal |
+-----------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------
+| LOCAL FUNCTION PROTOTYPES: |
+-----------------------------------------------------------------------*/
+/* STATIC INTERNAL FUNCTION */
+static int __mmstreamrecorder_set_conf_to_valid_info(MMHandleType handle)
+{
+ int *format = NULL;
+ int total_count = 0;
+
+ /* Video width */
+ total_count = _mmstreamrecorder_get_available_format(handle, KEYWORD_VIDEO_WIDTH, &format);
+ stream_attrs_const_info[MM_STR_VIDEO_RESOLUTION_WIDTH].validity_value1 = (int)format;
+ stream_attrs_const_info[MM_STR_VIDEO_RESOLUTION_WIDTH].validity_value2 = (int)total_count;
+
+ /* Video height */
+ total_count = _mmstreamrecorder_get_available_format(handle, KEYWORD_VIDEO_HEIGHT, &format);
+ stream_attrs_const_info[MM_STR_VIDEO_RESOLUTION_HEIGHT].validity_value1 = (int)format;
+ stream_attrs_const_info[MM_STR_VIDEO_RESOLUTION_HEIGHT].validity_value2 = (int)total_count;
+
+ /* Audio encoder */
+ total_count = _mmstreamrecorder_get_available_format(handle, KEYWORD_AUDIO_ENCODERS, &format);
+ stream_attrs_const_info[MM_STR_AUDIO_ENCODER].validity_value1 = (int)format;
+ stream_attrs_const_info[MM_STR_AUDIO_ENCODER].validity_value2 = (int)total_count;
+
+ /*Video encoder*/
+ total_count = _mmstreamrecorder_get_available_format(handle, KEYWORD_VIDEO_ENCODERS, &format);
+ stream_attrs_const_info[MM_STR_VIDEO_ENCODER].validity_value1 = (int)format;
+ stream_attrs_const_info[MM_STR_VIDEO_ENCODER].validity_value2 = (int)total_count;
+
+ /* File Format */
+ total_count = _mmstreamrecorder_get_available_format(handle, KEYWORD_FILE_FORMATS, &format);
+ stream_attrs_const_info[MM_STR_FILE_FORMAT].validity_value1 = (int)format;
+ stream_attrs_const_info[MM_STR_FILE_FORMAT].validity_value2 = (int)total_count;
+
+ return MM_ERROR_NONE;
+}
+
+static int __mmstreamrecorder_release_conf_valid_info(MMHandleType handle)
+{
+ int *allocated_memory = NULL;
+
+ _mmstreamrec_dbg_log("START");
+
+ allocated_memory = (int *)(stream_attrs_const_info[MM_STR_VIDEO_RESOLUTION_WIDTH].validity_value1);
+ if (allocated_memory) {
+ free(allocated_memory);
+ stream_attrs_const_info[MM_STR_VIDEO_RESOLUTION_WIDTH].validity_value1 = (int)NULL;
+ stream_attrs_const_info[MM_STR_VIDEO_RESOLUTION_WIDTH].validity_value2 = (int)0;
+ }
+
+ allocated_memory = (int *)(stream_attrs_const_info[MM_STR_VIDEO_RESOLUTION_HEIGHT].validity_value1);
+ if (allocated_memory) {
+ free(allocated_memory);
+ stream_attrs_const_info[MM_STR_VIDEO_RESOLUTION_HEIGHT].validity_value1 = (int)NULL;
+ stream_attrs_const_info[MM_STR_VIDEO_RESOLUTION_HEIGHT].validity_value2 = (int)0;
+ }
+
+ allocated_memory = (int *)(stream_attrs_const_info[MM_STR_AUDIO_ENCODER].validity_value1);
+ if (allocated_memory) {
+ free(allocated_memory);
+ stream_attrs_const_info[MM_STR_AUDIO_ENCODER].validity_value1 = (int)NULL;
+ stream_attrs_const_info[MM_STR_AUDIO_ENCODER].validity_value2 = (int)0;
+ }
+
+ allocated_memory = (int *)(stream_attrs_const_info[MM_STR_VIDEO_ENCODER].validity_value1);
+ if (allocated_memory) {
+ free(allocated_memory);
+ stream_attrs_const_info[MM_STR_VIDEO_ENCODER].validity_value1 = (int)NULL;
+ stream_attrs_const_info[MM_STR_VIDEO_ENCODER].validity_value2 = (int)0;
+ }
+
+ allocated_memory = (int *)(stream_attrs_const_info[MM_STR_FILE_FORMAT].validity_value1);
+ if (allocated_memory) {
+ free(allocated_memory);
+ stream_attrs_const_info[MM_STR_FILE_FORMAT].validity_value1 = (int)NULL;
+ stream_attrs_const_info[MM_STR_FILE_FORMAT].validity_value2 = (int)0;
+ }
+ _mmstreamrec_dbg_log("DONE");
+
+ return MM_ERROR_NONE;
+}
+
+#if 0
+static bool __mmstreamrecorder_attrs_is_supported(MMHandleType handle, int idx)
+{
+ mmf_attrs_t *attr = (mmf_attrs_t *) handle;
+ int flag;
+
+ if (mm_attrs_get_flags(handle, idx, &flag) == MM_ERROR_NONE) {
+ if (flag == MM_ATTRS_FLAG_NONE)
+ return FALSE;
+ } else {
+ return FALSE;
+ }
+
+ if (attr->items[idx].value_spec.type == MM_ATTRS_VALID_TYPE_INT_RANGE) {
+ int min, max;
+ mm_attrs_get_valid_range((MMHandleType) attr, idx, &min, &max);
+ if (max < min)
+ return FALSE;
+ } else if (attr->items[idx].value_spec.type == MM_ATTRS_VALID_TYPE_INT_ARRAY) {
+ int count;
+ int *array;
+ mm_attrs_get_valid_array((MMHandleType) attr, idx, &count, &array);
+ if (count == 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+#endif
+static int __mmstreamrecorder_check_valid_pair(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list var_args)
+{
+#define INIT_VALUE -1
+#define CHECK_COUNT 2
+#define CAPTURE_RESOLUTION 1
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ MMHandleType attrs = 0;
+
+ int ret = MM_ERROR_NONE;
+ int i = 0, j = 0;
+ const char *name = NULL;
+ const char *check_pair_name[2][3] = {
+ {MMSTR_VIDEO_RESOLUTION_WIDTH, MMSTR_VIDEO_RESOLUTION_HEIGHT, "MMSTR_VIDEO_RESOLUTION_WIDTH and HEIGHT"},
+ {NULL, NULL, NULL}
+ };
+
+ int check_pair_value[2][2] = {
+ {INIT_VALUE, INIT_VALUE},
+ {INIT_VALUE, INIT_VALUE},
+ };
+
+ if (hstreamrecorder == NULL || attribute_name == NULL) {
+ _mmstreamrec_dbg_warn("handle[%p] or attribute_name[%p] is NULL.", hstreamrecorder, attribute_name);
+ return MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT;
+ }
+
+ if (err_attr_name)
+ *err_attr_name = NULL;
+
+ /* _mmstreamrec_dbg_log( "ENTER" ); */
+
+ attrs = MMF_STREAMRECORDER_ATTRS(handle);
+
+ name = attribute_name;
+
+ while (name) {
+ int idx = -1;
+ MMAttrsType attr_type = MM_ATTRS_TYPE_INVALID;
+
+ /*_mmstreamrec_dbg_log( "NAME : %s", name );*/
+
+ /* attribute name check */
+ if ((ret = mm_attrs_get_index(attrs, name, &idx)) != MM_ERROR_NONE) {
+ if (err_attr_name)
+ *err_attr_name = strdup(name);
+
+ if (ret == (int)MM_ERROR_COMMON_OUT_OF_ARRAY)
+ return MM_ERROR_COMMON_ATTR_NOT_EXIST;
+ else
+ return ret;
+ }
+
+ /* type check */
+ if ((ret = mm_attrs_get_type(attrs, idx, &attr_type)) != MM_ERROR_NONE)
+ return ret;
+
+ switch (attr_type) {
+ case MM_ATTRS_TYPE_INT:
+ {
+ va_arg((var_args), int);
+ break;
+ }
+ case MM_ATTRS_TYPE_DOUBLE:
+ va_arg((var_args), double);
+ break;
+ case MM_ATTRS_TYPE_STRING:
+ va_arg((var_args), char *); /* string */
+ va_arg((var_args), int); /* size */
+ break;
+ case MM_ATTRS_TYPE_DATA:
+ va_arg((var_args), void *); /* data */
+ va_arg((var_args), int); /* size */
+ break;
+ case MM_ATTRS_TYPE_INVALID:
+ default:
+ _mmstreamrec_dbg_err("Not supported attribute type(%d, name:%s)", attr_type, name);
+ if (err_attr_name)
+ *err_attr_name = strdup(name);
+ return MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT;
+ }
+
+ /* next name */
+ name = va_arg(var_args, char *);
+ }
+
+ for (i = 0; i < CHECK_COUNT; i++) {
+ if (check_pair_value[i][0] != INIT_VALUE || check_pair_value[i][1] != INIT_VALUE) {
+ gboolean check_result = FALSE;
+ char *err_name = NULL;
+ MMStreamRecorderAttrsInfo attr_info_0, attr_info_1;
+
+ if (check_pair_value[i][0] == INIT_VALUE) {
+ mm_attrs_get_int_by_name(attrs, check_pair_name[i][0], &check_pair_value[i][0]);
+ err_name = strdup(check_pair_name[i][1]);
+ } else if (check_pair_value[i][1] == INIT_VALUE) {
+ mm_attrs_get_int_by_name(attrs, check_pair_name[i][1], &check_pair_value[i][1]);
+ err_name = strdup(check_pair_name[i][0]);
+ } else {
+ err_name = strdup(check_pair_name[i][2]);
+ }
+
+ mm_streamrecorder_get_attribute_info(handle, check_pair_name[i][0], &attr_info_0);
+ mm_streamrecorder_get_attribute_info(handle, check_pair_name[i][1], &attr_info_1);
+
+ check_result = FALSE;
+
+ for (j = 0; j < attr_info_0.int_array.count; j++) {
+ if (attr_info_0.int_array.array[j] == check_pair_value[i][0]
+ && attr_info_1.int_array.array[j] == check_pair_value[i][1]) {
+ _mmstreamrec_dbg_log("Valid Pair[%s,%s] existed %dx%d[index:%d]", check_pair_name[i][0], check_pair_name[i][1], check_pair_value[i][0], check_pair_value[i][1], i);
+ check_result = TRUE;
+ break;
+ }
+ }
+
+ if (check_result == FALSE) {
+ _mmstreamrec_dbg_err("INVALID pair[%s,%s] %dx%d", check_pair_name[i][0], check_pair_name[i][1], check_pair_value[i][0], check_pair_value[i][1]);
+ if (err_attr_name)
+ *err_attr_name = err_name;
+
+ return MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT;
+ }
+
+ if (err_name) {
+ free(err_name);
+ err_name = NULL;
+ }
+ }
+ }
+
+ /*_mmstreamrec_dbg_log("DONE");*/
+
+ return MM_ERROR_NONE;
+}
+
+/* attribute commiter */
+void __mmstreamrecorder_print_attrs(const char *attr_name, const mmf_value_t * value, const char *cmt_way)
+{
+ switch (value->type) {
+ case MMF_VALUE_TYPE_INT:
+ _mmstreamrec_dbg_log("%s :(%s:%d)", cmt_way, attr_name, value->value.i_val);
+ break;
+ case MMF_VALUE_TYPE_DOUBLE:
+ _mmstreamrec_dbg_log("%s :(%s:%f)", cmt_way, attr_name, value->value.d_val);
+ break;
+ case MMF_VALUE_TYPE_STRING:
+ _mmstreamrec_dbg_log("%s :(%s:%s)", cmt_way, attr_name, value->value.s_val);
+ break;
+ case MMF_VALUE_TYPE_DATA:
+ _mmstreamrec_dbg_log("%s :(%s:%p)", cmt_way, attr_name, value->value.p_val);
+ break;
+ default:
+ break;
+ }
+
+ return;
+}
+
+int _mmstreamrecorder_get_audio_codec_format(MMHandleType handle, const char *name)
+{
+ int codec_index = MM_AUDIO_CODEC_INVALID;
+
+ if (!name) {
+ _mmstreamrec_dbg_err("name is NULL");
+ return MM_AUDIO_CODEC_INVALID;
+ }
+
+ if (!strcmp(name, "AMR"))
+ codec_index = MM_AUDIO_CODEC_AMR;
+ else if (!strcmp(name, "AAC"))
+ codec_index = MM_AUDIO_CODEC_AAC;
+ else if (!strcmp(name, "PCM"))
+ codec_index = MM_AUDIO_CODEC_PCM;
+ else if (!strcmp(name, "VORBIS"))
+ codec_index = MM_AUDIO_CODEC_VORBIS;
+
+ return codec_index;
+}
+
+int _mmstreamrecorder_get_video_codec_format(MMHandleType handle, const char *name)
+{
+ int codec_index = MM_VIDEO_CODEC_INVALID;
+
+ if (!name) {
+ _mmstreamrec_dbg_err("name is NULL");
+ return MM_VIDEO_CODEC_INVALID;
+ }
+
+ if (!strcmp(name, "H263"))
+ codec_index = MM_VIDEO_CODEC_H263;
+ else if (!strcmp(name, "H264"))
+ codec_index = MM_VIDEO_CODEC_H264;
+ else if (!strcmp(name, "MPEG4"))
+ codec_index = MM_VIDEO_CODEC_MPEG4;
+
+ return codec_index;
+}
+
+
+int _mmstreamrecorder_get_mux_format(MMHandleType handle, const char *name)
+{
+ int mux_index = MM_FILE_FORMAT_INVALID;
+
+ if (!name) {
+ _mmstreamrec_dbg_err("name is NULL");
+ return MM_FILE_FORMAT_INVALID;
+ }
+
+ if (!strcmp(name, "3GP"))
+ mux_index = MM_FILE_FORMAT_3GP;
+ else if (!strcmp(name, "AMR"))
+ mux_index = MM_FILE_FORMAT_AMR;
+ else if (!strcmp(name, "MP4"))
+ mux_index = MM_FILE_FORMAT_MP4;
+ else if (!strcmp(name, "WAV"))
+ mux_index = MM_FILE_FORMAT_WAV;
+ return mux_index;
+}
+
+
+int _mmstreamrecorder_get_format(MMHandleType handle , int category, const char *name)
+{
+ int fmt = -1;
+
+ mmf_return_val_if_fail(name, -1);
+
+ switch (category) {
+ case KEYWORD_AUDIO_ENCODERS:
+ fmt = _mmstreamrecorder_get_audio_codec_format(handle, name);
+ break;
+ case KEYWORD_VIDEO_ENCODERS:
+ fmt = _mmstreamrecorder_get_video_codec_format(handle, name);
+ break;
+ case KEYWORD_FILE_FORMATS:
+ fmt = _mmstreamrecorder_get_mux_format(handle, name);
+ break;
+ default:
+ break;
+ }
+ return fmt;
+}
+
+int _mmstreamrecorder_get_type_count(MMHandleType handle, int type)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ int count = 0;
+ int i = 0;
+ if (type == KEYWORD_VIDEO_WIDTH) {
+ while (hstreamrecorder->ini.supported_video_width[i++])
+ count++;
+ } else if (type == KEYWORD_VIDEO_HEIGHT) {
+ while (hstreamrecorder->ini.supported_video_height[i++])
+ count++;
+ } else if (type == KEYWORD_AUDIO_ENCODERS) {
+ while (hstreamrecorder->ini.supported_audio_encoders[i++][0])
+ count++;
+ } else if (type == KEYWORD_VIDEO_ENCODERS) {
+ while (hstreamrecorder->ini.supported_video_encoders[i++][0])
+ count++;
+ } else if (type == KEYWORD_FILE_FORMATS) {
+ while (hstreamrecorder->ini.supported_file_formats[i++][0])
+ count++;
+ }
+ return count;
+}
+
+void __mmstreamrecorder_get_supported_name(MMHandleType handle, int type , char **str, int i)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ if (type == KEYWORD_AUDIO_ENCODERS) {
+ *str = hstreamrecorder->ini.supported_audio_encoders[i];
+ return;
+ } else if (type == KEYWORD_VIDEO_ENCODERS) {
+ *str = hstreamrecorder->ini.supported_video_encoders[i];
+ return;
+ } else if (type == KEYWORD_FILE_FORMATS) {
+ *str = hstreamrecorder->ini.supported_file_formats[i];
+ return;
+ } else {
+ *str = NULL;
+ return;
+ }
+}
+
+int __mmstreamrecorder_get_supported_value(MMHandleType handle, int type, int i)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ if (type == KEYWORD_VIDEO_WIDTH)
+ return hstreamrecorder->ini.supported_video_width[i];
+ else if (type == KEYWORD_VIDEO_HEIGHT)
+ return hstreamrecorder->ini.supported_video_height[i];
+ else
+ return -1;
+}
+
+int
+_mmstreamrecorder_get_available_format(MMHandleType handle, int type, int ** format)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ int *arr = NULL;
+ int total_count = 0;
+ int count = 0;
+ int i = 0;
+ int fmt = 0;
+ const char *name = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, 0);
+
+ count = _mmstreamrecorder_get_type_count(handle, type);
+
+ if (count <= 0)
+ return -1;
+
+ arr = (int*) g_malloc0(count * sizeof(int));
+ if (arr == NULL) {
+ _mmstreamrec_dbg_err("malloc failed : %d", count * sizeof(int));
+ return -1;
+ }
+
+ if (type == KEYWORD_VIDEO_WIDTH || type == KEYWORD_VIDEO_HEIGHT) {
+ for (i = 0 ; i < count ; i++) {
+ fmt = __mmstreamrecorder_get_supported_value(handle, type, i);
+ if (fmt >= 0)
+ arr[total_count++] = fmt;
+ }
+ } else {
+ for (i = 0 ; i < count ; i++) {
+ __mmstreamrecorder_get_supported_name(handle, type, &name, i);
+ fmt = _mmstreamrecorder_get_format(handle, type, name);
+ if (fmt >= 0)
+ arr[total_count++] = fmt;
+ }
+ }
+ *format = arr;
+ return total_count;
+}
+
+/*=======================================================================
+| FUNCTION DEFINITIONS |
+=======================================================================*/
+/*-----------------------------------------------------------------------
+| GLOBAL FUNCTION DEFINITIONS: |
+-----------------------------------------------------------------------*/
+MMHandleType _mmstreamrecorder_alloc_attribute(MMHandleType handle)
+{
+ _mmstreamrec_dbg_log("");
+
+ MMHandleType attrs = 0;
+ mmf_attrs_construct_info_t *attrs_const_info = NULL;
+ unsigned int attr_count = 0;
+ unsigned int idx;
+
+ /* Create attribute constructor */
+ _mmstreamrec_dbg_log("start");
+
+ /* alloc 'mmf_attrs_construct_info_t' */
+ attr_count = ARRAY_SIZE(stream_attrs_const_info);
+ attrs_const_info = malloc(attr_count * sizeof(mmf_attrs_construct_info_t));
+
+ if (!attrs_const_info) {
+ _mmstreamrec_dbg_err("Fail to alloc constructor.");
+ return 0;
+ }
+
+ for (idx = 0; idx < attr_count; idx++) {
+ /* attribute order check. This should be same. */
+ if (idx != stream_attrs_const_info[idx].attrid) {
+ _mmstreamrec_dbg_err("Please check attributes order. Is the idx same with enum val?");
+ free(attrs_const_info);
+ attrs_const_info = NULL;
+ return 0;
+ }
+
+ attrs_const_info[idx].name = stream_attrs_const_info[idx].name;
+ attrs_const_info[idx].value_type = stream_attrs_const_info[idx].value_type;
+ attrs_const_info[idx].flags = stream_attrs_const_info[idx].flags;
+ attrs_const_info[idx].default_value = stream_attrs_const_info[idx].default_value.value_void;
+ }
+
+ _mmstreamrec_dbg_log("Create Streamrecorder Attributes[%p, %d]", attrs_const_info, attr_count);
+
+ attrs = mmf_attrs_new_from_data("Streamrecorder_Attributes", attrs_const_info, attr_count, _mmstreamrecorder_commit_streamrecorder_attrs, (void *)handle);
+
+ free(attrs_const_info);
+ attrs_const_info = NULL;
+
+ if (attrs == 0) {
+ _mmstreamrec_dbg_err("Fail to alloc attribute handle");
+ return 0;
+ }
+
+ __mmstreamrecorder_set_conf_to_valid_info(handle);
+
+ for (idx = 0; idx < attr_count; idx++) {
+ mmf_attrs_set_valid_type(attrs, idx, stream_attrs_const_info[idx].validity_type);
+
+ switch (stream_attrs_const_info[idx].validity_type) {
+ case MM_ATTRS_VALID_TYPE_INT_ARRAY:
+ if (stream_attrs_const_info[idx].validity_value1 && stream_attrs_const_info[idx].validity_value2 > 0)
+ mmf_attrs_set_valid_array(attrs, idx, (const int *)(stream_attrs_const_info[idx].validity_value1), stream_attrs_const_info[idx].validity_value2, (int)(stream_attrs_const_info[idx].default_value.value_int));
+ break;
+ case MM_ATTRS_VALID_TYPE_INT_RANGE:
+ mmf_attrs_set_valid_range(attrs, idx, stream_attrs_const_info[idx].validity_value1, stream_attrs_const_info[idx].validity_value2, (int)(stream_attrs_const_info[idx].default_value.value_int));
+ break;
+ case MM_ATTRS_VALID_TYPE_DOUBLE_ARRAY:
+ if (stream_attrs_const_info[idx].validity_value1 && stream_attrs_const_info[idx].validity_value2 > 0)
+ mmf_attrs_set_valid_double_array(attrs, idx, (const double *)(stream_attrs_const_info[idx].validity_value1), stream_attrs_const_info[idx].validity_value2, (double)(stream_attrs_const_info[idx].default_value.value_double));
+ break;
+ case MM_ATTRS_VALID_TYPE_DOUBLE_RANGE:
+ mmf_attrs_set_valid_double_range(attrs, idx, (double)(stream_attrs_const_info[idx].validity_value1), (double)(stream_attrs_const_info[idx].validity_value2), (double)(stream_attrs_const_info[idx].default_value.value_double));
+ break;
+ case MM_ATTRS_VALID_TYPE_NONE:
+ break;
+ case MM_ATTRS_VALID_TYPE_INVALID:
+ default:
+ _mmstreamrec_dbg_err("Valid type error.");
+ break;
+ }
+ }
+
+ __mmstreamrecorder_release_conf_valid_info(handle);
+
+ return attrs;
+}
+
+void _mmstreamrecorder_dealloc_attribute(MMHandleType attrs)
+{
+ _mmstreamrec_dbg_log("");
+
+ if (attrs) {
+ mmf_attrs_free(attrs);
+
+ _mmstreamrec_dbg_log("released attribute");
+ }
+}
+
+int _mmstreamrecorder_get_attributes(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list var_args)
+{
+ MMHandleType attrs = 0;
+ int ret = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail(handle, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ attrs = MMF_STREAMRECORDER_ATTRS(handle);
+ mmf_return_val_if_fail(attrs, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ ret = mm_attrs_get_valist(attrs, err_attr_name, attribute_name, var_args);
+
+ return ret;
+}
+
+int _mmstreamrecorder_set_attributes(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list var_args)
+{
+ MMHandleType attrs = 0;
+ int ret = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail(handle, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ attrs = MMF_STREAMRECORDER_ATTRS(handle);
+ if (!attrs) {
+ _mmstreamrec_dbg_err("handle 0x%x, attrs is NULL, attr name [%s]", handle, attribute_name);
+ return MM_ERROR_STREAMRECORDER_NOT_INITIALIZED;
+ }
+
+ ret = __mmstreamrecorder_check_valid_pair(handle, err_attr_name, attribute_name, var_args);
+
+ _mmstreamrec_dbg_err("__mmstreamrecorder_check_valid_pair handle 0x%x, attr name [%s] , ret = %d", handle, attribute_name, ret);
+
+ if (ret == MM_ERROR_NONE)
+ ret = mm_attrs_set_valist(attrs, err_attr_name, attribute_name, var_args);
+
+ _mmstreamrec_dbg_err("mm_attrs_set_valist handle 0x%x, attr name [%s] , ret = %d", handle, attribute_name, ret);
+ return ret;
+}
+
+int _mmstreamrecorder_get_attribute_info(MMHandleType handle, const char *attr_name, MMStreamRecorderAttrsInfo * info)
+{
+ MMHandleType attrs = 0;
+ MMAttrsInfo attrinfo;
+ int ret = MM_ERROR_NONE;
+
+ mmf_return_val_if_fail(handle, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+ mmf_return_val_if_fail(attr_name, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+ mmf_return_val_if_fail(info, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ attrs = MMF_STREAMRECORDER_ATTRS(handle);
+ mmf_return_val_if_fail(attrs, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ ret = mm_attrs_get_info_by_name(attrs, attr_name, (MMAttrsInfo *) & attrinfo);
+
+ if (ret == MM_ERROR_NONE) {
+ memset(info, 0x00, sizeof(MMStreamRecorderAttrsInfo));
+ info->type = attrinfo.type;
+ info->flag = attrinfo.flag;
+ info->validity_type = attrinfo.validity_type;
+
+ switch (attrinfo.validity_type) {
+ case MM_ATTRS_VALID_TYPE_INT_ARRAY:
+ info->int_array.array = attrinfo.int_array.array;
+ info->int_array.count = attrinfo.int_array.count;
+ info->int_array.def = attrinfo.int_array.dval;
+ break;
+ case MM_ATTRS_VALID_TYPE_INT_RANGE:
+ info->int_range.min = attrinfo.int_range.min;
+ info->int_range.max = attrinfo.int_range.max;
+ info->int_range.def = attrinfo.int_range.dval;
+ break;
+ case MM_ATTRS_VALID_TYPE_DOUBLE_ARRAY:
+ info->double_array.array = attrinfo.double_array.array;
+ info->double_array.count = attrinfo.double_array.count;
+ info->double_array.def = attrinfo.double_array.dval;
+ break;
+ case MM_ATTRS_VALID_TYPE_DOUBLE_RANGE:
+ info->double_range.min = attrinfo.double_range.min;
+ info->double_range.max = attrinfo.double_range.max;
+ info->double_range.def = attrinfo.double_range.dval;
+ break;
+ case MM_ATTRS_VALID_TYPE_NONE:
+ break;
+ case MM_ATTRS_VALID_TYPE_INVALID:
+ default:
+ break;
+ }
+ }
+
+ return ret;
+}
+
+bool _mmstreamrecorder_commit_streamrecorder_attrs(int attr_idx, const char *attr_name, const mmf_value_t * value, void *commit_param)
+{
+ bool bret = FALSE;
+
+ mmf_return_val_if_fail(commit_param, FALSE);
+ mmf_return_val_if_fail(attr_idx >= 0, FALSE);
+ mmf_return_val_if_fail(attr_name, FALSE);
+ mmf_return_val_if_fail(value, FALSE);
+
+ if (stream_attrs_const_info[attr_idx].attr_commit) {
+ /* _mmstreamrec_dbg_log("Dynamic commit:(%s)", attr_name); */
+ __mmstreamrecorder_print_attrs(attr_name, value, "Dynamic");
+ bret = stream_attrs_const_info[attr_idx].attr_commit((MMHandleType) commit_param, attr_idx, value);
+ } else {
+ /* _mmstreamrec_dbg_log("Static commit:(%s)", attr_name); */
+ __mmstreamrecorder_print_attrs(attr_name, value, "Static");
+ bret = TRUE;
+ }
+
+ return bret;
+}
+
+bool _mmstreamrecorder_commit_video_enable(MMHandleType handle, int attr_idx, const mmf_value_t *value)
+{
+ MMHandleType attr = 0;
+ /* mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle); */
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderVideoInfo *info = NULL;
+
+ mmf_return_val_if_fail(handle, FALSE);
+ attr = MMF_STREAMRECORDER_ATTRS(handle);
+ mmf_return_val_if_fail(attr, FALSE);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+
+ _mmstreamrec_dbg_log("(%d)", attr_idx);
+
+ mmf_return_val_if_fail(sc, FALSE);
+
+ info = (_MMStreamRecorderVideoInfo *) sc->info_video;
+
+ if (info == NULL && value->value.i_val != 0) {
+ if (_mmstreamrecorder_alloc_subcontext_videoinfo(handle))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+bool _mmstreamrecorder_commit_video_encoder(MMHandleType handle, int attr_idx, const mmf_value_t *value)
+{
+ MMHandleType attr = 0;
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderVideoInfo *info = NULL;
+
+ mmf_return_val_if_fail(handle, FALSE);
+ attr = MMF_STREAMRECORDER_ATTRS(handle);
+ mmf_return_val_if_fail(attr, FALSE);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, FALSE);
+
+ info = (_MMStreamRecorderVideoInfo *) sc->info_video;
+ mmf_return_val_if_fail(info, FALSE);
+
+ _mmstreamrec_dbg_log("(%d)", attr_idx);
+
+ info->iVideoEncoder = value->value.i_val;
+
+ return TRUE;
+}
+
+bool _mmstreamrecorder_commit_audio_enable(MMHandleType handle, int attr_idx, const mmf_value_t *value)
+{
+ MMHandleType attr = 0;
+ /* mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle); */
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderAudioInfo *info = NULL;
+
+ mmf_return_val_if_fail(handle, FALSE);
+ attr = MMF_STREAMRECORDER_ATTRS(handle);
+ mmf_return_val_if_fail(attr, FALSE);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, FALSE);
+
+ _mmstreamrec_dbg_log("(%d)", attr_idx);
+
+ info = (_MMStreamRecorderAudioInfo *) sc->info_audio;
+
+ if (info == NULL && value->value.i_val != 0) {
+ if (_mmstreamrecorder_alloc_subcontext_audioinfo(handle))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+bool _mmstreamrecorder_commit_audio_encoder(MMHandleType handle, int attr_idx, const mmf_value_t *value)
+{
+ MMHandleType attr = 0;
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderAudioInfo *info = NULL;
+
+ mmf_return_val_if_fail(handle, FALSE);
+ attr = MMF_STREAMRECORDER_ATTRS(handle);
+ mmf_return_val_if_fail(attr, FALSE);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, FALSE);
+
+ info = (_MMStreamRecorderAudioInfo *) sc->info_audio;
+ mmf_return_val_if_fail(info, FALSE);
+
+ _mmstreamrec_dbg_log("(%d)", attr_idx);
+
+ info->iAudioEncoder = value->value.i_val;
+
+ return TRUE;
+}
+
+bool _mmstreamrecorder_commit_audio_samplingrate(MMHandleType handle, int attr_idx, const mmf_value_t *value)
+{
+ MMHandleType attr = 0;
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderAudioInfo *info = NULL;
+
+ mmf_return_val_if_fail(handle, FALSE);
+ attr = MMF_STREAMRECORDER_ATTRS(handle);
+ mmf_return_val_if_fail(attr, FALSE);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, FALSE);
+
+ info = (_MMStreamRecorderAudioInfo *) sc->info_audio;
+ mmf_return_val_if_fail(info, FALSE);
+
+ _mmstreamrec_dbg_log("(%d)", attr_idx);
+
+ info->iSamplingRate = value->value.i_val;
+
+ return TRUE;
+}
+
+bool _mmstreamrecorder_commit_audio_bitformat(MMHandleType handle, int attr_idx, const mmf_value_t *value)
+{
+ MMHandleType attr = 0;
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderAudioInfo *info = NULL;
+
+ mmf_return_val_if_fail(handle, FALSE);
+ attr = MMF_STREAMRECORDER_ATTRS(handle);
+ mmf_return_val_if_fail(attr, FALSE);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, FALSE);
+
+ info = (_MMStreamRecorderAudioInfo *) sc->info_audio;
+ mmf_return_val_if_fail(info, FALSE);
+
+ _mmstreamrec_dbg_log("(%d)", attr_idx);
+
+ if (value->value.i_val == MM_STREAMRECORDER_AUDIO_FORMAT_PCM_U8)
+ info->audio_encode_depth = 16;
+ else
+ info->audio_encode_depth = 8;
+
+ return TRUE;
+}
+
+bool _mmstreamrecorder_commit_video_bitrate(MMHandleType handle, int attr_idx, const mmf_value_t *value)
+{
+ MMHandleType attr = 0;
+ _MMStreamRecorderSubContext *sc = NULL;
+ int v_bitrate;
+
+ mmf_return_val_if_fail(handle, FALSE);
+ attr = MMF_STREAMRECORDER_ATTRS(handle);
+ mmf_return_val_if_fail(attr, FALSE);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, FALSE);
+
+ v_bitrate = value->value.i_val;
+
+ if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst) {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst, "bitrate", v_bitrate);
+ _mmstreamrec_dbg_log("video bitrate set to encoder success = %d", v_bitrate);
+ } else {
+ _mmstreamrec_dbg_log("_MMSTREAMRECORDER_ENCSINK_VENC is null %d", attr_idx);
+ }
+ return TRUE;
+}
+
+bool _mmstreamrecorder_commit_audio_bitrate(MMHandleType handle, int attr_idx, const mmf_value_t *value)
+{
+ MMHandleType attr = 0;
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderAudioInfo *info = NULL;
+
+ mmf_return_val_if_fail(handle, FALSE);
+ attr = MMF_STREAMRECORDER_ATTRS(handle);
+ mmf_return_val_if_fail(attr, FALSE);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, FALSE);
+
+ info = (_MMStreamRecorderAudioInfo *) sc->info_audio;
+ mmf_return_val_if_fail(info, FALSE);
+
+ _mmstreamrec_dbg_log("(%d)", attr_idx);
+
+ info->iBitrate = value->value.i_val;
+
+ return TRUE;
+}
+
+bool _mmstreamrecorder_commit_audio_channel(MMHandleType handle, int attr_idx, const mmf_value_t *value)
+{
+ MMHandleType attr = 0;
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderAudioInfo *info = NULL;
+
+ mmf_return_val_if_fail(handle, FALSE);
+ attr = MMF_STREAMRECORDER_ATTRS(handle);
+ mmf_return_val_if_fail(attr, FALSE);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, FALSE);
+
+ info = (_MMStreamRecorderAudioInfo *) sc->info_audio;
+ mmf_return_val_if_fail(info, FALSE);
+
+ _mmstreamrec_dbg_log("(%d)", attr_idx);
+
+ info->iChannels = value->value.i_val;
+
+ return TRUE;
+}
+
+int mm_streamrecorder_get_attribute_info(MMHandleType streamrecorder, const char *attribute_name, MMStreamRecorderAttrsInfo * info)
+{
+ return _mmstreamrecorder_get_attribute_info(streamrecorder, attribute_name, info);
+}
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 <math.h>
+#include <mm_types.h>
+#include <mm_error.h>
+#include "mm_streamrecorder_audio.h"
+#include "mm_streamrecorder_util.h"
+
+/*---------------------------------------------------------------------------------------
+| LOCAL ARRAY DEFINITIONS for internal |
+---------------------------------------------------------------------------------------*/
+
+/* Table for compatibility between audio codec and file format */
+gboolean common_audiocodec_fileformat_compatibility_table[MM_AUDIO_CODEC_NUM][MM_FILE_FORMAT_NUM] = {
+ /* 3GP ASF AVI MATROSKA MP4 OGG NUT QT REAL AMR AAC MP3 AIFF AU WAV MID MMF DIVX FLV VOB IMELODY WMA WMV JPG */
+ /*AMR*/ {1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*G723.1*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MP3*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*OGG*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*AAC*/ {1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*WMA*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*MMF*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*ADPCM*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*WAVE*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*WAVE_NEW*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*MIDI*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*IMELODY*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*MXMF*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*MPA*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MP2*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*G711*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*G722*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*G722.1*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*G722.2*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*G723*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*G726*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*G728*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*G729*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*G729A*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*G729.1*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*REAL*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*AAC_LC*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*AAC_MAIN*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*AAC_SRS*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*AAC_LTP*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*AAC_HE_V1*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*AAC_HE_V2*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*AC3*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*ALAC*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*ATRAC*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*SPEEX*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*VORBIS*/ {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*AIFF*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*AU*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*NONE*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*PCM*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*ALAW*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*MULAW*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MS_ADPCM*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+};
+
+int _mmstreamrecorder_check_audiocodec_fileformat_compatibility(unsigned int audio_codec, unsigned int file_format)
+{
+
+ /* Check compatibility between audio codec and file format */
+ if (audio_codec < MM_AUDIO_CODEC_NUM && file_format < MM_FILE_FORMAT_NUM) {
+ if (common_audiocodec_fileformat_compatibility_table[audio_codec][file_format] == 0) {
+ _mmstreamrec_dbg_err("Audio codec[%d] and file format[%d] compatibility FAILED.", audio_codec, file_format);
+ return MM_ERROR_STREAMRECORDER_ENCODER_WRONG_TYPE;
+ }
+ _mmstreamrec_dbg_log("Audio codec[%d] and file format[%d] compatibility SUCCESS.", audio_codec, file_format);
+ } else {
+ _mmstreamrec_dbg_err("Audio codec[%d] or file format[%d] is INVALID.", audio_codec, file_format);
+ return MM_ERROR_STREAMRECORDER_ENCODER_WRONG_TYPE;
+ }
+
+ return MM_ERROR_NONE;
+}
+
+int _mmstreamrecorder_get_amrnb_bitrate_mode(int bitrate)
+{
+ int result = MM_STREAMRECORDER_MR475;
+
+ if (bitrate < 5150)
+ result = MM_STREAMRECORDER_MR475; /*AMR475 */
+ else if (bitrate < 5900)
+ result = MM_STREAMRECORDER_MR515; /*AMR515 */
+ else if (bitrate < 6700)
+ result = MM_STREAMRECORDER_MR59; /*AMR59 */
+ else if (bitrate < 7400)
+ result = MM_STREAMRECORDER_MR67; /*AMR67 */
+ else if (bitrate < 7950)
+ result = MM_STREAMRECORDER_MR74; /*AMR74 */
+ else if (bitrate < 10200)
+ result = MM_STREAMRECORDER_MR795; /*AMR795 */
+ else if (bitrate < 12200)
+ result = MM_STREAMRECORDER_MR102; /*AMR102 */
+ else
+ result = MM_STREAMRECORDER_MR122; /*AMR122 */
+
+ return result;
+}
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 <mm_types.h>
+#include <mm_error.h>
+#include <mm_message.h>
+#include "mm_streamrecorder_video.h"
+#include "mm_streamrecorder_util.h"
+#include "mm_streamrecorder_buffer_manager.h"
+#include "mm_streamrecorder_internal.h"
+#include "mm_streamrecorder_gstdispatch.h"
+
+/*---------------------------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS for internal |
+---------------------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------------------
+| LOCAL VARIABLE DEFINITIONS for internal |
+---------------------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS for internal |
+-----------------------------------------------------------------------*/
+
+void _mmstreamrecorder_buffer_destroy(gpointer p_stream_buffer)
+{
+ _MMStreamRecorderMsgItem msg;
+ GstStreamRecorderBuffer *stream_buffer = (GstStreamRecorderBuffer *) p_stream_buffer;
+
+ msg.id = MM_MESSAGE_STREAMRECORDER_CONSUME_COMPLETE;
+ msg.param.union_type = MM_MSG_UNION_CONSUME_RECORDER_BUFFER;
+ msg.param.consumed_mediabuffer.consumed_buffer = stream_buffer->user_buffer;
+ _mmstreamrecorder_send_message(stream_buffer->str_handle, &msg);
+ free(stream_buffer);
+ return;
+}
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <sys/vfs.h> /* struct statfs */
+
+#include "mm_streamrecorder_internal.h"
+#include "mm_streamrecorder_util.h"
+#include "mm_streamrecorder_fileinfo.h"
+
+/*-----------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS for internal |
+-----------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------
+| LOCAL VARIABLE DEFINITIONS for internal |
+-----------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| LOCAL FUNCTION PROTOTYPES: |
+---------------------------------------------------------------------------*/
+/* STATIC INTERNAL FUNCTION */
+
+/*===========================================================================================
+| |
+| FUNCTION DEFINITIONS |
+========================================================================================== */
+/*---------------------------------------------------------------------------
+| GLOBAL FUNCTION DEFINITIONS: |
+---------------------------------------------------------------------------*/
+
+gboolean _mmstreamrecorder_find_fourcc(FILE *f, guint32 tag_fourcc, gboolean do_rewind)
+{
+ guchar buf[8];
+
+ if (do_rewind)
+ rewind(f);
+
+ while (fread(&buf, sizeof(guchar), 8, f) > 0) {
+ unsigned long long buf_size = 0;
+ unsigned int buf_fourcc = MMSTREAMRECORDER_FOURCC(buf[4], buf[5], buf[6], buf[7]);
+
+ if (tag_fourcc == buf_fourcc) {
+ _mmstreamrec_dbg_log("find tag : %c%c%c%c", MMSTREAMRECORDER_FOURCC_ARGS(tag_fourcc));
+ return TRUE;
+ } else if ((buf_fourcc == MMSTREAMRECORDER_FOURCC('m', 'o', 'o', 'v')) && (tag_fourcc != buf_fourcc)) {
+ if (_mmstreamrecorder_find_fourcc(f, tag_fourcc, FALSE))
+ return TRUE;
+ else
+ continue;
+ } else {
+ _mmstreamrec_dbg_log("skip [%c%c%c%c] tag", MMSTREAMRECORDER_FOURCC_ARGS(buf_fourcc));
+
+ buf_size = (unsigned long long)_mmstreamrecorder_get_container_size(buf);
+ buf_size = buf_size - 8; /* include tag */
+
+ do {
+ if (buf_size > _MMSTREAMRECORDER_MAX_INT) {
+ _mmstreamrec_dbg_log("seek %d", _MMSTREAMRECORDER_MAX_INT);
+ if (fseek(f, _MMSTREAMRECORDER_MAX_INT, SEEK_CUR) != 0) {
+ _mmstreamrec_dbg_err("fseek() fail");
+ return FALSE;
+ }
+
+ buf_size -= _MMSTREAMRECORDER_MAX_INT;
+ } else {
+ _mmstreamrec_dbg_log("seek %d", buf_size);
+ if (fseek(f, buf_size, SEEK_CUR) != 0) {
+ _mmstreamrec_dbg_err("fseek() fail");
+ return FALSE;
+ }
+ break;
+ }
+ } while (TRUE);
+ }
+ }
+
+ _mmstreamrec_dbg_log("cannot find tag : %c%c%c%c", MMSTREAMRECORDER_FOURCC_ARGS(tag_fourcc));
+
+ return FALSE;
+}
+
+gboolean _mmstreamrecorder_update_composition_matrix(FILE *f, int orientation)
+{
+ /* for 0 degree */
+ guint32 a = 0x00010000;
+ guint32 b = 0;
+ guint32 c = 0;
+ guint32 d = 0x00010000;
+
+ switch (orientation) {
+ case MM_STREAMRECORDER_TAG_VIDEO_ORT_90: /* 90 degree */
+ a = 0;
+ b = 0x00010000;
+ c = 0xffff0000;
+ d = 0;
+ break;
+ case MM_STREAMRECORDER_TAG_VIDEO_ORT_180: /* 180 degree */
+ a = 0xffff0000;
+ d = 0xffff0000;
+ break;
+ case MM_STREAMRECORDER_TAG_VIDEO_ORT_270: /* 270 degree */
+ a = 0;
+ b = 0xffff0000;
+ c = 0x00010000;
+ d = 0;
+ break;
+ case MM_STREAMRECORDER_TAG_VIDEO_ORT_NONE: /* 0 degree */
+ default:
+ break;
+ }
+
+ write_to_32(f, a);
+ write_to_32(f, b);
+ write_to_32(f, 0);
+ write_to_32(f, c);
+ write_to_32(f, d);
+ write_to_32(f, 0);
+ write_to_32(f, 0);
+ write_to_32(f, 0);
+ write_to_32(f, 0x40000000);
+
+ _mmstreamrec_dbg_log("orientation : %d, write data 0x%x 0x%x 0x%x 0x%x", orientation, a, b, c, d);
+
+ return TRUE;
+}
+
+guint64 _mmstreamrecorder_get_container_size(const guchar *size)
+{
+ guint64 result = 0;
+ guint64 temp = 0;
+
+ temp = size[0];
+ result = temp << 24;
+ temp = size[1];
+ result = result | (temp << 16);
+ temp = size[2];
+ result = result | (temp << 8);
+ result = result | size[3];
+
+ _mmstreamrec_dbg_log("result : %lld", (unsigned long long)result);
+
+ return result;
+}
+
+gboolean _mmstreamrecorder_update_size(FILE *f, gint64 prev_pos, gint64 curr_pos)
+{
+ _mmstreamrec_dbg_log("size : %" G_GINT64_FORMAT "", curr_pos - prev_pos);
+ if (fseek(f, prev_pos, SEEK_SET) != 0) {
+ _mmstreamrec_dbg_err("fseek() fail");
+ return FALSE;
+ }
+
+ if (!write_to_32(f, curr_pos - prev_pos))
+ return FALSE;
+
+ if (fseek(f, curr_pos, SEEK_SET) != 0) {
+ _mmstreamrec_dbg_err("fseek() fail");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+gboolean _mmstreamrecorder_write_udta_m4a(FILE *f)
+{
+ gint64 current_pos, pos;
+
+ _mmstreamrec_dbg_log("");
+
+ if ((pos = ftell(f)) < 0) {
+ _mmstreamrec_dbg_err("ftell() returns negative value");
+ return FALSE;
+ }
+
+ if (!write_to_32(f, 0)) /* udta atomic size */
+ return FALSE;
+
+ if (!write_tag(f, "udta")) /* user data fourcc */
+ return FALSE;
+
+ if ((current_pos = ftell(f)) < 0) {
+ _mmstreamrec_dbg_err("ftell() returns negative value");
+ return FALSE;
+ }
+
+ if (!_mmstreamrecorder_update_size(f, pos, current_pos))
+ return FALSE;
+
+ return TRUE;
+}
+
+gboolean _mmstreamrecorder_write_udta(FILE *f, _MMStreamRecorderLocationInfo info)
+{
+ gint64 current_pos, pos;
+
+ _mmstreamrec_dbg_log("");
+
+ if ((pos = ftell(f)) < 0) {
+ _mmstreamrec_dbg_err("ftell() returns negative value");
+ return FALSE;
+ }
+
+ if (!write_to_32(f, 0)) /*size */
+ return FALSE;
+
+ if (!write_tag(f, "udta")) /* type */
+ return FALSE;
+
+ if ((current_pos = ftell(f)) < 0) {
+ _mmstreamrec_dbg_err("ftell() returns negative value");
+ return FALSE;
+ }
+
+ if (!_mmstreamrecorder_update_size(f, pos, current_pos))
+ return FALSE;
+
+ return TRUE;
+}
+
+/* START TAG HERE */
+gboolean _mmstreamrecorder_audio_add_metadata_info_m4a(MMHandleType handle)
+{
+ FILE *f = NULL;
+ guchar buf[4];
+ guint64 udta_size = 0;
+ gint64 current_pos = 0;
+ gint64 moov_pos = 0;
+ gint64 udta_pos = 0;
+ char err_msg[128] = { '\0', };
+
+ _MMStreamRecorderFileInfo *finfo = NULL;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ mmf_return_val_if_fail(sc->info_file, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ finfo = sc->info_file;
+
+ f = fopen(finfo->filename, "rb+");
+ if (f == NULL) {
+ strerror_r(errno, err_msg, 128);
+ _mmstreamrec_dbg_err("file open failed [%s]", err_msg);
+ return FALSE;
+ }
+
+ /* find udta container.
+ if, there are udta container, write loci box after that
+ else, make udta container and write loci box. */
+ if (_mmstreamrecorder_find_fourcc(f, MMSTREAMRECORDER_FOURCC('u', 'd', 't', 'a'), TRUE)) {
+ size_t nread = 0;
+
+ _mmstreamrec_dbg_log("find udta container");
+
+ /* read size */
+ if (fseek(f, -8L, SEEK_CUR) != 0)
+ goto fail;
+
+ udta_pos = ftell(f);
+ if (udta_pos < 0)
+ goto ftell_fail;
+
+ nread = fread(&buf, sizeof(char), sizeof(buf), f);
+
+ _mmstreamrec_dbg_log("recorded file fread %d", nread);
+
+ udta_size = _mmstreamrecorder_get_container_size(buf);
+
+ /* goto end of udta and write 'smta' box */
+ if (fseek(f, (udta_size - 4L), SEEK_CUR) != 0)
+ goto fail;
+
+ current_pos = ftell(f);
+ if (current_pos < 0)
+ goto ftell_fail;
+
+ if (!_mmstreamrecorder_update_size(f, udta_pos, current_pos))
+ goto fail;
+ } else {
+ _mmstreamrec_dbg_log("No udta container");
+ if (fseek(f, 0, SEEK_END) != 0)
+ goto fail;
+
+ if (!_mmstreamrecorder_write_udta_m4a(f))
+ goto fail;
+ }
+
+ /* find moov container.
+ update moov container size. */
+ if ((current_pos = ftell(f)) < 0)
+ goto ftell_fail;
+
+ if (_mmstreamrecorder_find_fourcc(f, MMSTREAMRECORDER_FOURCC('m', 'o', 'o', 'v'), TRUE)) {
+
+ _mmstreamrec_dbg_log("found moov container");
+ if (fseek(f, -8L, SEEK_CUR) != 0)
+ goto fail;
+
+ moov_pos = ftell(f);
+ if (moov_pos < 0)
+ goto ftell_fail;
+
+ if (!_mmstreamrecorder_update_size(f, moov_pos, current_pos))
+ goto fail;
+
+ } else {
+ _mmstreamrec_dbg_err("No 'moov' container");
+ goto fail;
+ }
+
+ fclose(f);
+ return TRUE;
+
+ fail:
+ fclose(f);
+ return FALSE;
+
+ ftell_fail:
+ _mmstreamrec_dbg_err("ftell() returns negative value.");
+ fclose(f);
+ return FALSE;
+}
+
+/* END TAG HERE */
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 <sys/time.h>
+#include <unistd.h>
+
+#include "mm_streamrecorder_internal.h"
+#include "mm_streamrecorder_gstcommon.h"
+#include "mm_streamrecorder_gstdispatch.h"
+#include "mm_streamrecorder_util.h"
+#include "mm_streamrecorder.h"
+
+/*-----------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS for internal |
+-----------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------
+| LOCAL VARIABLE DEFINITIONS for internal |
+-----------------------------------------------------------------------*/
+#define USE_AUDIO_CLOCK_TUNE
+#define _MMSTREAMRECORDER_WAIT_EOS_TIME 5.0 /* sec */
+#define _MMSTREAMRECORDER_STATE_SET_COUNT 3
+
+/*-----------------------------------------------------------------------
+| LOCAL FUNCTION PROTOTYPES: |
+-----------------------------------------------------------------------*/
+/* STATIC INTERNAL FUNCTION */
+
+/*=======================================================================================
+| FUNCTION DEFINITIONS |
+=======================================================================================*/
+/*-----------------------------------------------------------------------
+| GLOBAL FUNCTION DEFINITIONS: |
+-----------------------------------------------------------------------*/
+gboolean _mmstreamrecorder_gstreamer_init()
+{
+ static const int max_argc = 10;
+ int i = 0;
+ gint *argc = NULL;
+ gchar **argv = NULL;
+ GError *err = NULL;
+ gboolean ret = FALSE;
+ /* type_string_array *GSTInitOption = NULL; */
+
+ /* mmf_return_val_if_fail(conf, FALSE); */
+
+ _mmstreamrec_dbg_log("");
+
+ /* alloc */
+ argc = malloc(sizeof(int));
+ argv = malloc(sizeof(gchar *) * max_argc);
+
+ if (!argc || !argv)
+ goto ERROR;
+
+ memset(argv, 0, sizeof(gchar *) * max_argc);
+
+ /* add initial */
+ *argc = 1;
+ argv[0] = g_strdup("mmstreamrecorder");
+
+ _mmstreamrec_dbg_log("initializing gstreamer with following parameter[argc:%d]", *argc);
+
+ for (i = 0; i < *argc; i++)
+ _mmstreamrec_dbg_log("argv[%d] : %s", i, argv[i]);
+
+ /* initializing gstreamer */
+ ret = gst_init_check(argc, &argv, &err);
+
+ if (!ret) {
+ _mmstreamrec_dbg_err("Could not initialize GStreamer: %s ", err ? err->message : "unknown error occurred");
+ if (err)
+ g_error_free(err);
+ }
+
+ /* release */
+
+ for (i = 0; i < *argc; i++) {
+ if (argv[i]) {
+ g_free(argv[i]);
+ argv[i] = NULL;
+ }
+ }
+
+ if (argv) {
+ g_free(argv);
+ argv = NULL;
+ }
+
+ if (argc) {
+ g_free(argc);
+ argc = NULL;
+ }
+
+ return ret;
+
+ ERROR:
+ _mmstreamrec_dbg_err("failed to initialize gstreamer");
+
+ if (argv) {
+ g_free(argv);
+ argv = NULL;
+ }
+
+ if (argc) {
+ g_free(argc);
+ argc = NULL;
+ }
+
+ return FALSE;
+}
+
+int _mmstreamrecorder_get_eos_message(MMHandleType handle)
+{
+ double elapsed = 0.0;
+
+ GstMessage *gMessage = NULL;
+ GstBus *bus = NULL;
+ GstClockTime timeout = 1 * GST_SECOND; /* maximum waiting time */
+ GTimer *timer = NULL;
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+
+ _mmstreamrec_dbg_log("");
+ if (sc) {
+ bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst));
+ timer = g_timer_new();
+
+ if (!(sc->bget_eos)) {
+ while (TRUE) {
+ elapsed = g_timer_elapsed(timer, NULL);
+
+ /*_mmstreamrec_dbg_log("elapsed:%f sec", elapsed);*/
+
+ if (elapsed > _MMSTREAMRECORDER_WAIT_EOS_TIME) {
+ _mmstreamrec_dbg_warn("Timeout. EOS isn't received.");
+ g_timer_destroy(timer);
+ gst_object_unref(bus);
+ return MM_ERROR_STREAMRECORDER_RESPONSE_TIMEOUT;
+ }
+
+ gMessage = gst_bus_timed_pop(bus, timeout);
+ if (gMessage != NULL) {
+ _mmstreamrec_dbg_log("Get message(%x).", GST_MESSAGE_TYPE(gMessage));
+ _mmstreamrecorder_pipeline_cb_message(bus, gMessage, (void *)hstreamrecorder);
+
+ if (GST_MESSAGE_TYPE(gMessage) == GST_MESSAGE_EOS || sc->bget_eos) {
+ gst_message_unref(gMessage);
+ break;
+ }
+ gst_message_unref(gMessage);
+ } else {
+ _mmstreamrec_dbg_log("timeout of gst_bus_timed_pop()");
+ if (sc->bget_eos) {
+ _mmstreamrec_dbg_log("Get EOS in another thread.");
+ break;
+ }
+ }
+ }
+ }
+
+ g_timer_destroy(timer);
+ timer = NULL;
+ gst_object_unref(bus);
+ bus = NULL;
+ } else {
+ _mmstreamrec_dbg_err("subcontext error NULL");
+ }
+ _mmstreamrec_dbg_log("END");
+
+ return MM_ERROR_NONE;
+}
+
+void _mmstreamrecorder_remove_element_handle(MMHandleType handle, void *element, int first_elem, int last_elem)
+{
+ int i = 0;
+ _MMStreamRecorderGstElement *remove_element = (_MMStreamRecorderGstElement *) element;
+
+ mmf_return_if_fail(handle && remove_element);
+ mmf_return_if_fail((first_elem >= 0) && (last_elem > 0) && (last_elem > first_elem));
+
+ _mmstreamrec_dbg_log("");
+
+ for (i = first_elem; i <= last_elem; i++) {
+ remove_element[i].gst = NULL;
+ remove_element[i].id = _MMSTREAMRECORDER_ENCODE_NONE;
+ }
+
+ return;
+}
+
+gboolean _mmstreamrecorder_add_elements_to_bin(GstBin *bin, GList *element_list)
+{
+ GList *local_list = element_list;
+ _MMStreamRecorderGstElement *element = NULL;
+
+ mmf_return_val_if_fail(bin && local_list, FALSE);
+
+ while (local_list) {
+ element = (_MMStreamRecorderGstElement *) local_list->data;
+ if (element && element->gst) {
+ if (!gst_bin_add(bin, GST_ELEMENT(element->gst))) {
+ _mmstreamrec_dbg_err("Add element [%s] to bin [%s] FAILED", GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), GST_ELEMENT_NAME(GST_ELEMENT(bin)));
+ return FALSE;
+ } else {
+ _mmstreamrec_dbg_log("Add element [%s] to bin [%s] OK", GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), GST_ELEMENT_NAME(GST_ELEMENT(bin)));
+ }
+ }
+ local_list = local_list->next;
+ }
+
+ return TRUE;
+}
+
+gboolean _mmstreamrecorder_link_elements(GList * element_list)
+{
+ GList *local_list = element_list;
+ _MMStreamRecorderGstElement *element = NULL;
+ _MMStreamRecorderGstElement *pre_element = NULL;
+
+ mmf_return_val_if_fail(local_list, FALSE);
+
+ pre_element = (_MMStreamRecorderGstElement *) local_list->data;
+ local_list = local_list->next;
+
+ while (local_list) {
+ element = (_MMStreamRecorderGstElement *) local_list->data;
+ if (element && element->gst) {
+ if (pre_element != NULL) {
+ if (_MM_GST_ELEMENT_LINK(GST_ELEMENT(pre_element->gst), GST_ELEMENT(element->gst))) {
+ _mmstreamrec_dbg_log("Link [%s] to [%s] OK", GST_ELEMENT_NAME(GST_ELEMENT(pre_element->gst)), GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
+ } else {
+ _mmstreamrec_dbg_err("Link [%s] to [%s] FAILED", GST_ELEMENT_NAME(GST_ELEMENT(pre_element->gst)), GST_ELEMENT_NAME(GST_ELEMENT(element->gst)));
+ return FALSE;
+ }
+ } else {
+ _mmstreamrec_dbg_err("pre_element is null");
+ return FALSE;
+ }
+ }
+
+ pre_element = element;
+ local_list = local_list->next;
+ }
+
+ return TRUE;
+}
+
+int _mmstreamrecorder_gst_set_state(MMHandleType handle, GstElement *pipeline, GstState target_state)
+{
+ unsigned int k = 0;
+ GstState pipeline_state = GST_STATE_VOID_PENDING;
+ GstStateChangeReturn setChangeReturn = GST_STATE_CHANGE_FAILURE;
+ GstStateChangeReturn getChangeReturn = GST_STATE_CHANGE_FAILURE;
+ GstClockTime get_timeout = __MMSTREAMRECORDER_SET_GST_STATE_TIMEOUT * GST_SECOND;
+
+ mmf_return_val_if_fail(handle, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ _mmstreamrec_dbg_log("Set state to %d", target_state);
+
+ _MMSTREAMRECORDER_LOCK_GST_STATE(handle);
+
+ for (k = 0; k < _MMSTREAMRECORDER_STATE_SET_COUNT; k++) {
+ setChangeReturn = gst_element_set_state(pipeline, target_state);
+ _mmstreamrec_dbg_log("gst_element_set_state[%d] return %d", target_state, setChangeReturn);
+ if (setChangeReturn != GST_STATE_CHANGE_FAILURE) {
+ getChangeReturn = gst_element_get_state(pipeline, &pipeline_state, NULL, get_timeout);
+ switch (getChangeReturn) {
+ case GST_STATE_CHANGE_NO_PREROLL:
+ _mmstreamrec_dbg_log("status=GST_STATE_CHANGE_NO_PREROLL.");
+ case GST_STATE_CHANGE_SUCCESS:
+ /* if we reached the final target state, exit */
+ if (pipeline_state == target_state) {
+ _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle);
+ return MM_ERROR_NONE;
+ }
+ break;
+ case GST_STATE_CHANGE_ASYNC:
+ _mmstreamrec_dbg_log("status=GST_STATE_CHANGE_ASYNC.");
+ break;
+ default:
+ _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle);
+ _mmstreamrec_dbg_log("status=GST_STATE_CHANGE_FAILURE.");
+ return MM_ERROR_STREAMRECORDER_GST_STATECHANGE;
+ }
+
+ _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle);
+ _mmstreamrec_dbg_err("timeout of gst_element_get_state()!!");
+ return MM_ERROR_STREAMRECORDER_RESPONSE_TIMEOUT;
+ }
+ usleep(_MMSTREAMRECORDER_STATE_CHECK_INTERVAL);
+ }
+
+ _MMSTREAMRECORDER_UNLOCK_GST_STATE(handle);
+
+ _mmstreamrec_dbg_err("Failure. gst_element_set_state timeout!!");
+
+ return MM_ERROR_STREAMRECORDER_RESPONSE_TIMEOUT;
+}
+
+GstCaps *gst_set_videosrcpad_caps(gint srcfmt, gint width, gint height, gint rate, gint scale)
+{
+
+ GstCaps *caps = NULL;
+
+ if (srcfmt == MM_STREAMRECORDER_INPUT_FORMAT_NV12)
+ caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "NV12", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, rate, scale, NULL);
+ else if (srcfmt == MM_STREAMRECORDER_INPUT_FORMAT_I420)
+ caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "I420", "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, rate, scale, NULL);
+ else
+ caps = gst_caps_new_simple("video/x-raw", "format", G_TYPE_STRING, "BGRA8888", "bpp", G_TYPE_INT, 32, "depth", G_TYPE_INT, 24, "endianness", G_TYPE_INT, 4321, "red_mask", G_TYPE_INT, 65280, "green_mask", G_TYPE_INT, 16711680, "blue_mask", G_TYPE_INT, -16777216, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, "framerate", GST_TYPE_FRACTION, rate, scale, NULL);
+
+ if (!caps) {
+ _mmstreamrec_dbg_err("failed to alloc caps");
+ return NULL;
+ }
+
+ /* gchar *type = gst_caps_to_string(caps); */
+
+ /* _mmstreamrec_dbg_warn("Set srcpad caps: %s",type); */
+
+ /* g_free(type); */
+
+ return caps;
+}
+
+GstCaps *gst_set_audiosrcpad_caps(gint samplerate, gint channel, gint depth, gint width, gint datatype)
+{
+
+ GstCaps *caps = gst_caps_new_simple("audio/x-raw",
+ "rate", G_TYPE_INT, samplerate,
+ "channels", G_TYPE_INT, 2,
+ "depth", G_TYPE_INT, depth,
+ "width", G_TYPE_INT, width,
+ "signed", G_TYPE_BOOLEAN, TRUE,
+ "endianness", G_TYPE_INT, 1234,
+ NULL);
+
+ if (!caps) {
+ _mmstreamrec_dbg_err("failed to alloc caps");
+ return NULL;
+ }
+
+ /* gchar *type = gst_caps_to_string(caps); */
+
+ /* _mmstreamrec_dbg_log("Set srcpad caps: %s", type); */
+
+ /* g_free(type); */
+
+ return caps;
+}
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <sys/vfs.h> /* struct statfs */
+
+#include "mm_streamrecorder_internal.h"
+#include "mm_streamrecorder_gstdispatch.h"
+#include "mm_streamrecorder_gstcommon.h"
+#include "mm_streamrecorder_util.h"
+#include "mm_streamrecorder_recorder.h"
+
+/*-----------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS for internal |
+-----------------------------------------------------------------------*/
+
+#define _MMSTREAMRECORDER_MINIMUM_FRAME 5
+#define _MMSTREAMRECORDER_FREE_SPACE_CHECK_INTERVAL 5
+#define _MMSTREAMRECORDER_MINIMUM_SPACE (512*1024) /* byte */
+#define _MMSTREAMRECORDER_MMS_MARGIN_SPACE (512) /* byte */
+#define _MMSTREAMRECORDER_AUDIO_FREE_SPACE_CHECK_INTERVAL 10
+#define _MMSTREAMRECORDER_AUDIO_MINIMUM_SPACE (100*1024)
+
+/*-----------------------------------------------------------------------
+| LOCAL VARIABLE DEFINITIONS for internal |
+-----------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------
+| LOCAL FUNCTION PROTOTYPES: |
+---------------------------------------------------------------------------*/
+/* STATIC INTERNAL FUNCTION */
+
+/*===========================================================================================
+| |
+| FUNCTION DEFINITIONS |
+========================================================================================== */
+/*---------------------------------------------------------------------------
+| GLOBAL FUNCTION DEFINITIONS: |
+---------------------------------------------------------------------------*/
+void _mmstreamrecorder_remove_buffer_probe(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ GList *list = NULL;
+ MMStreamRecorderHandlerItem *item = NULL;
+
+ mmf_return_if_fail(hstreamrecorder);
+
+ if (!hstreamrecorder->buffer_probes) {
+ _mmstreamrec_dbg_warn("list for buffer probe is NULL");
+ return;
+ }
+
+ _mmstreamrec_dbg_log("start - category : 0x%x", category);
+
+ list = hstreamrecorder->buffer_probes;
+ while (list) {
+ item = list->data;
+ if (!item) {
+ _mmstreamrec_dbg_err("Remove buffer probe faild, the item is NULL");
+ list = g_list_next(list);
+ continue;
+ }
+
+ if (item->category & category) {
+ if (item->object && GST_IS_PAD(item->object)) {
+ _mmstreamrec_dbg_log("Remove buffer probe on [%s:%s] - [ID : %lu], [Category : %x]", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category);
+ gst_pad_remove_probe(GST_PAD(item->object), item->handler_id);
+ } else {
+ _mmstreamrec_dbg_warn("Remove buffer probe faild, the pad is null or not pad, just remove item from list and free it");
+ }
+
+ list = g_list_next(list);
+ hstreamrecorder->buffer_probes = g_list_remove(hstreamrecorder->buffer_probes, item);
+ SAFE_FREE(item);
+ } else {
+ _mmstreamrec_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
+ list = g_list_next(list);
+ }
+ }
+
+ if (category == _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL) {
+ g_list_free(hstreamrecorder->buffer_probes);
+ hstreamrecorder->buffer_probes = NULL;
+ }
+
+ _mmstreamrec_dbg_log("done");
+
+ return;
+}
+
+void _mmstreamrecorder_remove_event_probe(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ GList *list = NULL;
+ MMStreamRecorderHandlerItem *item = NULL;
+
+ mmf_return_if_fail(hstreamrecorder);
+
+ if (!hstreamrecorder->event_probes) {
+ _mmstreamrec_dbg_warn("list for event probe is NULL");
+ return;
+ }
+
+ _mmstreamrec_dbg_log("start - category : 0x%x", category);
+
+ list = hstreamrecorder->event_probes;
+ while (list) {
+ item = list->data;
+ if (!item) {
+ _mmstreamrec_dbg_err("Remove event probe faild, the item is NULL");
+ list = g_list_next(list);
+ continue;
+ }
+
+ if (item->category & category) {
+ if (item->object && GST_IS_PAD(item->object)) {
+ _mmstreamrec_dbg_log("Remove event probe on [%s:%s] - [ID : %lu], [Category : %x]", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category);
+ gst_pad_remove_probe(GST_PAD(item->object), item->handler_id);
+ } else {
+ _mmstreamrec_dbg_warn("Remove event probe faild, the pad is null or not pad, just remove item from list and free it");
+ }
+
+ list = g_list_next(list);
+ hstreamrecorder->event_probes = g_list_remove(hstreamrecorder->event_probes, item);
+ SAFE_FREE(item);
+ } else {
+ _mmstreamrec_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
+ list = g_list_next(list);
+ }
+ }
+
+ if (category == _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL) {
+ g_list_free(hstreamrecorder->event_probes);
+ hstreamrecorder->event_probes = NULL;
+ }
+
+ _mmstreamrec_dbg_log("done");
+
+ return;
+}
+
+void _mmstreamrecorder_remove_data_probe(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ GList *list = NULL;
+ MMStreamRecorderHandlerItem *item = NULL;
+
+ mmf_return_if_fail(hstreamrecorder);
+
+ if (!hstreamrecorder->data_probes) {
+ _mmstreamrec_dbg_warn("list for data probe is NULL");
+ return;
+ }
+
+ _mmstreamrec_dbg_log("start - category : 0x%x", category);
+
+ list = hstreamrecorder->data_probes;
+ while (list) {
+ item = list->data;
+ if (!item) {
+ _mmstreamrec_dbg_err("Remove data probe faild, the item is NULL");
+ list = g_list_next(list);
+ continue;
+ }
+
+ if (item->category & category) {
+ if (item->object && GST_IS_PAD(item->object)) {
+ _mmstreamrec_dbg_log("Remove data probe on [%s:%s] - [ID : %lu], [Category : %x]", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category);
+ gst_pad_remove_probe(GST_PAD(item->object), item->handler_id);
+ } else {
+ _mmstreamrec_dbg_warn("Remove data probe faild, the pad is null or not pad, just remove item from list and free it");
+ }
+
+ list = g_list_next(list);
+ hstreamrecorder->data_probes = g_list_remove(hstreamrecorder->data_probes, item);
+ SAFE_FREE(item);
+ } else {
+ _mmstreamrec_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
+ list = g_list_next(list);
+ }
+ }
+
+ if (category == _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL) {
+ g_list_free(hstreamrecorder->data_probes);
+ hstreamrecorder->data_probes = NULL;
+ }
+
+ _mmstreamrec_dbg_log("done");
+
+ return;
+}
+
+void _mmstreamrecorder_disconnect_signal(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ GList *list = NULL;
+ MMStreamRecorderHandlerItem *item = NULL;
+
+ mmf_return_if_fail(hstreamrecorder);
+
+ if (!hstreamrecorder->signals) {
+ _mmstreamrec_dbg_warn("list for signal is NULL");
+ return;
+ }
+
+ _mmstreamrec_dbg_log("start - category : 0x%x", category);
+
+ list = hstreamrecorder->signals;
+ while (list) {
+ item = list->data;
+ if (!item) {
+ _mmstreamrec_dbg_err("Fail to Disconnecting signal, the item is NULL");
+ list = g_list_next(list);
+ continue;
+ }
+
+ if (item->category & category) {
+ if (item->object && GST_IS_ELEMENT(item->object)) {
+ if (g_signal_handler_is_connected(item->object, item->handler_id)) {
+ _mmstreamrec_dbg_log("Disconnect signal from [%s] : [ID : %lu], [Category : %x]", GST_OBJECT_NAME(item->object), item->handler_id, item->category);
+ g_signal_handler_disconnect(item->object, item->handler_id);
+ } else {
+ _mmstreamrec_dbg_warn("Signal was not connected, cannot disconnect it : [%s] [ID : %lu], [Category : %x]", GST_OBJECT_NAME(item->object), item->handler_id, item->category);
+ }
+ } else {
+ _mmstreamrec_dbg_err("Fail to Disconnecting signal, the element is null or not element, just remove item from list and free it");
+ }
+
+ list = g_list_next(list);
+ hstreamrecorder->signals = g_list_remove(hstreamrecorder->signals, item);
+ SAFE_FREE(item);
+ } else {
+ _mmstreamrec_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category);
+ list = g_list_next(list);
+ }
+ }
+
+ if (category == _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL) {
+ g_list_free(hstreamrecorder->signals);
+ hstreamrecorder->signals = NULL;
+ }
+
+ _mmstreamrec_dbg_log("done");
+
+ return;
+}
+
+void _mmstreamrecorder_element_release_noti(gpointer data, GObject *where_the_object_was)
+{
+ int i = 0;
+ _MMStreamRecorderSubContext *sc = (_MMStreamRecorderSubContext *) data;
+
+ mmf_return_if_fail(sc);
+
+ mmf_return_if_fail(sc->encode_element);
+
+ for (i = 0; i < _MMSTREAMRECORDER_ENCODE_PIPELINE_ELEMENT_NUM; i++) {
+ if (sc->encode_element[i].gst && (G_OBJECT(sc->encode_element[i].gst) == where_the_object_was)) {
+ _mmstreamrec_dbg_warn("The encode element[%d][%p] is finalized", sc->encode_element[i].id, sc->encode_element[i].gst);
+ sc->encode_element[i].gst = NULL;
+ sc->encode_element[i].id = _MMSTREAMRECORDER_ENCODE_NONE;
+ return;
+ }
+ }
+
+ _mmstreamrec_dbg_warn("there is no matching element %p", where_the_object_was);
+
+ return;
+}
+
+gboolean _mmstreamrecorder_msg_callback(void *data)
+{
+ _MMStreamRecorderMsgItem *item = (_MMStreamRecorderMsgItem *) data;
+ mmf_streamrecorder_t *hstreamrecorder = NULL;
+ mmf_return_val_if_fail(item, FALSE);
+
+ hstreamrecorder = MMF_STREAMRECORDER(item->handle);
+ mmf_return_val_if_fail(hstreamrecorder, FALSE);
+
+ /* _mmstreamrec_dbg_log("msg id:%x, msg_cb:%p, msg_data:%p, item:%p", item->id, hstreamrecorder->msg_cb, hstreamrecorder->msg_data, item); */
+ _MMSTREAMRECORDER_LOCK_MESSAGE_CALLBACK(hstreamrecorder);
+
+ if ((hstreamrecorder) && (hstreamrecorder->msg_cb))
+ hstreamrecorder->msg_cb(item->id, (MMMessageParamType *) (&(item->param)), hstreamrecorder->msg_cb_param);
+
+ _MMSTREAMRECORDER_UNLOCK_MESSAGE_CALLBACK(hstreamrecorder);
+
+ _MMSTREAMRECORDER_LOCK((MMHandleType) hstreamrecorder);
+ if (hstreamrecorder->msg_data)
+ hstreamrecorder->msg_data = g_list_remove(hstreamrecorder->msg_data, item);
+
+ free(item);
+ item = NULL;
+ _MMSTREAMRECORDER_UNLOCK((MMHandleType) hstreamrecorder);
+ /* For not being called again */
+ return FALSE;
+}
+
+void _mmstreamrecorder_remove_all_handlers(MMHandleType handle, _MMStreamRecorderHandlerCategory category)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ _mmstreamrec_dbg_log("ENTER");
+
+ if (hstreamrecorder->signals)
+ _mmstreamrecorder_disconnect_signal((MMHandleType) hstreamrecorder, category);
+ if (hstreamrecorder->data_probes)
+ _mmstreamrecorder_remove_data_probe((MMHandleType) hstreamrecorder, category);
+ if (hstreamrecorder->event_probes)
+ _mmstreamrecorder_remove_event_probe((MMHandleType) hstreamrecorder, category);
+ if (hstreamrecorder->buffer_probes)
+ _mmstreamrecorder_remove_buffer_probe((MMHandleType) hstreamrecorder, category);
+
+ _mmstreamrec_dbg_log("LEAVE");
+}
+
+gboolean _mmstreamrecorder_send_message(MMHandleType handle, _MMStreamRecorderMsgItem *data)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderMsgItem *item = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, FALSE);
+ mmf_return_val_if_fail(data, FALSE);
+
+ /* _mmstreamrec_dbg_err("ENTER"); */
+
+ /* _mmstreamrec_dbg_err("data->id = %x",data->id); */
+
+ switch (data->id) {
+ case MM_MESSAGE_STREAMRECORDER_STATE_CHANGED:
+ data->param.union_type = MM_MSG_UNION_STATE;
+ break;
+ case MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS:
+ data->param.union_type = MM_MSG_UNION_RECORDING_STATUS;
+ break;
+ case MM_MESSAGE_STREAMRECORDER_CONSUME_COMPLETE: /* 0x801 */
+ data->param.union_type = MM_MSG_UNION_CONSUME_RECORDER_BUFFER;
+ break;
+ case MM_MESSAGE_STREAMRECORDER_TIME_LIMIT:
+ case MM_MESSAGE_STREAMRECORDER_MAX_SIZE:
+ case MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE:
+ case MM_MESSAGE_STREAMRECORDER_ERROR:
+ case MM_MESSAGE_STREAMRECORDER_VIDEO_CAPTURED:
+ case MM_MESSAGE_STREAMRECORDER_AUDIO_CAPTURED:
+ case MM_MESSAGE_READY_TO_RESUME:
+ default:
+ data->param.union_type = MM_MSG_UNION_CODE;
+ break;
+ }
+
+ item = g_malloc(sizeof(_MMStreamRecorderMsgItem));
+ if (!item)
+ return FALSE;
+ memcpy(item, data, sizeof(_MMStreamRecorderMsgItem));
+ item->handle = handle;
+
+ _MMSTREAMRECORDER_LOCK(handle);
+ hstreamrecorder->msg_data = g_list_append(hstreamrecorder->msg_data, item);
+ /* _mmstreamrec_dbg_log("item[%p]", item); */
+
+ /* Use DEFAULT priority */
+ g_idle_add_full(G_PRIORITY_DEFAULT, _mmstreamrecorder_msg_callback, item, NULL);
+
+ _MMSTREAMRECORDER_UNLOCK(handle);
+
+ return TRUE;
+}
+
+gboolean _mmstreamrecorder_remove_message_all(MMHandleType handle)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderMsgItem *item = NULL;
+ gboolean ret = TRUE;
+ GList *list = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, FALSE);
+
+ _MMSTREAMRECORDER_LOCK(handle);
+
+ if (hstreamrecorder->msg_data) {
+ list = hstreamrecorder->msg_data;
+
+ while (list) {
+ item = list->data;
+ list = g_list_next(list);
+
+ if (item) {
+ ret = g_idle_remove_by_data(item);
+ _mmstreamrec_dbg_log("Remove item[%p]. ret[%d]", item, ret);
+
+ hstreamrecorder->msg_data = g_list_remove(hstreamrecorder->msg_data, item);
+
+ SAFE_FREE(item);
+ }
+ }
+
+ g_list_free(hstreamrecorder->msg_data);
+ hstreamrecorder->msg_data = NULL;
+ }
+
+ /* remove idle function for playing capture sound */
+ do {
+ ret = g_idle_remove_by_data(hstreamrecorder);
+ _mmstreamrec_dbg_log("remove idle function for playing capture sound. ret[%d]", ret);
+ } while (ret);
+
+ _MMSTREAMRECORDER_UNLOCK(handle);
+
+ return ret;
+}
+
+gboolean _mmstreamrecorder_handle_gst_error(MMHandleType handle, GstMessage *message, GError *error)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ /* _MMstreamrecorderMsgItem msg; */
+ gchar *msg_src_element;
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ return_val_if_fail(hstreamrecorder, FALSE);
+ return_val_if_fail(error, FALSE);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, FALSE);
+
+ _mmstreamrec_dbg_log("");
+
+ /* filtering filesink related errors */
+ if ((error->code == GST_RESOURCE_ERROR_WRITE || error->code == GST_RESOURCE_ERROR_SEEK)) {
+ if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
+ sc->ferror_send = TRUE;
+ /* msg.param.code = __mmstreamrecorder_gst_handle_resource_error(handle, error->code, message); */
+ } else {
+ sc->ferror_count++;
+ _mmstreamrec_dbg_warn("Skip error");
+ return TRUE;
+ }
+ }
+
+ if (error->domain == GST_CORE_ERROR) {
+ /* msg.param.code = __mmstreamrecorder_gst_handle_core_error(handle, error->code, message); */
+ } else if (error->domain == GST_LIBRARY_ERROR) {
+ /* msg.param.code = __mmstreamrecorder_gst_handle_library_error(handle, error->code, message); */
+ } else if (error->domain == GST_RESOURCE_ERROR) {
+ /* msg.param.code = __mmstreamrecorder_gst_handle_resource_error(handle, error->code, message); */
+ } else if (error->domain == GST_STREAM_ERROR) {
+ /* msg.param.code = __mmstreamrecorder_gst_handle_stream_error(handle, error->code, message); */
+ } else {
+ _mmstreamrec_dbg_warn("This error domain is not defined.");
+
+ /* we treat system error as an internal error */
+ /* msg.param.code = MM_ERROR_streamrecorder_INTERNAL; */
+ }
+
+ if (message->src) {
+ msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src));
+/* _mmstreamrec_dbg_err("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
+ msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg.param.code); */
+ } else {
+/* _mmstreamrec_dbg_err("Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]",
+ g_quark_to_string (error->domain), error->message, error->code, msg.param.code); */
+ }
+
+#ifdef _MMSTREAMRECORDER_SKIP_GST_FLOW_ERROR
+ /* Check whether send this error to application */
+/* if (msg.param.code == MM_ERROR_streamrecorder_GST_FLOW_ERROR) {
+ _mmstreamrec_dbg_log("We got the error. But skip it.");
+ return TRUE;
+ } */
+#endif /* _MMstreamrecorder_SKIP_GST_FLOW_ERROR */
+
+ /* post error to application */
+ sc->error_occurs = TRUE;
+/* msg.id = MM_MESSAGE_streamrecorder_ERROR;
+ _mmstreamrecorder_send_message(handle, &msg); */
+
+ return TRUE;
+}
+
+gint _mmstreamrecorder_gst_handle_core_error(MMHandleType handle, int code, GstMessage *message)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ GstElement *element = NULL;
+
+ _mmstreamrec_dbg_log("");
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ /* Specific plugin - video encoder plugin */
+ element = GST_ELEMENT_CAST(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst);
+
+ if (GST_ELEMENT_CAST(message->src) == element) {
+ if (code == GST_CORE_ERROR_NEGOTIATION)
+ return MM_ERROR_STREAMRECORDER_GST_NEGOTIATION;
+ else
+ return MM_ERROR_STREAMRECORDER_ENCODER;
+ }
+
+ /* General */
+ switch (code) {
+ case GST_CORE_ERROR_STATE_CHANGE:
+ return MM_ERROR_STREAMRECORDER_GST_STATECHANGE;
+ case GST_CORE_ERROR_NEGOTIATION:
+ return MM_ERROR_STREAMRECORDER_GST_NEGOTIATION;
+ case GST_CORE_ERROR_MISSING_PLUGIN:
+ case GST_CORE_ERROR_SEEK:
+ case GST_CORE_ERROR_NOT_IMPLEMENTED:
+ case GST_CORE_ERROR_FAILED:
+ case GST_CORE_ERROR_TOO_LAZY:
+ case GST_CORE_ERROR_PAD:
+ case GST_CORE_ERROR_THREAD:
+ case GST_CORE_ERROR_EVENT:
+ case GST_CORE_ERROR_CAPS:
+ case GST_CORE_ERROR_TAG:
+ case GST_CORE_ERROR_CLOCK:
+ case GST_CORE_ERROR_DISABLED:
+ default:
+ return MM_ERROR_STREAMRECORDER_GST_CORE;
+ break;
+ }
+}
+
+gint _mmstreamrecorder_gst_handle_library_error(MMHandleType handle, int code, GstMessage *message)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ _mmstreamrec_dbg_log("");
+
+ /* Specific plugin - NONE */
+
+ /* General */
+ switch (code) {
+ case GST_LIBRARY_ERROR_FAILED:
+ case GST_LIBRARY_ERROR_TOO_LAZY:
+ case GST_LIBRARY_ERROR_INIT:
+ case GST_LIBRARY_ERROR_SHUTDOWN:
+ case GST_LIBRARY_ERROR_SETTINGS:
+ case GST_LIBRARY_ERROR_ENCODE:
+ default:
+ _mmstreamrec_dbg_err("Library error(%d)", code);
+ return MM_ERROR_STREAMRECORDER_GST_LIBRARY;
+ }
+}
+
+gint _mmstreamrecorder_gst_handle_resource_error(MMHandleType handle, int code, GstMessage *message)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ GstElement *element = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ _mmstreamrec_dbg_log("");
+
+ /* Specific plugin */
+
+ /* encodebin */
+ element = GST_ELEMENT_CAST(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst);
+ if (GST_ELEMENT_CAST(message->src) == element) {
+ if (code == GST_RESOURCE_ERROR_FAILED) {
+ _mmstreamrec_dbg_err("Encoder [Resource error]");
+ return MM_ERROR_STREAMRECORDER_ENCODER_BUFFER;
+ } else {
+ _mmstreamrec_dbg_err("Encoder [General(%d)]", code);
+ return MM_ERROR_STREAMRECORDER_ENCODER;
+ }
+ }
+
+ /* General */
+ switch (code) {
+ case GST_RESOURCE_ERROR_WRITE:
+ _mmstreamrec_dbg_err("File write error");
+ return MM_ERROR_FILE_WRITE;
+ case GST_RESOURCE_ERROR_NO_SPACE_LEFT:
+ _mmstreamrec_dbg_err("No left space");
+ return MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
+ case GST_RESOURCE_ERROR_OPEN_WRITE:
+ _mmstreamrec_dbg_err("Out of storage");
+ return MM_ERROR_OUT_OF_STORAGE;
+ case GST_RESOURCE_ERROR_SEEK:
+ _mmstreamrec_dbg_err("File read(seek)");
+ return MM_ERROR_FILE_READ;
+ case GST_RESOURCE_ERROR_NOT_FOUND:
+ case GST_RESOURCE_ERROR_FAILED:
+ case GST_RESOURCE_ERROR_TOO_LAZY:
+ case GST_RESOURCE_ERROR_BUSY:
+ case GST_RESOURCE_ERROR_OPEN_READ:
+ case GST_RESOURCE_ERROR_OPEN_READ_WRITE:
+ case GST_RESOURCE_ERROR_CLOSE:
+ case GST_RESOURCE_ERROR_READ:
+ case GST_RESOURCE_ERROR_SYNC:
+ case GST_RESOURCE_ERROR_SETTINGS:
+ default:
+ _mmstreamrec_dbg_err("Resource error(%d)", code);
+ return MM_ERROR_STREAMRECORDER_GST_RESOURCE;
+ }
+}
+
+gint _mmstreamrecorder_gst_handle_stream_error(MMHandleType handle, int code, GstMessage *message)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ GstElement *element = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ _mmstreamrec_dbg_log("");
+
+ /* Specific plugin */
+ /* video encoder */
+ element = GST_ELEMENT_CAST(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst);
+ if (GST_ELEMENT_CAST(message->src) == element) {
+ switch (code) {
+ case GST_STREAM_ERROR_WRONG_TYPE:
+ _mmstreamrec_dbg_err("Video encoder [wrong stream type]");
+ return MM_ERROR_STREAMRECORDER_ENCODER_WRONG_TYPE;
+ case GST_STREAM_ERROR_ENCODE:
+ _mmstreamrec_dbg_err("Video encoder [encode error]");
+ return MM_ERROR_STREAMRECORDER_ENCODER_WORKING;
+ case GST_STREAM_ERROR_FAILED:
+ _mmstreamrec_dbg_err("Video encoder [stream failed]");
+ return MM_ERROR_STREAMRECORDER_ENCODER_WORKING;
+ default:
+ _mmstreamrec_dbg_err("Video encoder [General(%d)]", code);
+ return MM_ERROR_STREAMRECORDER_ENCODER;
+ }
+ }
+
+ /* General plugin */
+ switch (code) {
+ case GST_STREAM_ERROR_FORMAT:
+ _mmstreamrec_dbg_err("General [negotiation error(%d)]", code);
+ return MM_ERROR_STREAMRECORDER_GST_NEGOTIATION;
+ case GST_STREAM_ERROR_FAILED:
+ _mmstreamrec_dbg_err("General [flow error(%d)]", code);
+ return MM_ERROR_STREAMRECORDER_GST_FLOW_ERROR;
+ case GST_STREAM_ERROR_TYPE_NOT_FOUND:
+ case GST_STREAM_ERROR_DECODE:
+ case GST_STREAM_ERROR_CODEC_NOT_FOUND:
+ case GST_STREAM_ERROR_NOT_IMPLEMENTED:
+ case GST_STREAM_ERROR_TOO_LAZY:
+ case GST_STREAM_ERROR_ENCODE:
+ case GST_STREAM_ERROR_DEMUX:
+ case GST_STREAM_ERROR_MUX:
+ case GST_STREAM_ERROR_DECRYPT:
+ case GST_STREAM_ERROR_DECRYPT_NOKEY:
+ case GST_STREAM_ERROR_WRONG_TYPE:
+ default:
+ _mmstreamrec_dbg_err("General [error(%d)]", code);
+ return MM_ERROR_STREAMRECORDER_GST_STREAM;
+ }
+}
+
+gboolean _mmstreamrecorder_handle_gst_warning(MMHandleType handle, GstMessage *message, GError *error)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ gchar *debug = NULL;
+ GError *err = NULL;
+
+ return_val_if_fail(hstreamrecorder, FALSE);
+ return_val_if_fail(error, FALSE);
+
+ _mmstreamrec_dbg_log("");
+
+ gst_message_parse_warning(message, &err, &debug);
+
+ if (error->domain == GST_CORE_ERROR) {
+ _mmstreamrec_dbg_warn("GST warning: GST_CORE domain");
+ } else if (error->domain == GST_LIBRARY_ERROR) {
+ _mmstreamrec_dbg_warn("GST warning: GST_LIBRARY domain");
+ } else if (error->domain == GST_RESOURCE_ERROR) {
+ _mmstreamrec_dbg_warn("GST warning: GST_RESOURCE domain");
+ /* _mmstreamrecorder_gst_handle_resource_warning(handle, message, error); */
+ } else if (error->domain == GST_STREAM_ERROR) {
+ _mmstreamrec_dbg_warn("GST warning: GST_STREAM domain");
+ } else {
+ _mmstreamrec_dbg_warn("This error domain(%d) is not defined.", error->domain);
+ }
+
+ if (err != NULL) {
+ g_error_free(err);
+ err = NULL;
+ }
+ if (debug != NULL) {
+ _mmstreamrec_dbg_err("Debug: %s", debug);
+ g_free(debug);
+ debug = NULL;
+ }
+
+ return TRUE;
+}
+
+gboolean _mmstreamrecorder_pipeline_cb_message(GstBus *bus, GstMessage *message, gpointer data)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(data);
+ /* _MMstreamrecorderMsgItem msg; */
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, FALSE);
+ mmf_return_val_if_fail(message, FALSE);
+ /* _mmstreamrec_dbg_log("message type=(%d)", GST_MESSAGE_TYPE(message)); */
+
+ switch (GST_MESSAGE_TYPE(message)) {
+ case GST_MESSAGE_UNKNOWN:
+ _mmstreamrec_dbg_log("GST_MESSAGE_UNKNOWN");
+ break;
+ case GST_MESSAGE_EOS:
+ {
+ _mmstreamrec_dbg_log("Got EOS from element \"%s\".", GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message))));
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
+ mmf_return_val_if_fail(sc, TRUE);
+
+ /*if (hstreamrecorder->type != MM_STREAMRECORDER_MODE_AUDIO) { */
+ mmf_return_val_if_fail(sc->info_video, TRUE);
+ if (sc->info_video->b_commiting) {
+ _mmstreamrecorder_video_handle_eos((MMHandleType) hstreamrecorder);
+ }
+ /*} else {
+ mmf_return_val_if_fail(sc->info_audio, TRUE);
+ if (sc->info_audio->b_commiting) {
+ _mmstreamrecorder_audio_handle_eos((MMHandleType)hstreamrecorder);
+ }
+ } */
+
+ sc->bget_eos = TRUE;
+
+ break;
+ }
+ case GST_MESSAGE_ERROR:
+ {
+ GError *err;
+ gchar *debug;
+ gst_message_parse_error(message, &err, &debug);
+
+ _mmstreamrec_dbg_err("GSTERR: %s", err->message);
+ _mmstreamrec_dbg_err("Error Debug: %s", debug);
+
+ _mmstreamrecorder_handle_gst_error((MMHandleType) hstreamrecorder, message, err);
+
+ g_error_free(err);
+ g_free(debug);
+ break;
+ }
+ case GST_MESSAGE_WARNING:
+ {
+ GError *err;
+ gchar *debug;
+ gst_message_parse_warning(message, &err, &debug);
+
+ _mmstreamrec_dbg_warn("GSTWARN: %s", err->message);
+
+ _mmstreamrecorder_handle_gst_warning((MMHandleType) hstreamrecorder, message, err);
+
+ g_error_free(err);
+ g_free(debug);
+ break;
+ }
+ case GST_MESSAGE_INFO:
+ _mmstreamrec_dbg_log("GST_MESSAGE_INFO");
+ break;
+ case GST_MESSAGE_TAG:
+ _mmstreamrec_dbg_log("GST_MESSAGE_TAG");
+ break;
+ case GST_MESSAGE_BUFFERING:
+ _mmstreamrec_dbg_log("GST_MESSAGE_BUFFERING");
+ break;
+ case GST_MESSAGE_STATE_CHANGED:
+ {
+ const GValue *vnewstate;
+ GstState newstate;
+ GstElement *pipeline = NULL;
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
+ if ((sc) && (sc->encode_element)) {
+ if (sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst) {
+ pipeline = sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst;
+ if (message->src == (GstObject *) pipeline) {
+ vnewstate = (GValue *) gst_structure_get_value(gst_message_get_structure(message), "new-state");
+ newstate = (GstState) vnewstate->data[0].v_int;
+ _mmstreamrec_dbg_log("GST_MESSAGE_STATE_CHANGED[%s]", gst_element_state_get_name(newstate));
+ }
+ }
+ }
+ break;
+ }
+ case GST_MESSAGE_STATE_DIRTY:
+ _mmstreamrec_dbg_log("GST_MESSAGE_STATE_DIRTY");
+ break;
+ case GST_MESSAGE_STEP_DONE:
+ _mmstreamrec_dbg_log("GST_MESSAGE_STEP_DONE");
+ break;
+ case GST_MESSAGE_CLOCK_PROVIDE:
+ _mmstreamrec_dbg_log("GST_MESSAGE_CLOCK_PROVIDE");
+ break;
+ case GST_MESSAGE_CLOCK_LOST:
+ _mmstreamrec_dbg_log("GST_MESSAGE_CLOCK_LOST");
+ break;
+ case GST_MESSAGE_NEW_CLOCK:
+ {
+ GstClock *l_clock;
+ gst_message_parse_new_clock(message, &l_clock);
+ _mmstreamrec_dbg_log("GST_MESSAGE_NEW_CLOCK : %s", (l_clock ? GST_OBJECT_NAME(l_clock) : "NULL"));
+ break;
+ }
+ case GST_MESSAGE_STRUCTURE_CHANGE:
+ _mmstreamrec_dbg_log("GST_MESSAGE_STRUCTURE_CHANGE");
+ break;
+ case GST_MESSAGE_STREAM_STATUS:
+ _mmstreamrec_dbg_log("GST_MESSAGE_STREAM_STATUS");
+ break;
+ case GST_MESSAGE_APPLICATION:
+ _mmstreamrec_dbg_log("GST_MESSAGE_APPLICATION");
+ break;
+ case GST_MESSAGE_ELEMENT:
+ _mmstreamrec_dbg_log("GST_MESSAGE_ELEMENT");
+ break;
+ case GST_MESSAGE_SEGMENT_START:
+ _mmstreamrec_dbg_log("GST_MESSAGE_SEGMENT_START");
+ break;
+ case GST_MESSAGE_SEGMENT_DONE:
+ _mmstreamrec_dbg_log("GST_MESSAGE_SEGMENT_DONE");
+ break;
+ case GST_MESSAGE_DURATION:
+ _mmstreamrec_dbg_log("GST_MESSAGE_DURATION");
+ break;
+ case GST_MESSAGE_LATENCY:
+ _mmstreamrec_dbg_log("GST_MESSAGE_LATENCY");
+ break;
+ case GST_MESSAGE_ASYNC_START:
+ _mmstreamrec_dbg_log("GST_MESSAGE_ASYNC_START");
+ break;
+ case GST_MESSAGE_ASYNC_DONE:
+ _mmstreamrec_dbg_log("GST_MESSAGE_ASYNC_DONE");
+ break;
+ case GST_MESSAGE_ANY:
+ _mmstreamrec_dbg_log("GST_MESSAGE_ANY");
+ break;
+ default:
+ _mmstreamrec_dbg_log("not handled message type=(%d)", GST_MESSAGE_TYPE(message));
+ break;
+ }
+
+ return TRUE;
+}
+
+/**
+ * This function is record video data probing function.
+ * If this function is linked with certain pad by gst_pad_add_buffer_probe(),
+ * this function will be called when data stream pass through the pad.
+ *
+ * @param[in] pad probing pad which calls this function.
+ * @param[in] buffer buffer which contains stream data.
+ * @param[in] u_data user data.
+ * @return This function returns true on success, or false value with error
+ * @remarks
+ * @see
+ */
+GstPadProbeReturn __mmstreamrecorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
+{
+ GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
+ switch (GST_EVENT_TYPE(event)) {
+ case GST_EVENT_UNKNOWN:
+ /* upstream events */
+ case GST_EVENT_QOS:
+ case GST_EVENT_SEEK:
+ case GST_EVENT_NAVIGATION:
+ case GST_EVENT_LATENCY:
+ /* downstream serialized events */
+ case GST_EVENT_SEGMENT:
+ case GST_EVENT_TAG:
+ case GST_EVENT_BUFFERSIZE:
+ _mmstreamrec_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
+ break;
+ case GST_EVENT_EOS:
+ _mmstreamrec_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
+ break;
+ /* bidirectional events */
+ case GST_EVENT_FLUSH_START:
+ case GST_EVENT_FLUSH_STOP:
+ _mmstreamrec_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
+ break;
+ default:
+ _mmstreamrec_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event));
+ break;
+ }
+
+ return GST_PAD_PROBE_OK;
+}
+
+GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
+ GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
+ GstMapInfo mapinfo = GST_MAP_INFO_INIT;
+ guint64 buffer_size = 0;
+
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderAudioInfo *audioinfo = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
+ mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
+
+ mmf_return_val_if_fail(sc && sc->info_audio, GST_PAD_PROBE_OK);
+ memset(&mapinfo, 0x0, sizeof(GstMapInfo));
+
+ audioinfo = sc->info_audio;
+
+ gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
+ buffer_size = mapinfo.size;
+ gst_buffer_unmap(buffer, &mapinfo);
+
+ /*_mmstreamrec_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
+
+ if (audioinfo->audio_frame_count == 0) {
+ audioinfo->filesize += buffer_size;
+ audioinfo->audio_frame_count++;
+ return GST_PAD_PROBE_OK;
+ }
+
+ if (sc->ferror_send || sc->isMaxsizePausing) {
+ _mmstreamrec_dbg_warn("Recording is paused, drop frames");
+ return GST_PAD_PROBE_DROP;
+ }
+
+ audioinfo->filesize += buffer_size;
+ audioinfo->audio_frame_count++;
+
+ return GST_PAD_PROBE_OK;
+}
+
+GstPadProbeReturn __mmstreamrecorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
+{
+ static int count = 0;
+ gint ret = 0;
+ guint vq_size = 0;
+ guint aq_size = 0;
+ guint64 free_space = 0;
+ guint64 buffer_size = 0;
+ guint64 trailer_size = 0;
+ guint64 queued_buffer = 0;
+ char *filename = NULL;
+ GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
+ GstMapInfo mapinfo = GST_MAP_INFO_INIT;
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
+ _MMStreamRecorderMsgItem msg;
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderVideoInfo *videoinfo = NULL;
+ _MMStreamRecorderFileInfo *finfo = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
+ mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
+ mmf_return_val_if_fail(sc && sc->info_video && sc->info_file, TRUE);
+ memset(&mapinfo, 0x0, sizeof(GstMapInfo));
+
+ videoinfo = sc->info_video;
+ finfo = sc->info_file;
+
+ /*_mmstreamrec_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/
+ if (sc->ferror_send) {
+ _mmstreamrec_dbg_warn("file write error, drop frames");
+ return GST_PAD_PROBE_DROP;
+ }
+ gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
+ buffer_size = mapinfo.size;
+ gst_buffer_unmap(buffer, &mapinfo);
+
+ videoinfo->video_frame_count++;
+ if (videoinfo->video_frame_count <= (guint64) _MMSTREAMRECORDER_MINIMUM_FRAME) {
+ /* _mmstreamrec_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ", info->video_frame_count); */
+ videoinfo->filesize += buffer_size;
+ return GST_PAD_PROBE_OK;
+ }
+
+ /* get trailer size */
+ if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4) {
+ MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
+ } else {
+ trailer_size = 0;
+ }
+
+ /* to minimizing free space check overhead */
+ count = count % _MMSTREAMRECORDER_FREE_SPACE_CHECK_INTERVAL;
+ if (count++ == 0) {
+ filename = finfo->filename;
+ ret = _mmstreamrecorder_get_freespace(filename, &free_space);
+
+ /*_mmstreamrec_dbg_log("check free space for recording");*/
+
+ switch (ret) {
+ case -2: /* file not exist */
+ case -1: /* failed to get free space */
+ _mmstreamrec_dbg_err("Error occured. [%d]", ret);
+ if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
+ sc->ferror_send = TRUE;
+ msg.id = MM_MESSAGE_STREAMRECORDER_ERROR;
+ if (ret == -2) {
+ msg.param.code = MM_ERROR_FILE_NOT_FOUND;
+ } else {
+ msg.param.code = MM_ERROR_FILE_READ;
+ }
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+ } else {
+ sc->ferror_count++;
+ }
+
+ return GST_PAD_PROBE_DROP; /* skip this buffer */
+ break;
+ default: /* succeeded to get free space */
+ /* check free space for recording */
+ /* get queued buffer size */
+ if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst) {
+ MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size);
+ }
+ if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst) {
+ MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size);
+ }
+
+ queued_buffer = aq_size + vq_size;
+
+ /* check free space */
+ if (free_space < (_MMSTREAMRECORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) {
+ _mmstreamrec_dbg_warn("No more space for recording!!! Recording is paused.");
+ _mmstreamrec_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", free_space, trailer_size, buffer_size, queued_buffer);
+
+ if (!sc->isMaxsizePausing) {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
+ sc->isMaxsizePausing = TRUE;
+
+ msg.id = MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+ }
+
+ return GST_PAD_PROBE_DROP;
+ }
+ break;
+ }
+ }
+
+ videoinfo->filesize += (guint64) buffer_size;
+
+ /*
+ _mmstreamrec_dbg_log("filesize %lld Byte, ", info->filesize);
+ */
+
+ return GST_PAD_PROBE_OK;
+}
+
+GstPadProbeReturn __mmstreamrecorder_video_dataprobe_audio_disable(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
+{
+ guint64 trailer_size = 0;
+ guint64 rec_pipe_time = 0;
+ unsigned int remained_time = 0;
+
+ GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
+ GstClockTime b_time;
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
+ _MMStreamRecorderMsgItem msg;
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderVideoInfo *videoinfo = NULL;
+ _MMStreamRecorderFileInfo *finfo = NULL;
+
+ mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
+ mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(u_data);
+ mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
+ mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
+ mmf_return_val_if_fail(sc->info_file, GST_PAD_PROBE_OK);
+
+ videoinfo = sc->info_video;
+ finfo = sc->info_file;
+
+ b_time = GST_BUFFER_TIMESTAMP(buffer);
+
+ rec_pipe_time = GST_TIME_AS_MSECONDS(b_time);
+
+ if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4) {
+ MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
+ } else {
+ trailer_size = 0;
+ }
+
+ /* check max time */
+ if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
+ _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, videoinfo->max_time);
+
+ if (!sc->isMaxtimePausing) {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
+
+ sc->isMaxtimePausing = TRUE;
+
+ msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
+ msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
+ msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
+ msg.param.recording_status.remained_time = 0;
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+
+ msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+ }
+
+ return GST_PAD_PROBE_DROP;
+ }
+
+ if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time))
+ remained_time = videoinfo->max_time - rec_pipe_time;
+
+ msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
+ msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
+ msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
+ msg.param.recording_status.remained_time = remained_time;
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+
+ /*
+ _mmstreamrec_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]",
+ GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
+ */
+
+ return GST_PAD_PROBE_OK;
+}
+
+GstPadProbeReturn __mmstreamrecorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
+{
+ _MMStreamRecorderMsgItem msg;
+ guint64 trailer_size = 0;
+ guint64 rec_pipe_time = 0;
+ _MMStreamRecorderSubContext *sc = NULL;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
+ _MMStreamRecorderVideoInfo *videoinfo = NULL;
+ _MMStreamRecorderFileInfo *finfo = NULL;
+ unsigned int remained_time = 0;
+ GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
+
+ mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
+ mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_OK);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(u_data);
+
+ mmf_return_val_if_fail(sc, GST_PAD_PROBE_OK);
+ mmf_return_val_if_fail(sc->info_video, GST_PAD_PROBE_OK);
+ mmf_return_val_if_fail(sc->info_file, GST_PAD_PROBE_OK);
+
+ videoinfo = sc->info_video;
+ finfo = sc->info_file;
+
+ if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
+ _mmstreamrec_dbg_err("Buffer timestamp is invalid, check it");
+ return GST_PAD_PROBE_OK;
+ }
+
+ rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
+
+ if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4) {
+ MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
+ } else {
+ trailer_size = 0;
+ }
+
+ if (videoinfo->max_time > 0 && videoinfo->max_time < (remained_time + rec_pipe_time))
+ remained_time = videoinfo->max_time - rec_pipe_time;
+
+ if (videoinfo->max_time > 0 && rec_pipe_time > videoinfo->max_time) {
+ _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, videoinfo->max_time);
+
+ if (!sc->isMaxtimePausing) {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
+
+ sc->isMaxtimePausing = TRUE;
+
+ msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
+ msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
+ msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
+ msg.param.recording_status.remained_time = 0;
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+
+ msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+ }
+
+ return GST_PAD_PROBE_DROP;
+ }
+
+ msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
+ msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
+ msg.param.recording_status.filesize = (unsigned long long)((videoinfo->filesize + trailer_size) >> 10);
+ msg.param.recording_status.remained_time = remained_time;
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+
+ /*
+ _mmstreamrec_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]",
+ GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize);
+ */
+
+ return GST_PAD_PROBE_OK;
+}
+
+void __mmstreamrecorder_audiorec_pad_added_cb(GstElement *element, GstPad *pad, MMHandleType handle)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ _mmstreamrec_dbg_log("ENTER(%s)", GST_PAD_NAME(pad));
+ /* FIXME : the name of audio sink pad of wavparse, oggmux doesn't have 'audio'. How could I handle the name? */
+ if ((strstr(GST_PAD_NAME(pad), "audio")) || (strstr(GST_PAD_NAME(pad), "sink"))) {
+ MMSTREAMRECORDER_ADD_BUFFER_PROBE(pad, _MMSTREAMRECORDER_HANDLER_AUDIOREC, __mmstreamrecorder_audio_dataprobe_record, hstreamrecorder);
+ } else {
+ _mmstreamrec_dbg_warn("Unknow pad is added, check it : [%s]", GST_PAD_NAME(pad));
+ }
+
+ return;
+}
+
+GstPadProbeReturn __mmstreamrecorder_audio_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
+{
+ static int count = 0;
+ guint64 rec_pipe_time = 0;
+ guint64 free_space = 0;
+ guint64 buffer_size = 0;
+ guint64 trailer_size = 0;
+ char *filename = NULL;
+ unsigned long long remained_time = 0;
+ GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
+
+ _MMStreamRecorderSubContext *sc = NULL;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(u_data);
+ _MMStreamRecorderAudioInfo *audioinfo = NULL;
+ _MMStreamRecorderFileInfo *finfo = NULL;
+ _MMStreamRecorderMsgItem msg;
+
+ mmf_return_val_if_fail(hstreamrecorder, GST_PAD_PROBE_DROP);
+ mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(hstreamrecorder);
+ mmf_return_val_if_fail(sc && sc->info_audio && sc->info_file, FALSE);
+ audioinfo = sc->info_audio;
+ finfo = sc->info_file;
+
+ if (sc->isMaxtimePausing || sc->isMaxsizePausing) {
+ _mmstreamrec_dbg_warn("isMaxtimePausing[%d],isMaxsizePausing[%d]", sc->isMaxtimePausing, sc->isMaxsizePausing);
+ return GST_PAD_PROBE_DROP;
+ }
+
+ buffer_size = gst_buffer_get_size(buffer);
+
+ if (audioinfo->filesize == 0) {
+ if (finfo->fileformat == MM_FILE_FORMAT_WAV) {
+ audioinfo->filesize += 44; /* wave header size */
+ } else if (finfo->fileformat == MM_FILE_FORMAT_AMR) {
+ audioinfo->filesize += 6; /* amr header size */
+ }
+
+ audioinfo->filesize += buffer_size;
+ return GST_PAD_PROBE_OK;
+ }
+
+ if (sc->ferror_send) {
+ _mmstreamrec_dbg_warn("file write error, drop frames");
+ return GST_PAD_PROBE_DROP;
+ }
+
+ /* get trailer size */
+ if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4 || finfo->fileformat == MM_FILE_FORMAT_AAC) {
+ MMSTREAMRECORDER_G_OBJECT_GET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size);
+ /*_mmstreamrec_dbg_log("trailer_size %d", trailer_size);*/
+ } else {
+ trailer_size = 0; /* no trailer */
+ }
+
+ filename = finfo->filename;
+
+ /* to minimizing free space check overhead */
+ count = count % _MMSTREAMRECORDER_AUDIO_FREE_SPACE_CHECK_INTERVAL;
+ if (count++ == 0) {
+ gint free_space_ret = _mmstreamrecorder_get_freespace(filename, &free_space);
+
+ /*_mmstreamrec_dbg_log("check free space for recording");*/
+
+ switch (free_space_ret) {
+ case -2: /* file not exist */
+ case -1: /* failed to get free space */
+ _mmstreamrec_dbg_err("Error occured. [%d]", free_space_ret);
+ if (sc->ferror_count == 2 && sc->ferror_send == FALSE) {
+ sc->ferror_send = TRUE;
+ msg.id = MM_MESSAGE_STREAMRECORDER_ERROR;
+ if (free_space_ret == -2) {
+ msg.param.code = MM_ERROR_FILE_NOT_FOUND;
+ } else {
+ msg.param.code = MM_ERROR_FILE_READ;
+ }
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+ } else {
+ sc->ferror_count++;
+ }
+
+ return GST_PAD_PROBE_DROP; /* skip this buffer */
+
+ default: /* succeeded to get free space */
+ /* check free space for recording */
+ if (free_space < (guint64) (_MMSTREAMRECORDER_AUDIO_MINIMUM_SPACE + buffer_size + trailer_size)) {
+ _mmstreamrec_dbg_warn("No more space for recording!!!");
+ _mmstreamrec_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], file size : [%" G_GUINT64_FORMAT "]", free_space, audioinfo->filesize);
+
+ if (audioinfo->bMuxing) {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
+ } else {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
+ }
+
+ sc->isMaxsizePausing = TRUE;
+ msg.id = MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+
+ return FALSE; /* skip this buffer */
+ }
+ break;
+ }
+ }
+
+ if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_PTS(buffer))) {
+ _mmstreamrec_dbg_err("Buffer timestamp is invalid, check it");
+ return GST_PAD_PROBE_DROP;
+ }
+
+ rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer));
+
+ if (audioinfo->max_time > 0 && audioinfo->max_time < (remained_time + rec_pipe_time))
+ remained_time = audioinfo->max_time - rec_pipe_time;
+
+ /*_mmstreamrec_dbg_log("remained time : %u", remained_time);*/
+
+ /* check recording time limit and send recording status message */
+ if (audioinfo->max_time > 0 && rec_pipe_time > audioinfo->max_time) {
+ _mmstreamrec_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", rec_pipe_time, audioinfo->max_time);
+
+ if (audioinfo->bMuxing) {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
+ } else {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE);
+ }
+
+ sc->isMaxtimePausing = TRUE;
+ msg.id = MM_MESSAGE_STREAMRECORDER_TIME_LIMIT;
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+
+ /* skip this buffer */
+ return GST_PAD_PROBE_DROP;
+ }
+
+ /* send message for recording time and recorded file size */
+ if (audioinfo->b_commiting == FALSE) {
+ audioinfo->filesize += buffer_size;
+
+ msg.id = MM_MESSAGE_STREAMRECORDER_RECORDING_STATUS;
+ msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time;
+ msg.param.recording_status.filesize = (unsigned long long)((audioinfo->filesize + trailer_size) >> 10);
+ msg.param.recording_status.remained_time = remained_time;
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+
+ return GST_PAD_PROBE_OK;
+ } else {
+ /* skip this buffer if commit process has been started */
+ return GST_PAD_PROBE_DROP;
+ }
+}
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 <glib.h>
+#include <glib/gstdio.h>
+#include <stdlib.h>
+#include <iniparser.h>
+#include <mm_debug.h>
+#include <mm_error.h>
+#include "mm_streamrecorder_ini.h"
+
+static gboolean loaded = FALSE;
+
+/* global variables here */
+#ifdef MM_STREAMRECORDER_DEFAULT_INI
+static gboolean __generate_default_ini(void);
+#endif
+static void __get_element_list(mm_streamrecorder_ini_t* ini, gchar* str, int keyword_type);
+
+static void __mm_streamrecorder_ini_check_status(void);
+
+/* macro */
+#define MM_STREAMRECORDER_INI_GET_STRING(x_dict, x_item, x_ini, x_default) \
+do { \
+ gchar *str = NULL; \
+ gint length = 0; \
+ str = iniparser_getstring(x_dict, x_ini, x_default); \
+ if (str) { \
+ length = strlen(str); \
+ if ((length > 1) && (length < STREAMRECORDER_INI_MAX_STRLEN)) \
+ strncpy(x_item, str, length+1); \
+ else \
+ strncpy(x_item, x_default, STREAMRECORDER_INI_MAX_STRLEN-1); \
+ } else { \
+ strncpy(x_item, x_default, STREAMRECORDER_INI_MAX_STRLEN-1); \
+ } \
+} while (0)
+
+/* x_ini is the list of value to be set at x_list[index] */
+#define MMSTREAMRECORDER_INI_GET_INT_FROM_LIST(x_dict, x_list, x_list_max, x_ini, x_default) \
+do { \
+ int index = 0; \
+ int value = 0; \
+ const char *delimiters = " ,"; \
+ char *usr_ptr = NULL; \
+ char *token = NULL; \
+ gchar temp_arr[STREAMRECORDER_INI_MAX_STRLEN] = {0}; \
+ MM_STREAMRECORDER_INI_GET_STRING(x_dict, temp_arr, x_ini, x_default); \
+ token = strtok_r(temp_arr, delimiters, &usr_ptr); \
+ while (token) { \
+ if (index > x_list_max -1) { \
+ debug_error("%d is not valid index\n", index); \
+ break; \
+ } else { \
+ value = atoi(token); \
+ x_list[index] = value; \
+ index++; \
+ } \
+ token = strtok_r(NULL, delimiters, &usr_ptr); \
+ } \
+} while (0)
+
+
+#ifdef MM_STREAMRECORDER_DEFAULT_INI
+static
+gboolean __generate_default_ini(void)
+{
+ FILE *fp = NULL;
+ const gchar *default_ini = MM_STREAMRECORDER_DEFAULT_INI;
+
+ /* create new file */
+ fp = fopen(MM_STREAMRECORDER_INI_DEFAULT_PATH, "wt");
+
+ if (!fp)
+ return FALSE;
+
+ /* writing default ini file */
+ if (strlen(default_ini) != fwrite(default_ini, 1, strlen(default_ini), fp)) {
+ fclose(fp);
+ return FALSE;
+ }
+
+ fclose(fp);
+ return TRUE;
+}
+#endif
+
+int _mm_streamrecorder_ini_load(mm_streamrecorder_ini_t *ini)
+{
+ dictionary *dict = NULL;
+
+ debug_fenter();
+
+ __mm_streamrecorder_ini_check_status();
+
+ /* first, try to load existing ini file */
+ dict = iniparser_load(MM_STREAMRECORDER_INI_DEFAULT_PATH);
+
+ /* if no file exists. create one with set of default values */
+ if (!dict) {
+ _mmstreamrec_dbg_err("No ini file found. \n");
+ return MM_ERROR_FILE_NOT_FOUND;
+ }
+
+ /* get ini values */
+ memset(ini, 0, sizeof(mm_streamrecorder_ini_t));
+
+ if (dict) { /* if dict is available */
+ /* general */
+ ini->encsink_src_islive = iniparser_getboolean(dict, "general:encscink source is live", DEFAULT_ENCSINK_SRC_IS_LIVE);
+ ini->retrial_count = iniparser_getint(dict, "general:retrialcount", DEFAULT_RETRIAL_COUNT);
+ ini->minimum_frame = iniparser_getint(dict, "general:minimum frame", DEFAULT_MINIMUM_FRAME);
+ ini->convert_output_buffer_num = iniparser_getint(dict, "general:convert output buffer num", DEFAULT_CONVERT_OUTPUT_BUFFER_NUM);
+ ini->reset_pause_time = iniparser_getint(dict, "general:reset pause time", DEFAULT_RESET_PAUSE_TIME);
+ ini->screen_record = iniparser_getint(dict, "general:screen record", DEFAULT_SCREEN_RECORD);
+
+ /*encodebin */
+ ini->encsink_bin_profile = iniparser_getint(dict, "encodebin:encsink bin profile", DEFAULT_ENCSINK_BIN_PROFILE);
+ ini->encsink_bin_auto_audio_resample = iniparser_getboolean(dict, "encodebin:encsink bin auto audio resample", DEFAULT_ENCSINK_BIN_AUTO_AUDIO_RESAMPLE);
+ ini->encsink_bin_auto_colorspace = iniparser_getboolean(dict, "encodebin: encsink bin auto colorspace", DEFAULT_ENCSINK_BIN_AUTO_COLORSPACE);
+ ini->encsink_bin_use_video_toggle = iniparser_getboolean(dict, "encodebin:encsink bin use video toggle", DEFAULT_ENCSINK_BIN_USE_VIDEO_TOGGLE);
+ ini->encsink_bin_auto_audio_convert = iniparser_getboolean(dict, "encodebin:encsink bin auto audio convert", DEFAULT_ENCSINK_BIN_AUTO_CONVERT);
+
+ /* pipeline */
+ MM_STREAMRECORDER_INI_GET_STRING(dict, ini->name_of_encsink_src, (const char *)"pipeline:encsink bin source", (char *)DEFAULT_VIDEO_SOURCE);
+ MM_STREAMRECORDER_INI_GET_STRING(dict, ini->name_of_audio_src, (const char *)"pipeline:name of audio src", (char *)DEFAULT_AUDIO_SRC);
+ MM_STREAMRECORDER_INI_GET_STRING(dict, ini->h264_video_encoder, (const char *)"pipeline:h264 encoder", (char *)DEFAULT_NAME_OF_H264_VIDEO_ENCODER);
+ MM_STREAMRECORDER_INI_GET_STRING(dict, ini->h263_video_encoder, (const char *)"pipeline:h263 encoder", (char *)DEFAULT_NAME_OF_H263_VIDEO_ENCODER);
+ MM_STREAMRECORDER_INI_GET_STRING(dict, ini->mpeg4_video_encoder, (const char *)"pipeline:mpeg4 encoder", (char *)DEFAULT_NAME_OF_MPEG4_VIDEO_ENCODER);
+ MM_STREAMRECORDER_INI_GET_STRING(dict, ini->name_of_encsink_bin_audio_encoder, (const char *)"pipeline:name of audio encoder", (char *)DEFAULT_NAME_OF_AUDIO_ENCODER);
+ MM_STREAMRECORDER_INI_GET_STRING(dict, ini->encsink_bin_use_parser, (const char *)"pipeline:use parser", (char *)DEFAULT_USE_PARSER);
+ MM_STREAMRECORDER_INI_GET_STRING(dict, ini->name_of_encsink_bin_video_converter, (const char *)"pipeline:name of video converter", (char *)DEFAULT_NAME_OF_VIDEO_CONVERTER);
+ MM_STREAMRECORDER_INI_GET_STRING(dict, ini->name_of_encsink_bin_3GPMUXER, (const char *)"pipeline:name of 3GP muxer", (char *)DEFAULT_NAME_OF_3GP_MUXER);
+ MM_STREAMRECORDER_INI_GET_STRING(dict, ini->name_of_encsink_bin_MP4MUXER, (const char *)"pipeline:name of MP4 muxer", (char *)DEFAULT_NAME_OF_MP4_MUXER);
+ MM_STREAMRECORDER_INI_GET_STRING(dict, ini->name_of_encsink_sink, (const char *)"pipeline:name of sink", (char *)DEFAULT_NAME_OF_BIN_SINK);
+
+ /* audio parameter */
+ ini->audio_frame_minimum_space = iniparser_getint(dict, "audio param:audio frame minimum space", DEFAULT_AUDIO_FRAME_MINIMUM_SPACE);
+ ini->audio_frame_wait_time = iniparser_getint(dict, "audio param:audio frame wait time", DEFAULT_AUDIO_FRAME_WAIT_TIME);
+
+ /* video parameter */
+ ini->video_frame_wait_time = iniparser_getint(dict, "video param:video frame wait time", DEFAULT_VIDEO_FRAME_WAIT_TIME);
+
+ /*supported attribute*/
+ MMSTREAMRECORDER_INI_GET_INT_FROM_LIST(dict, ini->supported_video_width, STREAMRECORDER_ATTRIBUTE_NUM_MAX, "attribute:supported width", DEFAULT_SUPPORTED_WIDTH);
+ MMSTREAMRECORDER_INI_GET_INT_FROM_LIST(dict, ini->supported_video_height, STREAMRECORDER_ATTRIBUTE_NUM_MAX, "attribute:supported height", DEFAULT_SUPPORTED_HEIGHT);
+ __get_element_list(ini, iniparser_getstring(dict, "attribute:supported audio encoders", DEFAULT_SUPPORTED_AUDIO_ENCODERS), KEYWORD_AUDIO_ENCODERS);
+ __get_element_list(ini, iniparser_getstring(dict, "attribute:supported video encoders", DEFAULT_SUPPORTED_VIDEO_ENCODERS), KEYWORD_VIDEO_ENCODERS);
+ __get_element_list(ini, iniparser_getstring(dict, "attribute:supported file formats", DEFAULT_SUPPORTED_FILE_FORMATS), KEYWORD_FILE_FORMATS);
+
+ } else { /* if dict is not available just fill the structure with default value */
+ _mmstreamrec_dbg_err("failed to load ini. using hardcoded default\n");
+ /* general */
+ ini->encsink_src_islive = DEFAULT_ENCSINK_SRC_IS_LIVE;
+ ini->retrial_count = DEFAULT_RETRIAL_COUNT;
+ ini->minimum_frame = DEFAULT_MINIMUM_FRAME;
+ ini->convert_output_buffer_num = DEFAULT_CONVERT_OUTPUT_BUFFER_NUM;
+ ini->reset_pause_time = DEFAULT_RESET_PAUSE_TIME;
+ ini->screen_record = DEFAULT_SCREEN_RECORD;
+
+ /*encodebin */
+ ini->encsink_bin_profile = DEFAULT_ENCSINK_BIN_PROFILE;
+ ini->encsink_bin_auto_audio_resample = DEFAULT_ENCSINK_BIN_AUTO_AUDIO_RESAMPLE;
+ ini->encsink_bin_auto_colorspace = DEFAULT_ENCSINK_BIN_AUTO_COLORSPACE;
+ ini->encsink_bin_use_video_toggle = DEFAULT_ENCSINK_BIN_USE_VIDEO_TOGGLE;
+ ini->encsink_bin_auto_audio_convert = DEFAULT_ENCSINK_BIN_AUTO_CONVERT;
+
+ /* pipeline */
+ strncpy(ini->name_of_encsink_src, DEFAULT_VIDEO_SOURCE, STREAMRECORDER_INI_MAX_STRLEN - 1);
+ strncpy(ini->name_of_audio_src, DEFAULT_AUDIO_SRC, STREAMRECORDER_INI_MAX_STRLEN - 1);
+ strncpy(ini->h264_video_encoder, DEFAULT_NAME_OF_H264_VIDEO_ENCODER, STREAMRECORDER_INI_MAX_STRLEN - 1);
+ strncpy(ini->h263_video_encoder, DEFAULT_NAME_OF_H263_VIDEO_ENCODER, STREAMRECORDER_INI_MAX_STRLEN - 1);
+ strncpy(ini->mpeg4_video_encoder, DEFAULT_NAME_OF_MPEG4_VIDEO_ENCODER, STREAMRECORDER_INI_MAX_STRLEN - 1);
+ strncpy(ini->name_of_encsink_bin_audio_encoder, DEFAULT_NAME_OF_AUDIO_ENCODER, STREAMRECORDER_INI_MAX_STRLEN - 1);
+ strncpy(ini->encsink_bin_use_parser, DEFAULT_USE_PARSER, STREAMRECORDER_INI_MAX_STRLEN - 1);
+ strncpy(ini->name_of_encsink_bin_video_converter, DEFAULT_NAME_OF_VIDEO_CONVERTER, STREAMRECORDER_INI_MAX_STRLEN - 1);
+ strncpy(ini->name_of_encsink_bin_3GPMUXER, DEFAULT_NAME_OF_3GP_MUXER, STREAMRECORDER_INI_MAX_STRLEN - 1);
+ strncpy(ini->name_of_encsink_bin_MP4MUXER, DEFAULT_NAME_OF_MP4_MUXER, STREAMRECORDER_INI_MAX_STRLEN - 1);
+ strncpy(ini->name_of_encsink_sink, DEFAULT_NAME_OF_BIN_SINK, STREAMRECORDER_INI_MAX_STRLEN - 1);
+
+ /* audio parameter */
+ ini->audio_frame_minimum_space = DEFAULT_AUDIO_FRAME_MINIMUM_SPACE;
+ ini->audio_frame_wait_time = DEFAULT_AUDIO_FRAME_WAIT_TIME;
+
+ /* video parameter */
+ ini->video_frame_wait_time = DEFAULT_VIDEO_FRAME_WAIT_TIME;
+
+ /*supported attributes*/
+ __get_element_list(ini, DEFAULT_SUPPORTED_AUDIO_ENCODERS, KEYWORD_AUDIO_ENCODERS);
+ __get_element_list(ini, DEFAULT_SUPPORTED_VIDEO_ENCODERS, KEYWORD_VIDEO_ENCODERS);
+ __get_element_list(ini, DEFAULT_SUPPORTED_FILE_FORMATS, KEYWORD_FILE_FORMATS);
+ }
+
+ /* free dict as we got our own structure */
+ iniparser_freedict(dict);
+
+ /* dump structure */
+ _mmstreamrec_dbg_log("Stream Recorder initial settings.......................................\n");
+
+ /* general */
+ _mmstreamrec_dbg_log("encsink_src_islive : %d\n", ini->encsink_src_islive);
+ _mmstreamrec_dbg_log("retrial_count : %d\n", ini->retrial_count);
+ _mmstreamrec_dbg_log("minimum_frame : %d\n", ini->minimum_frame);
+ _mmstreamrec_dbg_log("convert_output_buffer_num : %d\n", ini->convert_output_buffer_num);
+ _mmstreamrec_dbg_log("reset_pause_time : %d\n", ini->reset_pause_time);
+ _mmstreamrec_dbg_log("screen_record : %d\n", ini->screen_record);
+
+ /*encodebin */
+ _mmstreamrec_dbg_log("encode bin profile : %d\n", ini->encsink_bin_profile);
+ _mmstreamrec_dbg_log("encode bin auto audio resample property : %d\n", ini->encsink_bin_auto_audio_resample);
+ _mmstreamrec_dbg_log("encode bin auto colorspace property : %d\n", ini->encsink_bin_auto_colorspace);
+ _mmstreamrec_dbg_log("encode bin use video toggle property : %d\n", ini->encsink_bin_use_video_toggle);
+ _mmstreamrec_dbg_log("encode bin auto audio convert property : %d\n", ini->encsink_bin_auto_audio_convert);
+
+ /* pipeline */
+ _mmstreamrec_dbg_log("name_of_encodebin_source : %s\n", ini->name_of_encsink_src);
+ _mmstreamrec_dbg_log("name_of_audio_source : %s\n", ini->name_of_audio_src);
+ _mmstreamrec_dbg_log("name_of_h264_video_encoder : %s\n", ini->h264_video_encoder);
+ _mmstreamrec_dbg_log("name_of_h263_video_encoder : %s\n", ini->h263_video_encoder);
+ _mmstreamrec_dbg_log("name_of_mpeg4_video_encoder : %s\n", ini->mpeg4_video_encoder);
+ _mmstreamrec_dbg_log("name_of_audio_encoder : %s\n", ini->name_of_encsink_bin_audio_encoder);
+ _mmstreamrec_dbg_log("name_of_video_converter : %s\n", ini->name_of_encsink_bin_video_converter);
+ _mmstreamrec_dbg_log("name_of_3GP_muxer : %s\n", ini->name_of_encsink_bin_3GPMUXER);
+ _mmstreamrec_dbg_log("name_of_MP4_muxer : %s\n", ini->name_of_encsink_bin_MP4MUXER);
+ _mmstreamrec_dbg_log("name_of_sink : %s\n", ini->name_of_encsink_sink);
+
+ /* audio parameter */
+ _mmstreamrec_dbg_log("audio_frame_minimum_space : %d\n", ini->audio_frame_minimum_space);
+ _mmstreamrec_dbg_log("audio_frame_wait_time : %d\n", ini->audio_frame_wait_time);
+
+ /* video parameter */
+ _mmstreamrec_dbg_log("video_frame_wait_time : %d\n", ini->video_frame_wait_time);
+
+ _mmstreamrec_dbg_log("---------------------------------------------------\n");
+
+ loaded = TRUE;
+
+ debug_fleave();
+
+ return MM_ERROR_NONE;
+}
+
+static
+void __get_element_list(mm_streamrecorder_ini_t* ini, gchar* str, int keyword_type)
+{
+ gchar** list = NULL;
+ gchar** walk = NULL;
+ int i = 0;
+ gchar* strtmp = NULL;
+
+ if (!str)
+ return;
+
+ if (strlen(str) < 1)
+ return;
+
+ strtmp = g_strdup(str);
+
+ /* trimming. it works inplace */
+ g_strstrip(strtmp);
+
+
+ /* split */
+ list = g_strsplit(strtmp, ",", 10);
+
+ if (!list) {
+ if (strtmp)
+ g_free(strtmp);
+
+ return;
+ }
+
+ /* copy list */
+ switch (keyword_type) {
+ case KEYWORD_AUDIO_ENCODERS:
+ {
+ for (walk = list; *walk; walk++) {
+ strncpy(ini->supported_audio_encoders[i], *walk, (STREAMRECORDER_INI_MAX_STRLEN - 1));
+ g_strstrip(ini->supported_audio_encoders[i]);
+ ini->supported_audio_encoders[i][STREAMRECORDER_INI_MAX_STRLEN -1] = '\0';
+ i++;
+ }
+ /* mark last item to NULL*/
+ ini->supported_audio_encoders[i][0] = '\0';
+ break;
+ }
+ case KEYWORD_VIDEO_ENCODERS:
+ {
+ for (walk = list; *walk; walk++) {
+ strncpy(ini->supported_video_encoders[i], *walk, (STREAMRECORDER_INI_MAX_STRLEN - 1));
+ g_strstrip(ini->supported_video_encoders[i]);
+ ini->supported_video_encoders[i][STREAMRECORDER_INI_MAX_STRLEN -1] = '\0';
+ i++;
+ }
+ /* mark last item to NULL */
+ ini->supported_video_encoders[i][0] = '\0';
+ break;
+ }
+ case KEYWORD_FILE_FORMATS:
+ {
+ for (walk = list; *walk; walk++) {
+ strncpy(ini->supported_file_formats[i], *walk, (STREAMRECORDER_INI_MAX_STRLEN - 1));
+ g_strstrip(ini->supported_file_formats[i]);
+ ini->supported_file_formats[i][STREAMRECORDER_INI_MAX_STRLEN -1] = '\0';
+ i++;
+ }
+ /* mark last item to NULL*/
+ ini->supported_file_formats[i][0] = '\0';
+ break;
+ }
+ default:
+ break;
+ }
+
+ g_strfreev(list);
+ if (strtmp)
+ g_free(strtmp);
+}
+
+
+static
+void __mm_streamrecorder_ini_check_status(void)
+{
+ struct stat ini_buff;
+
+ debug_fenter();
+
+ if (g_stat(MM_STREAMRECORDER_INI_DEFAULT_PATH, &ini_buff) < 0) {
+ _mmstreamrec_dbg_err("failed to get mmfw_wfd_sink ini status\n");
+ } else {
+ if (ini_buff.st_size < 5) {
+ _mmstreamrec_dbg_err("mmfw_wfd_sink.ini file size=%d, Corrupted! So, Removed\n", (int)ini_buff.st_size);
+ g_remove(MM_STREAMRECORDER_INI_DEFAULT_PATH);
+ }
+ }
+
+ debug_fleave();
+}
+
+int _mm_streamrecorder_ini_unload(mm_streamrecorder_ini_t *ini)
+{
+ debug_fenter();
+
+ loaded = FALSE;
+
+ debug_fleave();
+
+ return MM_ERROR_NONE;
+}
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <string.h>
+#include <mm_types.h>
+#include <mm_error.h>
+
+#include "mm_streamrecorder_internal.h"
+#include "mm_streamrecorder_recorder.h"
+#include "mm_streamrecorder_attribute.h"
+#include "mm_streamrecorder_gstdispatch.h"
+
+#include <asm/types.h>
+
+/*---------------------------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS for internal |
+---------------------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------------------
+| LOCAL VARIABLE DEFINITIONS for internal |
+---------------------------------------------------------------------------------------*/
+#define __MMSTREAMRECORDER_CMD_ITERATE_MAX 3
+
+/*---------------------------------------------------------------------------------------
+| LOCAL FUNCTION PROTOTYPES: |
+---------------------------------------------------------------------------------------*/
+
+/*=======================================================================================
+| FUNCTION DEFINITIONS |
+=======================================================================================*/
+/*---------------------------------------------------------------------------------------
+| GLOBAL FUNCTION DEFINITIONS: |
+---------------------------------------------------------------------------------------*/
+
+/* Internal command functions {*/
+int _mmstreamrecorder_create(MMHandleType *handle)
+{
+ int ret = MM_ERROR_NONE;
+ /* char *err_attr_name = NULL; */
+ mmf_streamrecorder_t *hstreamrecorder = NULL;
+
+ _mmstreamrec_dbg_log("Entered");
+ mmf_return_val_if_fail(handle, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ /* Create mmf_streamrecorder_t handle and initialize every variable */
+ hstreamrecorder = (mmf_streamrecorder_t *) malloc(sizeof(mmf_streamrecorder_t));
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_LOW_MEMORY);
+ memset(hstreamrecorder, 0x00, sizeof(mmf_streamrecorder_t));
+
+ /* init values */
+ hstreamrecorder->sub_context = NULL;
+
+ pthread_mutex_init(&((hstreamrecorder->mtsafe).lock), NULL);
+ pthread_cond_init(&((hstreamrecorder->mtsafe).cond), NULL);
+
+ pthread_mutex_init(&((hstreamrecorder->mtsafe).cmd_lock), NULL);
+ pthread_mutex_init(&((hstreamrecorder->mtsafe).state_lock), NULL);
+ pthread_mutex_init(&((hstreamrecorder->mtsafe).gst_state_lock), NULL);
+ pthread_mutex_init(&((hstreamrecorder->mtsafe).message_cb_lock), NULL);
+
+ ret = _mm_streamrecorder_ini_load(&hstreamrecorder->ini);
+ if (ret != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_warn("failed to load ini file\n");
+ goto _ERR_INITIAL_INI;
+ }
+
+ hstreamrecorder->attributes = _mmstreamrecorder_alloc_attribute((MMHandleType) hstreamrecorder);
+
+ if (!(hstreamrecorder->attributes)) {
+ _mmstreamrec_dbg_err("_mmstreamrecorder_create::alloc attribute error.");
+
+ ret = MM_ERROR_STREAMRECORDER_RESOURCE_CREATION;
+ goto _ERR_ALLOC_ATTRIBUTE;
+ }
+
+ _mmstreamrecorder_alloc_subcontext((MMHandleType) hstreamrecorder);
+ if (!hstreamrecorder->sub_context) {
+ ret = MM_ERROR_STREAMRECORDER_RESOURCE_CREATION;
+ goto _ERR_ALLOC_SUBCONTEXT;
+ }
+
+ /* Initial GSTREAMER */
+ ret = _mmstreamrecorder_gstreamer_init();
+
+ if (!ret) {
+ _mmstreamrec_dbg_err("Failed to initialize gstreamer!!");
+ ret = MM_ERROR_STREAMRECORDER_NOT_INITIALIZED;
+ goto _ERR_INITIAL_GSTREAMER;
+ }
+
+ _mmstreamrecorder_set_state((MMHandleType)hstreamrecorder, MM_STREAMRECORDER_STATE_CREATED);
+
+ *handle = (MMHandleType) hstreamrecorder;
+
+ return MM_ERROR_NONE;
+
+ _ERR_INITIAL_GSTREAMER:
+ _mmstreamrecorder_dealloc_subcontext((MMHandleType) hstreamrecorder);
+ _ERR_ALLOC_ATTRIBUTE:
+ _ERR_ALLOC_SUBCONTEXT:
+ _ERR_INITIAL_INI:
+ pthread_mutex_destroy(&((hstreamrecorder->mtsafe).lock));
+ pthread_cond_destroy(&((hstreamrecorder->mtsafe).cond));
+ pthread_mutex_destroy(&((hstreamrecorder->mtsafe).cmd_lock));
+ pthread_mutex_destroy(&((hstreamrecorder->mtsafe).state_lock));
+ pthread_mutex_destroy(&((hstreamrecorder->mtsafe).gst_state_lock));
+ pthread_mutex_destroy(&((hstreamrecorder->mtsafe).message_cb_lock));
+ /* Release handle */
+ memset(hstreamrecorder, 0x00, sizeof(mmf_streamrecorder_t));
+ free(hstreamrecorder);
+
+ return ret;
+}
+
+MMStreamRecorderStateType _mmstreamrecorder_get_state(MMHandleType handle)
+{
+ int state;
+ mmf_streamrecorder_t *streamrecorder = MMF_STREAMRECORDER(handle);
+
+ mmf_return_val_if_fail(streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ _MMSTREAMRECORDER_LOCK_STATE(handle);
+
+ state = streamrecorder->state;
+
+ _MMSTREAMRECORDER_UNLOCK_STATE(handle);
+
+ return state;
+}
+
+void _mmstreamrecorder_set_state(MMHandleType handle, int state)
+{
+ int old_state;
+ mmf_streamrecorder_t *streamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderMsgItem msg;
+
+ mmf_return_val_if_fail(streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT);
+
+ /*_mmstreamrec_dbg_log("");*/
+
+ _MMSTREAMRECORDER_LOCK_STATE(handle);
+
+ old_state = streamrecorder->state;
+
+ if (old_state != state) {
+ streamrecorder->state = state;
+
+ _mmstreamrec_dbg_log("set state[%d] and send state-changed message", state);
+
+ msg.id = MM_MESSAGE_STREAMRECORDER_STATE_CHANGED;
+ msg.param.state.code = MM_ERROR_NONE;
+
+ msg.param.state.previous = old_state;
+ msg.param.state.current = state;
+
+ /*_mmstreamrec_dbg_log("_mmstreamcorder_send_message : msg : %p, id:%x", &msg, msg.id);*/
+ _mmstreamrecorder_send_message(handle, &msg);
+ }
+
+ _MMSTREAMRECORDER_UNLOCK_STATE(handle);
+
+ return;
+}
+
+
+
+int _mmstreamrecorder_destroy(MMHandleType handle)
+{
+ int ret = MM_ERROR_NONE;
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ _mmstreamrec_dbg_log("");
+
+ if (!hstreamrecorder) {
+ _mmstreamrec_dbg_err("Not initialized");
+ ret = MM_ERROR_STREAMRECORDER_NOT_INITIALIZED;
+ goto _ERR_STREAMRECORDER_CMD_PRECON;
+ }
+
+ if (!_MMSTREAMRECORDER_TRYLOCK_CMD(hstreamrecorder)) {
+ _mmstreamrec_dbg_err("Another command is running.");
+ ret = MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING;
+ goto _ERR_STREAMRECORDER_CMD_PRECON;
+ }
+
+ /* Release SubContext and pipeline */
+ if (hstreamrecorder->sub_context) {
+ if (hstreamrecorder->sub_context->encode_element)
+ _mmstreamrecorder_destroy_pipeline(handle);
+
+ _mmstreamrecorder_dealloc_subcontext(handle);
+ }
+
+ /* Remove attributes */
+ if (hstreamrecorder->attributes) {
+ _mmstreamrecorder_dealloc_attribute(hstreamrecorder->attributes);
+ hstreamrecorder->attributes = 0;
+ }
+
+ /* Remove messages which are not called yet */
+ _mmstreamrecorder_remove_message_all(handle);
+
+ _MMSTREAMRECORDER_UNLOCK_CMD(hstreamrecorder);
+
+ /* Release lock, cond */
+ pthread_mutex_destroy(&((hstreamrecorder->mtsafe).lock));
+ pthread_cond_destroy(&((hstreamrecorder->mtsafe).cond));
+ pthread_mutex_destroy(&((hstreamrecorder->mtsafe).cmd_lock));
+ pthread_mutex_destroy(&((hstreamrecorder->mtsafe).state_lock));
+ pthread_mutex_destroy(&((hstreamrecorder->mtsafe).gst_state_lock));
+ pthread_mutex_destroy(&((hstreamrecorder->mtsafe).message_cb_lock));
+
+ /* Release handle */
+ memset(hstreamrecorder, 0x00, sizeof(mmf_streamrecorder_t));
+ free(hstreamrecorder);
+
+ return MM_ERROR_NONE;
+
+ _ERR_STREAMRECORDER_CMD_PRECON:
+
+ _mmstreamrec_dbg_err("Destroy fail (ret %x)", ret);
+
+ return ret;
+}
+
+int _mmstreamrecorder_realize(MMHandleType handle)
+{
+ int ret = MM_ERROR_NONE;
+/* int errorcode = MM_ERROR_NONE;
+ char *videosink_element_type = NULL;
+ char *videosink_name = NULL; */
+
+ _mmstreamrec_dbg_log("");
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ if (!hstreamrecorder) {
+ _mmstreamrec_dbg_err("Not initialized");
+ ret = MM_ERROR_STREAMRECORDER_NOT_INITIALIZED;
+ return ret;
+ }
+
+ if (!_MMSTREAMRECORDER_TRYLOCK_CMD(hstreamrecorder)) {
+ _mmstreamrec_dbg_err("Another command is running.");
+ ret = MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING;
+ goto _ERR_STREAMRECORDER_CMD_PRECON;
+ }
+
+ /* create pipeline */
+ ret = _mmstreamrecorder_create_pipeline(handle);
+ if (ret != MM_ERROR_NONE) {
+ /* check internal error of gstreamer */
+ if (hstreamrecorder->sub_context->error_code != MM_ERROR_NONE) {
+ ret = hstreamrecorder->sub_context->error_code;
+ _mmstreamrec_dbg_log("gstreamer error is occurred. return it %x", ret);
+ }
+ /* release sub context */
+ _mmstreamrecorder_dealloc_subcontext(handle);
+ goto _ERR_STREAMRECORDER_CMD;
+ }
+
+ /* set command function */
+ _mmstreamrecorder_set_functions(handle);
+
+ _mmstreamrecorder_set_state(handle, MM_STREAMRECORDER_STATE_PREPARED);
+
+ _MMSTREAMRECORDER_UNLOCK_CMD(hstreamrecorder);
+
+ return MM_ERROR_NONE;
+
+ _ERR_STREAMRECORDER_CMD:
+/* _ERR_STREAMRECORDER_CMD_PRECON_AFTER_LOCK: */
+ /* Security thread release */
+ _MMSTREAMRECORDER_UNLOCK_CMD(hstreamrecorder);
+
+ _ERR_STREAMRECORDER_CMD_PRECON:
+/* _mmstreamrec_dbg_err("Realize fail (type %d, state %d, ret %x)", hstreamrecorder->type, state, ret); */
+
+ return ret;
+}
+
+int _mmstreamrecorder_unrealize(MMHandleType handle)
+{
+ int ret = MM_ERROR_NONE;
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ _mmstreamrec_dbg_log("");
+
+ if (!hstreamrecorder) {
+ _mmstreamrec_dbg_err("Not initialized");
+ ret = MM_ERROR_STREAMRECORDER_NOT_INITIALIZED;
+ return ret;
+ }
+
+ if (!_MMSTREAMRECORDER_TRYLOCK_CMD(hstreamrecorder)) {
+ _mmstreamrec_dbg_err("Another command is running.");
+ ret = MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING;
+ goto _ERR_STREAMRECORDER_CMD_PRECON;
+ }
+
+ /* Release SubContext */
+ if (hstreamrecorder->sub_context) {
+ /* destroy pipeline */
+ _mmstreamrecorder_destroy_pipeline(handle);
+ /* Deallocate SubContext */
+ }
+
+ /* Deinitialize main context member */
+ _mmstreamrecorder_unset_functions(handle);
+
+ _mmstreamrecorder_set_state(handle, MM_STREAMRECORDER_STATE_CREATED);
+
+ _MMSTREAMRECORDER_UNLOCK_CMD(hstreamrecorder);
+
+ return MM_ERROR_NONE;
+
+ _ERR_STREAMRECORDER_CMD_PRECON:
+ /* send message */
+ return ret;
+}
+
+int _mmstreamrecorder_record(MMHandleType handle)
+{
+ int ret = MM_ERROR_NONE;
+
+ _MMStreamRecorderSubContext *sc = NULL;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ _mmstreamrec_dbg_log("");
+
+ if (!hstreamrecorder) {
+ _mmstreamrec_dbg_err("Not initialized");
+ ret = MM_ERROR_STREAMRECORDER_NOT_INITIALIZED;
+ return ret;
+ }
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ /* initialize error code */
+ hstreamrecorder->sub_context->error_code = MM_ERROR_NONE;
+
+ ret = hstreamrecorder->command((MMHandleType) hstreamrecorder, _MM_STREAMRECORDER_CMD_RECORD);
+ if (ret != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_err("_mmstreamrecorder_record does not work!");
+ goto _ERR_STREAMRECORDER_CMD;
+ }
+
+ _mmstreamrecorder_set_state(handle, MM_STREAMRECORDER_STATE_RECORDING);
+
+ return MM_ERROR_NONE;
+
+ _ERR_STREAMRECORDER_CMD:
+ _ERR_STREAMRECORDER_CMD_PRECON:
+ /* check internal error of gstreamer */
+ if (hstreamrecorder->sub_context->error_code != MM_ERROR_NONE) {
+ ret = hstreamrecorder->sub_context->error_code;
+ hstreamrecorder->sub_context->error_code = MM_ERROR_NONE;
+
+ _mmstreamrec_dbg_log("gstreamer error is occurred. return it %x", ret);
+ }
+ return ret;
+}
+
+int _mmstreamrecorder_push_stream_buffer(MMHandleType handle, MMStreamRecorderStreamType streamtype, unsigned long timestamp, void *buffer, int size)
+{
+ int ret = MM_ERROR_NONE;
+
+ int format;
+ GstMapInfo map;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ /* _mmstreamrec_dbg_log(""); */
+
+ if (!hstreamrecorder) {
+ _mmstreamrec_dbg_err("Not initialized");
+ ret = MM_ERROR_STREAMRECORDER_NOT_INITIALIZED;
+ return ret;
+ }
+ mm_streamrecorder_get_attributes(handle, NULL,
+ MMSTR_VIDEO_SOURCE_FORMAT, &format,
+ NULL);
+ GstStreamRecorderBuffer *stream_buffer = NULL;
+ stream_buffer = (GstStreamRecorderBuffer *) malloc(sizeof(GstStreamRecorderBuffer));
+ if (stream_buffer == NULL) {
+ _mmstreamrec_dbg_err("stream buffer allocation fail");
+ return MM_ERROR_STREAMRECORDER_LOW_MEMORY;
+ }
+ stream_buffer->str_handle = handle;
+ stream_buffer->buffer = gst_buffer_new();
+ if (stream_buffer->buffer == NULL) {
+ free(stream_buffer);
+ stream_buffer = NULL;
+ _mmstreamrec_dbg_err("gst buffer allocation fail");
+ return MM_ERROR_STREAMRECORDER_LOW_MEMORY;
+ }
+ stream_buffer->user_buffer = buffer;
+ /* Get Media Packet to Surface to MMVideoBuffer */
+
+ stream_buffer->buffer->pts = timestamp;
+ GST_BUFFER_DURATION(stream_buffer->buffer) = GST_CLOCK_TIME_NONE;
+
+ gst_buffer_map(stream_buffer->buffer, &map, GST_MAP_READWRITE);
+ if (streamtype == MM_STREAM_TYPE_VIDEO) {
+ if (format == MM_STREAMRECORDER_INPUT_FORMAT_NV12 || format == MM_STREAMRECORDER_INPUT_FORMAT_NV21) {
+
+ MMVideoBuffer *video_buf = (MMVideoBuffer *)buffer;
+ /* Buffer at 0th position */
+ gst_buffer_append_memory(stream_buffer->buffer, gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY,
+ video_buf->handle.paddr[0], size, 0, size, video_buf->handle.paddr[0], NULL));
+ /* Buffer at 1st position */
+ gst_buffer_append_memory(stream_buffer->buffer, gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY,
+ video_buf, sizeof(MMVideoBuffer), 0, sizeof(MMVideoBuffer), stream_buffer, _mmstreamrecorder_buffer_destroy));
+ } else {
+ gst_buffer_append_memory(stream_buffer->buffer, gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY,
+ buffer, size, 0, size, stream_buffer, _mmstreamrecorder_buffer_destroy));
+ }
+ ret = _mmstreamrecorder_push_videostream_buffer(handle, timestamp, stream_buffer->buffer, size);
+ } else if (streamtype == MM_STREAM_TYPE_AUDIO) {
+ gst_buffer_append_memory(stream_buffer->buffer, gst_memory_new_wrapped(GST_MEMORY_FLAG_READONLY,
+ buffer, size, 0, buffer, stream_buffer, _mmstreamrecorder_buffer_destroy));
+ ret = _mmstreamrecorder_push_audiostream_buffer(handle, timestamp, stream_buffer->buffer, size);
+ } else {
+ gst_buffer_unmap(stream_buffer->buffer, &map);
+ gst_object_unref(stream_buffer->buffer);
+ free(stream_buffer);
+ stream_buffer = NULL;
+ return MM_ERROR_STREAMRECORDER_INVALID_CONDITION;
+ }
+ gst_buffer_unmap(stream_buffer->buffer, &map);
+ return ret;
+
+}
+
+int _mmstreamrecorder_pause(MMHandleType handle)
+{
+ int ret = MM_ERROR_NONE;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ _mmstreamrec_dbg_log("");
+
+ if (!hstreamrecorder) {
+ _mmstreamrec_dbg_err("Not initialized");
+ ret = MM_ERROR_STREAMRECORDER_NOT_INITIALIZED;
+ return ret;
+ }
+
+ if (!_MMSTREAMRECORDER_TRYLOCK_CMD(hstreamrecorder)) {
+ _mmstreamrec_dbg_err("Another command is running.");
+ ret = MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING;
+ goto _ERR_STREAMRECORDER_CMD_PRECON;
+ }
+
+ ret = hstreamrecorder->command((MMHandleType) hstreamrecorder, _MM_STREAMRECORDER_CMD_PAUSE);
+ if (ret != MM_ERROR_NONE)
+ goto _ERR_STREAMRECORDER_CMD;
+
+ _mmstreamrecorder_set_state(handle, MM_STREAMRECORDER_STATE_PAUSED);
+
+ _MMSTREAMRECORDER_UNLOCK_CMD(hstreamrecorder);
+
+ return MM_ERROR_NONE;
+
+ _ERR_STREAMRECORDER_CMD:
+ _MMSTREAMRECORDER_UNLOCK_CMD(hstreamrecorder);
+ _ERR_STREAMRECORDER_CMD_PRECON:
+ /* send message */
+ return ret;
+}
+
+int _mmstreamrecorder_commit(MMHandleType handle)
+{
+ int ret = MM_ERROR_NONE;
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ _mmstreamrec_dbg_log("");
+
+ if (!hstreamrecorder) {
+ _mmstreamrec_dbg_err("Not initialized");
+ ret = MM_ERROR_STREAMRECORDER_NOT_INITIALIZED;
+ return ret;
+ }
+
+ if (!_MMSTREAMRECORDER_TRYLOCK_CMD(hstreamrecorder)) {
+ _mmstreamrec_dbg_err("Another command is running.");
+ ret = MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING;
+ goto _ERR_STREAMRECORDER_CMD_PRECON;
+ }
+
+ ret = hstreamrecorder->command((MMHandleType) hstreamrecorder, _MM_STREAMRECORDER_CMD_COMMIT);
+ if (ret != MM_ERROR_NONE)
+ goto _ERR_STREAMRECORDER_CMD;
+
+ _mmstreamrecorder_set_state(handle, MM_STREAMRECORDER_STATE_PREPARED);
+
+ _MMSTREAMRECORDER_UNLOCK_CMD(hstreamrecorder);
+
+ return MM_ERROR_NONE;
+
+ _ERR_STREAMRECORDER_CMD:
+ _MMSTREAMRECORDER_UNLOCK_CMD(hstreamrecorder);
+ _ERR_STREAMRECORDER_CMD_PRECON:
+ /* send message */
+
+ return ret;
+}
+
+int _mmstreamrecorder_cancel(MMHandleType handle)
+{
+ int ret = MM_ERROR_NONE;
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ _mmstreamrec_dbg_log("");
+
+ if (!hstreamrecorder) {
+ _mmstreamrec_dbg_err("Not initialized");
+ ret = MM_ERROR_STREAMRECORDER_NOT_INITIALIZED;
+ return ret;
+ }
+
+ if (!_MMSTREAMRECORDER_TRYLOCK_CMD(hstreamrecorder)) {
+ _mmstreamrec_dbg_err("Another command is running.");
+ ret = MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING;
+ goto _ERR_STREAMRECORDER_CMD_PRECON;
+ }
+
+ ret = hstreamrecorder->command((MMHandleType) hstreamrecorder, _MM_STREAMRECORDER_CMD_CANCEL);
+ if (ret != MM_ERROR_NONE)
+ goto _ERR_STREAMRECORDER_CMD;
+
+ _mmstreamrecorder_set_state(handle, MM_STREAMRECORDER_STATE_PREPARED);
+
+ _MMSTREAMRECORDER_UNLOCK_CMD(hstreamrecorder);
+
+ return MM_ERROR_NONE;
+
+ _ERR_STREAMRECORDER_CMD:
+ _MMSTREAMRECORDER_UNLOCK_CMD(hstreamrecorder);
+ _ERR_STREAMRECORDER_CMD_PRECON:
+ /* send message */
+
+ return ret;
+}
+
+/* } Internal command functions */
+
+int _mmstreamrecorder_set_message_callback(MMHandleType handle, MMMessageCallback callback, void *user_data)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ _mmstreamrec_dbg_log("%p", hstreamrecorder);
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ if (callback == NULL) {
+ _mmstreamrec_dbg_warn("Message Callback is disabled");
+ _mmstreamrec_dbg_warn("Application sets callback as NULL");
+ }
+
+ if (!_MMSTREAMRECORDER_TRYLOCK_MESSAGE_CALLBACK(hstreamrecorder)) {
+ _mmstreamrec_dbg_warn("Application's message callback is running now");
+ return MM_ERROR_STREAMRECORDER_INVALID_CONDITION;
+ }
+
+ /* set message callback to message handle */
+ hstreamrecorder->msg_cb = callback;
+ hstreamrecorder->msg_cb_param = user_data;
+
+ _MMSTREAMRECORDER_UNLOCK_MESSAGE_CALLBACK(hstreamrecorder);
+
+ return MM_ERROR_NONE;
+}
+
+int _mmstreamrecorder_alloc_subcontext(MMHandleType handle)
+{
+ int i;
+ int ret = MM_ERROR_NONE;
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ _mmstreamrec_dbg_log("");
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_RESOURCE_CREATION);
+
+ /* alloc container */
+ sc = (_MMStreamRecorderSubContext *) malloc(sizeof(_MMStreamRecorderSubContext));
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_LOW_MEMORY);
+
+ /* init members */
+ memset(sc, 0x00, sizeof(_MMStreamRecorderSubContext));
+
+ sc->encode_element_num = _MMSTREAMRECORDER_ENCODE_PIPELINE_ELEMENT_NUM;
+
+ /* alloc element array */
+ sc->encode_element = (_MMStreamRecorderGstElement *) malloc(sizeof(_MMStreamRecorderGstElement) * sc->encode_element_num);
+ if (!sc->encode_element) {
+ _mmstreamrec_dbg_err("Failed to alloc encode element structure");
+ goto ALLOC_SUBCONTEXT_FAILED;
+ }
+
+ for (i = 0; i < sc->encode_element_num; i++) {
+ sc->encode_element[i].id = _MMSTREAMRECORDER_ENCODE_NONE;
+ sc->encode_element[i].gst = NULL;
+ }
+
+ sc->fourcc = 0x80000000;
+
+ hstreamrecorder->sub_context = sc;
+
+ ret = _mmstreamrecorder_alloc_subcontext_fileinfo((MMHandleType) hstreamrecorder);
+ if (ret != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_err("Failed to allocate subcontext fileinfo");
+ goto ALLOC_SUBCONTEXT_FAILED;
+ }
+
+ ret = _mmstreamrecorder_alloc_subcontext_videoinfo((MMHandleType) hstreamrecorder);
+ if (ret != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_err("Failed to allocate subcontext videoinfo");
+ goto ALLOC_SUBCONTEXT_FAILED;
+ }
+
+ _mmstreamrecorder_alloc_subcontext_audioinfo((MMHandleType) hstreamrecorder);
+ if (ret != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_err("Failed to allocate subcontext audioinfo");
+ goto ALLOC_SUBCONTEXT_FAILED;
+ }
+
+ return MM_ERROR_NONE;
+
+ ALLOC_SUBCONTEXT_FAILED:
+
+ if (sc) {
+ if (sc->encode_element) {
+ free(sc->encode_element);
+ sc->encode_element = NULL;
+ }
+ free(sc);
+ sc = NULL;
+ }
+ if (hstreamrecorder->sub_context != NULL)
+ hstreamrecorder->sub_context = NULL;
+ return MM_ERROR_STREAMRECORDER_LOW_MEMORY;
+}
+
+int _mmstreamrecorder_alloc_subcontext_videoinfo(MMHandleType handle)
+{
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ _mmstreamrec_dbg_log("");
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ /* alloc info for each mode */
+
+ sc->info_video = malloc(sizeof(_MMStreamRecorderVideoInfo));
+ if (!sc->info_video) {
+ _mmstreamrec_dbg_err("Failed to alloc info structure");
+ return MM_ERROR_STREAMRECORDER_LOW_MEMORY;
+ }
+ memset(sc->info_video, 0x00, sizeof(_MMStreamRecorderVideoInfo));
+
+ return MM_ERROR_NONE;
+}
+
+int _mmstreamrecorder_alloc_subcontext_audioinfo(MMHandleType handle)
+{
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ _mmstreamrec_dbg_log("");
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ /* alloc info for each mode */
+ sc->info_audio = malloc(sizeof(_MMStreamRecorderAudioInfo));
+ if (!sc->info_audio) {
+ _mmstreamrec_dbg_err("Failed to alloc info structure");
+ return MM_ERROR_STREAMRECORDER_LOW_MEMORY;
+ }
+ memset(sc->info_audio, 0x00, sizeof(_MMStreamRecorderAudioInfo));
+
+ return MM_ERROR_NONE;
+}
+
+int _mmstreamrecorder_alloc_subcontext_fileinfo(MMHandleType handle)
+{
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ _mmstreamrec_dbg_log("");
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ /* alloc info for each mode */
+ sc->info_file = malloc(sizeof(_MMStreamRecorderFileInfo));
+ if (!sc->info_file) {
+ _mmstreamrec_dbg_err("Failed to alloc info structure");
+ return MM_ERROR_STREAMRECORDER_LOW_MEMORY;
+ }
+ memset(sc->info_file, 0x00, sizeof(_MMStreamRecorderFileInfo));
+
+ return MM_ERROR_NONE;
+}
+
+void _mmstreamrecorder_dealloc_subcontext(MMHandleType handle)
+{
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ _mmstreamrec_dbg_log("");
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ mmf_return_if_fail(hstreamrecorder);
+ mmf_return_if_fail(hstreamrecorder->sub_context);
+
+ sc = hstreamrecorder->sub_context;
+
+ if (sc) {
+
+ if (sc->encode_element) {
+ _mmstreamrec_dbg_log("release encode_element");
+ free(sc->encode_element);
+ sc->encode_element = NULL;
+ }
+
+ if (sc->info_video) {
+ _mmstreamrec_dbg_log("release info_video");
+ free(sc->info_video);
+ sc->info_video = NULL;
+ }
+
+ if (sc->info_audio) {
+ _mmstreamrec_dbg_log("release info_audio");
+ free(sc->info_audio);
+ sc->info_audio = NULL;
+ }
+
+ if (sc->info_file) {
+ _mmstreamrec_dbg_log("release info_file");
+ free(sc->info_file);
+ sc->info_file = NULL;
+ }
+
+ free(sc);
+ sc = NULL;
+ }
+ if (hstreamrecorder->sub_context != NULL)
+ hstreamrecorder->sub_context = NULL;
+
+ return;
+}
+
+void _mmstreamrecorder_set_functions(MMHandleType handle)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ _mmstreamrec_dbg_log("");
+
+ /* Now only video type */
+
+ hstreamrecorder->command = _mmstreamrecorder_video_command;
+
+ return;
+}
+
+void _mmstreamrecorder_unset_functions(MMHandleType handle)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+
+ _mmstreamrec_dbg_log("");
+
+ hstreamrecorder->command = NULL;
+
+ return;
+}
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 "mm_streamrecorder_internal.h"
+#include "mm_streamrecorder_video.h"
+#include "mm_streamrecorder_gstcommon.h"
+#include "mm_streamrecorder_recorder.h"
+#include "mm_streamrecorder_util.h"
+#include "mm_streamrecorder_buffer_manager.h"
+#include "mm_streamrecorder_fileinfo.h"
+#include "mm_streamrecorder_attribute.h"
+
+#include <gst/gst.h>
+#include <gst/base/gstadapter.h>
+#include <gst/app/gstappsrc.h>
+#include <gst/app/gstappsink.h>
+
+
+/*---------------------------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS for internal |
+---------------------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------------------
+| LOCAL VARIABLE DEFINITIONS for internal |
+---------------------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS for internal |
+-----------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------------------
+| LOCAL FUNCTION PROTOTYPES: |
+---------------------------------------------------------------------------------------*/
+/* STATIC INTERNAL FUNCTION */
+
+/*=======================================================================================
+| FUNCTION DEFINITIONS |
+=======================================================================================*/
+/*---------------------------------------------------------------------------------------
+| GLOBAL FUNCTION DEFINITIONS: |
+---------------------------------------------------------------------------------------*/
+int _mmstreamrecorder_create_pipeline(MMHandleType handle)
+{
+ int ret = MM_ERROR_NONE;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ GstElement *pipeline = NULL;
+
+ _mmstreamrec_dbg_log("handle : %x", handle);
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ /* ENCODER MODE */
+ ret = _mmstreamrecorder_create_recorder_pipeline(handle);
+
+ pipeline = sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst;
+
+ ret = _mmstreamrecorder_gst_set_state(handle, pipeline, GST_STATE_READY);
+
+ _mmstreamrec_dbg_log("ret[%x]", ret);
+ return ret;
+}
+
+void _mmstreamrecorder_destroy_pipeline(MMHandleType handle)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ gint i = 0;
+ int element_num = 0;
+ _MMStreamRecorderGstElement *element = NULL;
+ GstBus *bus = NULL;
+
+ mmf_return_if_fail(hstreamrecorder);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_if_fail(sc);
+
+ _mmstreamrec_dbg_log("");
+
+ element = sc->encode_element;
+ element_num = sc->encode_element_num;
+ if (element == NULL) {
+ _mmstreamrec_dbg_log("encode element is null!!");
+ return;
+ }
+
+ if (sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst != NULL) {
+ bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst));
+
+ _mmstreamrec_dbg_log("Pipeline clear!!");
+
+ /* Remove pipeline message callback */
+ if (hstreamrecorder->pipeline_cb_event_id != 0) {
+ g_source_remove(hstreamrecorder->pipeline_cb_event_id);
+ hstreamrecorder->pipeline_cb_event_id = 0;
+ }
+
+ /* Remove remained message in bus */
+ if (bus) {
+ GstMessage *gst_msg = NULL;
+ while ((gst_msg = gst_bus_pop(bus)) != NULL) {
+ _mmstreamrecorder_pipeline_cb_message(bus, gst_msg, (gpointer) hstreamrecorder);
+ gst_message_unref(gst_msg);
+ gst_msg = NULL;
+ }
+ gst_object_unref(bus);
+ bus = NULL;
+ }
+
+ /* Inside each pipeline destroy function, Set GST_STATE_NULL to Main pipeline */
+ _mmstreamrecorder_destroy_recorder_pipeline(handle);
+ }
+
+ if (element != NULL) {
+ /* checking unreleased element */
+ for (i = 0; i < element_num; i++) {
+ if (element[i].gst) {
+ if (GST_IS_ELEMENT(element[i].gst)) {
+ _mmstreamrec_dbg_warn("Still alive element - ID[%d], name [%s], ref count[%d], status[%s]", element[i].id, GST_OBJECT_NAME(element[i].gst), GST_OBJECT_REFCOUNT(element[i].gst), gst_element_state_get_name(GST_STATE(element[i].gst)));
+ g_object_weak_unref(G_OBJECT(element[i].gst), (GWeakNotify) _mmstreamrecorder_element_release_noti, sc);
+ } else {
+ _mmstreamrec_dbg_warn("The element[%d] is still aliving, check it", element[i].id);
+ }
+
+ element[i].id = _MMSTREAMRECORDER_ENCODE_NONE;
+ element[i].gst = NULL;
+ }
+ }
+ }
+ return;
+}
+
+int _mmstreamrecorder_create_recorder_pipeline(MMHandleType handle)
+{
+ int i = 0;
+ int err = MM_ERROR_NONE;
+ int audio_enable = FALSE;
+ GstBus *bus = NULL;
+ GstPad *srcpad = NULL;
+ GstPad *sinkpad = NULL;
+
+ unsigned int video_codec = MM_VIDEO_CODEC_INVALID;
+ unsigned int file_format = MM_FILE_FORMAT_INVALID;
+ char *err_name = NULL;
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ _mmstreamrec_dbg_warn("start");
+
+ err = mm_streamrecorder_get_attributes(handle, &err_name, MMSTR_VIDEO_ENCODER, &video_codec, MMSTR_FILE_FORMAT, &file_format, NULL);
+ if (err != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
+ SAFE_FREE(err_name);
+ return err;
+ }
+
+ err = _mmstreamrecorder_check_videocodec_fileformat_compatibility(video_codec, file_format);
+ if (err != MM_ERROR_NONE)
+ return err;
+
+ /* Main pipeline */
+ _MMSTREAMRECORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
+
+ /* get audio disable */
+ mm_streamrecorder_get_attributes(handle, NULL, MMSTR_AUDIO_ENABLE, &audio_enable, NULL);
+ sc->audio_enable = audio_enable;
+
+ _mmstreamrec_dbg_log("AUDIO DISABLE : %d", sc->audio_enable);
+
+ if (sc->audio_enable == TRUE) {
+ /* create audiosrc bin */
+ err = _mmstreamrecorder_create_audiosrc_bin((MMHandleType) hstreamrecorder);
+ if (err != MM_ERROR_NONE)
+ return err;
+ }
+
+ err = _mmstreamrecorder_create_encodesink_bin((MMHandleType) hstreamrecorder, MM_STREAMRECORDER_ENCBIN_PROFILE_VIDEO);
+ if (err != MM_ERROR_NONE)
+ return err;
+
+ if (sc->audio_enable == TRUE) {
+ gst_bin_add(GST_BIN(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst), sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst);
+ }
+
+ /* add element and encodesink bin to encode main pipeline */
+ gst_bin_add_many(GST_BIN(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst), sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SRC].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_FILT].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst, NULL);
+
+ /* Link each element : appsrc - capsfilter - encodesink bin */
+ srcpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SRC].gst, "src");
+ sinkpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_FILT].gst, "sink");
+ _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
+
+ srcpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_FILT].gst, "src");
+ sinkpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst, "video_sink0");
+ _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
+
+ if (sc->audio_enable == TRUE) {
+ srcpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst, "src");
+ sinkpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst, "audio_sink0");
+ _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
+ }
+
+ if (sc->audio_enable == TRUE) {
+ sinkpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC].gst, "sink");
+ MMSTREAMRECORDER_ADD_BUFFER_PROBE(sinkpad, _MMSTREAMRECORDER_HANDLER_VIDEOREC, __mmstreamrecorder_audioque_dataprobe, hstreamrecorder);
+ gst_object_unref(sinkpad);
+ sinkpad = NULL;
+
+ if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst) {
+ srcpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC_QUE].gst, "src");
+ MMSTREAMRECORDER_ADD_EVENT_PROBE(srcpad, _MMSTREAMRECORDER_HANDLER_VIDEOREC, __mmstreamrecorder_eventprobe_monitor, hstreamrecorder);
+ gst_object_unref(srcpad);
+ srcpad = NULL;
+ }
+ }
+
+ if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst) {
+ srcpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC_QUE].gst, "src");
+ MMSTREAMRECORDER_ADD_EVENT_PROBE(srcpad, _MMSTREAMRECORDER_HANDLER_VIDEOREC, __mmstreamrecorder_eventprobe_monitor, hstreamrecorder);
+ gst_object_unref(srcpad);
+ srcpad = NULL;
+ }
+
+ if (sc->audio_enable == FALSE) {
+ sinkpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst, "sink");
+ MMSTREAMRECORDER_ADD_BUFFER_PROBE(sinkpad, _MMSTREAMRECORDER_HANDLER_VIDEOREC, __mmstreamrecorder_video_dataprobe_audio_disable, hstreamrecorder);
+ gst_object_unref(sinkpad);
+ sinkpad = NULL;
+ }
+
+ if (!strcmp(/*gst_element_rsink_name */"filesink", "filesink")) {
+ srcpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst, "src");
+ MMSTREAMRECORDER_ADD_BUFFER_PROBE(srcpad, _MMSTREAMRECORDER_HANDLER_VIDEOREC, __mmstreamrecorder_video_dataprobe_record, hstreamrecorder);
+ gst_object_unref(srcpad);
+ srcpad = NULL;
+
+ if (sc->audio_enable == TRUE) {
+ srcpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC].gst, "src");
+ MMSTREAMRECORDER_ADD_BUFFER_PROBE(srcpad, _MMSTREAMRECORDER_HANDLER_VIDEOREC, __mmstreamrecorder_audio_dataprobe_check, hstreamrecorder);
+ gst_object_unref(srcpad);
+ srcpad = NULL;
+ }
+ }
+
+ bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst));
+
+ /* register pipeline message callback */
+ hstreamrecorder->encode_pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc) _mmstreamrecorder_pipeline_cb_message, hstreamrecorder);
+
+ gst_object_unref(bus);
+ bus = NULL;
+
+ return MM_ERROR_NONE;
+
+ pipeline_creation_error:
+ for (i = _MMSTREAMRECORDER_AUDIOSRC_BIN; i <= _MMSTREAMRECORDER_ENCSINK_SINK; i++) {
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, i);
+ }
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCODE_MAIN_PIPE);
+ return err;
+}
+
+int _mmstreamrecorder_destroy_recorder_pipeline(MMHandleType handle)
+{
+ int ret = MM_ERROR_NONE;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ GstBus *bus = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ _mmstreamrec_dbg_log("start");
+
+ if (!sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst) {
+ _mmstreamrec_dbg_warn("pipeline is not existed.");
+ return MM_ERROR_NONE;
+ }
+
+ _mmstreamrecorder_remove_all_handlers((MMHandleType) hstreamrecorder, _MMSTREAMRECORDER_HANDLER_VIDEOREC);
+
+ ret = _mmstreamrecorder_gst_set_state(handle, sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
+ if (ret != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_err("Faile to change encode main pipeline [0x%x]", ret);
+ return ret;
+ }
+
+ bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst));
+
+ /* Remove remained message */
+ if (bus) {
+ GstMessage *gst_msg = NULL;
+ while ((gst_msg = gst_bus_pop(bus)) != NULL) {
+ _mmstreamrecorder_pipeline_cb_message(bus, gst_msg, (gpointer) hstreamrecorder);
+ gst_message_unref(gst_msg);
+ gst_msg = NULL;
+ }
+ gst_object_unref(bus);
+ bus = NULL;
+ }
+
+ /* remove audio pipeline first */
+ ret = _mmstreamrecorder_destroy_audiosrc_bin(handle);
+ if (ret != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_err("Fail to remove audio pipeline");
+ return ret;
+ }
+
+ ret = _mmstreamrecorder_destroy_encodesink_bin(handle);
+ if (ret != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_err("Fail to remove encoder pipeline");
+ return ret;
+ }
+
+ /* Remove pipeline message callback */
+ if (hstreamrecorder->encode_pipeline_cb_event_id != 0) {
+ g_source_remove(hstreamrecorder->encode_pipeline_cb_event_id);
+ hstreamrecorder->encode_pipeline_cb_event_id = 0;
+ }
+
+ _mmstreamrec_dbg_log("done");
+
+ return ret;
+}
+
+int _mmstreamrecorder_create_encodesink_bin(MMHandleType handle, MMStreamRecorderEncodebinProfile profile)
+{
+ int err = MM_ERROR_NONE;
+ int result = 0;
+ int channel = 0;
+ int audio_enc = 0;
+ int video_enc = 0;
+ int v_bitrate = 0;
+ int a_bitrate = 0;
+ int video_width = 0;
+ int video_height = 0;
+ int video_fps = 0;
+ int file_format = 0;
+ int audio_src_format = 0;
+ int video_src_format = 0;
+ int audio_samplerate = 0;
+ const char *str_profile = NULL;
+ const char *str_aac = NULL;
+ const char *str_aar = NULL;
+ const char *str_acs = NULL;
+ char *err_name = NULL;
+
+ GstCaps *caps = NULL;
+ GstPad *pad = NULL;
+ GList *element_list = NULL;
+ char *temp_filename = NULL;
+ int fileformat = 0;
+ int size = 0;
+ guint imax_size = 0;
+ guint imax_time = 0;
+ int rec_mode = 0;
+
+ _MMStreamRecorderVideoInfo *info = NULL;
+ _MMStreamRecorderFileInfo *finfo = NULL;
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ /* type_element *VideoencElement = NULL; */
+ /* type_element *AudioencElement = NULL; */
+ /* type_element *MuxElement = NULL; */
+ /* type_element *RecordsinkElement = NULL; */
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ _mmstreamrec_dbg_log("start - profile : %d", profile);
+
+ info = sc->info_video;
+ finfo = sc->info_file;
+
+ /* check element availability */
+ mm_streamrecorder_get_attributes(handle, &err_name, MMSTR_AUDIO_ENCODER, &audio_enc, MMSTR_AUDIO_CHANNEL, &channel, MMSTR_VIDEO_BITRATE, &v_bitrate, MMSTR_VIDEO_ENCODER, &video_enc, MMSTR_AUDIO_BITRATE, &a_bitrate, MMSTR_VIDEO_RESOLUTION_WIDTH, &video_width, MMSTR_VIDEO_RESOLUTION_HEIGHT, &video_height, MMSTR_VIDEO_FRAMERATE, &video_fps, MMSTR_FILE_FORMAT, &file_format, MMSTR_AUDIO_SAMPLERATE, &audio_samplerate, MMSTR_AUDIO_SOURCE_FORMAT, &audio_src_format, MMSTR_VIDEO_SOURCE_FORMAT, &video_src_format, MMSTR_RECORDER_MODE, &rec_mode, NULL);
+
+ _mmstreamrec_dbg_err("audio encoder - %d , video encoder : %d", audio_enc, video_enc);
+ _mmstreamrec_dbg_err("audio channel - %d , video v_bitrate : %d", channel, v_bitrate);
+ _mmstreamrec_dbg_err("audio a_bitrate - %d , video video_width : %d ,video video_height : %d ", a_bitrate, video_width, video_height);
+ _mmstreamrec_dbg_err("video_fps - %d , video file_format : %d", video_fps, file_format);
+
+ /* Check existence */
+ if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst) {
+ if (((GObject *) sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst)->ref_count > 0)
+ gst_object_unref(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst);
+
+ _mmstreamrec_dbg_log("_MMSTREAMRECORDER_ENCSINK_BIN is Already existed.");
+ }
+
+ /* Create bin element */
+ _MMSTREAMRECORDER_BIN_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_ENCSINK_BIN, "encodesink_bin", err);
+
+ /* Create child element */
+ if (hstreamrecorder->ini.encsink_bin_profile != MM_STREAMRECORDER_ENCBIN_PROFILE_AUDIO) {
+ /* create appsrc and capsfilter */
+ _MMSTREAMRECORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_ENCSINK_SRC, hstreamrecorder->ini.name_of_encsink_src, "encodesink_src", element_list, err);
+ _MMSTREAMRECORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_ENCSINK_FILT, "capsfilter", "encodesink_filter", element_list, err);
+
+ caps = gst_set_videosrcpad_caps(video_src_format, video_width, video_height, video_fps, 1);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SRC].gst, "caps", caps);
+ if (caps) {
+ gst_caps_unref(caps);
+ caps = NULL;
+ }
+
+ caps = gst_set_videosrcpad_caps(video_src_format, video_width, video_height, video_fps, 1);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_FILT].gst, "caps", caps);
+ if (caps) {
+ gst_caps_unref(caps);
+ caps = NULL;
+ }
+
+
+ /* release element_list, they will be placed out of encodesink bin */
+ if (element_list) {
+ g_list_free(element_list);
+ element_list = NULL;
+ }
+ if (rec_mode == MM_STREAMRECORDER_MODE_MEDIABUFFER) {
+ /* set appsrc as live source */
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SRC].gst, "is-live", hstreamrecorder->ini.encsink_src_islive);
+ }
+
+ }
+
+ _MMSTREAMRECORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_ENCSINK_ENCBIN, "encodebin", "encodesink_encbin", element_list, err);
+
+ _mmstreamrec_dbg_log("Profile[%d]", profile);
+
+ /* Set information */
+ if (hstreamrecorder->ini.encsink_bin_profile == MM_STREAMRECORDER_ENCBIN_PROFILE_VIDEO) {
+ str_profile = "VideoProfile";
+ str_aac = "VideoAutoAudioConvert";
+ str_aar = "VideoAutoAudioResample";
+ str_acs = "VideoAutoColorSpace";
+ } else if (hstreamrecorder->ini.encsink_bin_profile == MM_STREAMRECORDER_ENCBIN_PROFILE_AUDIO) {
+ str_profile = "AudioProfile";
+ str_aac = "AudioAutoAudioConvert";
+ str_aar = "AudioAutoAudioResample";
+ str_acs = "AudioAutoColorSpace";
+ }
+
+ /* TODO : check the last value ( set ) */
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "profile", hstreamrecorder->ini.encsink_bin_profile);
+ if (rec_mode == MM_STREAMRECORDER_MODE_MEDIABUFFER) {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "auto-audio-convert", hstreamrecorder->ini.encsink_bin_auto_audio_convert);
+ }
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "auto-audio-resample", hstreamrecorder->ini.encsink_bin_auto_audio_resample);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "auto-colorspace", hstreamrecorder->ini.encsink_bin_auto_colorspace);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "use-video-toggle", hstreamrecorder->ini.encsink_bin_use_video_toggle);
+
+ /* Codec */
+ if (hstreamrecorder->ini.encsink_bin_profile == MM_STREAMRECORDER_ENCBIN_PROFILE_VIDEO) {
+ switch (video_enc) {
+ case MM_VIDEO_CODEC_H263:
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "venc-name", hstreamrecorder->ini.h263_video_encoder);
+ break;
+ case MM_VIDEO_CODEC_H264:
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "venc-name", hstreamrecorder->ini.h264_video_encoder);
+ break;
+ case MM_VIDEO_CODEC_MPEG4:
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "venc-name", hstreamrecorder->ini.mpeg4_video_encoder);
+ break;
+ default:
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "venc-name", hstreamrecorder->ini.h264_video_encoder);
+ break;
+ }
+ _MMSTREAMRECORDER_ENCODEBIN_ELMGET(sc, _MMSTREAMRECORDER_ENCSINK_VENC, "video-encode", err);
+ /* _mmstreamrec_dbg_err(" hyuntae log = %p sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst = %p" ,sc, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst); */
+
+
+ /* set color converter size */
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "vconv-name", hstreamrecorder->ini.name_of_encsink_bin_video_converter);
+ _MMSTREAMRECORDER_ENCODEBIN_ELMGET(sc, _MMSTREAMRECORDER_ENCSINK_VCONV, "video-convert", err);
+
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "auto-colorspace", hstreamrecorder->ini.encsink_bin_auto_colorspace);
+
+ if (video_src_format == MM_STREAMRECORDER_INPUT_FORMAT_NV12) {
+ video_src_format = MM_STREAMRECORDER_INPUT_FORMAT_I420;
+ }
+ caps = gst_set_videosrcpad_caps(video_src_format, video_width, video_height, video_fps, 1);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "vcaps", caps);
+ if (video_src_format != MM_STREAMRECORDER_INPUT_FORMAT_NV12) {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VCONV].gst, "dst-buffer-num", hstreamrecorder->ini.convert_output_buffer_num);
+ }
+ /* state tuning */
+ err = gst_pad_set_caps(gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst, "sink"), caps);
+ err = MM_ERROR_NONE;
+ /* MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst, "state-tuning", TRUE); */
+
+ if (caps) {
+ gst_caps_unref(caps);
+ caps = NULL;
+ }
+ _mmstreamrec_dbg_log("size %dx%d, dst-buffer-num %d", video_width, video_height, hstreamrecorder->ini.convert_output_buffer_num);
+
+ _mmstreamrec_dbg_warn("encoder set caps result : 0x%x", err);
+
+ if (hstreamrecorder->ini.encsink_bin_use_parser[0]) {
+ GstElement *parser = gst_element_factory_make(hstreamrecorder->ini.encsink_bin_use_parser, "parse");
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "use-venc-queue", parser);
+ _MMSTREAMRECORDER_ENCODEBIN_ELMGET(sc, _MMSTREAMRECORDER_ENCSINK_PARSER, "use-venc-queue", err);
+ }
+ }
+
+ if (sc->audio_enable == TRUE) {
+
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "aenc-name", hstreamrecorder->ini.name_of_encsink_bin_audio_encoder);
+ _MMSTREAMRECORDER_ENCODEBIN_ELMGET(sc, _MMSTREAMRECORDER_ENCSINK_AENC, "audio-encode", err);
+ _mmstreamrec_dbg_err("audio-encode err = %x ", err);
+
+ /* Set basic infomation */
+ if (audio_enc != MM_AUDIO_CODEC_VORBIS) {
+ int depth = 0;
+
+ if (audio_src_format == MM_STREAMRECORDER_AUDIO_FORMAT_PCM_S16_LE) {
+ depth = 16;
+ } else { /* MM_STREAMRECORDER_AUDIO_FORMAT_PCM_U8 */
+ depth = 8;
+ }
+
+ /* TODO : set rate , channel , depth */
+
+ caps = gst_set_audiosrcpad_caps(audio_samplerate, 2, depth, 16, 1);
+ /* MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "auto-audio-convert", TRUE); */
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "acaps", caps);
+ {
+ gchar *type = gst_caps_to_string(caps);
+
+ _mmstreamrec_dbg_warn("Set srcpad caps: %s", type);
+ }
+ gst_caps_unref(caps);
+ caps = NULL;
+ } else {
+ /* what are the audio encoder which should get audio/x-raw-float? */
+ caps = gst_caps_new_simple("audio/x-raw", "rate", G_TYPE_INT, audio_samplerate, "channels", G_TYPE_INT, channel, "endianness", G_TYPE_INT, BYTE_ORDER, "width", G_TYPE_INT, 32, NULL);
+ _mmstreamrec_dbg_log("caps [x-raw-float, rate:%d, channel:%d, endianness:%d, width:32]", audio_samplerate, channel, BYTE_ORDER);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "auto-audio-convert", TRUE);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "acaps", caps);
+ gst_caps_unref(caps);
+ caps = NULL;
+ }
+
+#if 0
+ if (audio_enc == MM_AUDIO_CODEC_AMR && channel == 2) {
+ caps = gst_caps_new_simple("audio/x-raw-int", "channels", G_TYPE_INT, 1, NULL);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "auto-audio-convert", TRUE);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "acaps", caps);
+ gst_caps_unref(caps);
+ caps = NULL;
+ }
+
+ if (audio_enc == MM_AUDIO_CODEC_OGG) {
+ caps = gst_caps_new_simple("audio/x-raw-int", NULL);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "auto-audio-convert", TRUE);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "acaps", caps);
+ gst_caps_unref(caps);
+ caps = NULL;
+ }
+#endif
+
+ _MMSTREAMRECORDER_ENCODEBIN_ELMGET(sc, _MMSTREAMRECORDER_ENCSINK_AENC_QUE, "use-aenc-queue", err);
+ }
+
+ /* Mux */
+ switch (file_format) {
+ case MM_FILE_FORMAT_3GP:{
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "mux-name", hstreamrecorder->ini.name_of_encsink_bin_3GPMUXER);
+ }
+ break;
+
+ case MM_FILE_FORMAT_MP4:{
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "mux-name", hstreamrecorder->ini.name_of_encsink_bin_MP4MUXER);
+ }
+ break;
+
+ default:{
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "mux-name", hstreamrecorder->ini.name_of_encsink_bin_MP4MUXER);
+ }
+ break;
+
+ }
+ _MMSTREAMRECORDER_ENCODEBIN_ELMGET(sc, _MMSTREAMRECORDER_ENCSINK_MUX, "mux", err);
+
+ /* Sink */
+ /* for recording */
+ _MMSTREAMRECORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_ENCSINK_SINK, "filesink", NULL, element_list, err);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SINK].gst, "async", 0);
+
+ err = mm_streamrecorder_get_attributes(handle, &err_name,
+ MMSTR_FILE_FORMAT, &fileformat, MMSTR_FILENAME, &temp_filename, &size,
+ MMSTR_TARGET_MAX_SIZE, &imax_size,
+ MMSTR_TARGET_TIME_LIMIT, &imax_time,
+ NULL);
+
+ if (err != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
+ SAFE_FREE(err_name);
+ return err;
+ }
+
+ finfo->fileformat = fileformat;
+
+ /* set max size */
+ if (imax_size <= 0)
+ info->max_size = 0; /* do not check */
+ else
+ info->max_size = ((guint64) imax_size) << 10; /* to byte */
+
+ /* set max time */
+ if (imax_time <= 0)
+ info->max_time = 0; /* do not check */
+ else
+ info->max_time = ((guint64) imax_time) * 1000; /* to millisecond */
+
+ finfo->filename = strdup(temp_filename);
+ if (!finfo->filename) {
+ _mmstreamrec_dbg_err("strdup was failed");
+ return err;
+ }
+
+ _mmstreamrec_dbg_log("Record start : set file name using attribute - %s ", finfo->filename);
+
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SINK].gst, "location", finfo->filename);
+
+ if (profile == MM_STREAMRECORDER_ENCBIN_PROFILE_VIDEO) {
+ /* video encoder attribute setting */
+ if (v_bitrate > 0) {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst, "bitrate", v_bitrate);
+ } else {
+ _mmstreamrec_dbg_warn("video bitrate is too small[%d], so skip setting. Use DEFAULT value.", v_bitrate);
+ }
+ }
+
+ if (sc->audio_enable == TRUE) {
+ /* audio encoder attribute setting */
+ if (a_bitrate > 0) {
+ switch (audio_enc) {
+ case MM_AUDIO_CODEC_AMR:
+ result = _mmstreamrecorder_get_amrnb_bitrate_mode(a_bitrate);
+ _mmstreamrec_dbg_log("Set AMR encoder mode [%d]", result);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC].gst, "band-mode", result);
+ break;
+ case MM_AUDIO_CODEC_AAC:
+ _mmstreamrec_dbg_log("Set AAC encoder bitrate [%d]", a_bitrate);
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC].gst, "bitrate", a_bitrate);
+ break;
+ default:
+ _mmstreamrec_dbg_log("Audio codec is not AMR or AAC... you need to implement setting function for audio encoder bit-rate");
+ break;
+ }
+ } else {
+ _mmstreamrec_dbg_warn("Setting bitrate is too small, so skip setting. Use DEFAULT value.");
+ }
+ }
+
+ _mmstreamrec_dbg_log("Element creation complete");
+
+ /* Add element to bin */
+ if (!_mmstreamrecorder_add_elements_to_bin(GST_BIN(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst), element_list)) {
+ _mmstreamrec_dbg_err("element add error.");
+ err = MM_ERROR_STREAMRECORDER_RESOURCE_CREATION;
+ goto pipeline_creation_error;
+ }
+
+ _mmstreamrec_dbg_log("Element add complete");
+
+ if (profile == MM_STREAMRECORDER_ENCBIN_PROFILE_VIDEO) {
+ pad = gst_element_get_request_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "video");
+ if (gst_element_add_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst, gst_ghost_pad_new("video_sink0", pad)) < 0) {
+ gst_object_unref(pad);
+ pad = NULL;
+ _mmstreamrec_dbg_err("failed to create ghost video_sink0 on _MMSTREAMRECORDER_ENCSINK_BIN.");
+ err = MM_ERROR_STREAMRECORDER_GST_LINK;
+ goto pipeline_creation_error;
+ }
+ gst_object_unref(pad);
+ pad = NULL;
+
+ if (sc->audio_enable == TRUE) {
+ pad = gst_element_get_request_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "audio");
+ if (gst_element_add_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst, gst_ghost_pad_new("audio_sink0", pad)) < 0) {
+ gst_object_unref(pad);
+ pad = NULL;
+ _mmstreamrec_dbg_err("failed to create ghost audio_sink0 on _MMSTREAMRECORDER_ENCSINK_BIN.");
+ err = MM_ERROR_STREAMRECORDER_GST_LINK;
+ goto pipeline_creation_error;
+ }
+ gst_object_unref(pad);
+ pad = NULL;
+ }
+ } else if (profile == MM_STREAMRECORDER_ENCBIN_PROFILE_AUDIO) {
+ pad = gst_element_get_request_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "audio");
+ if (gst_element_add_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst, gst_ghost_pad_new("audio_sink0", pad)) < 0) {
+ gst_object_unref(pad);
+ pad = NULL;
+ _mmstreamrec_dbg_err("failed to create ghost audio_sink0 on _MMSTREAMRECORDER_ENCSINK_BIN.");
+ err = MM_ERROR_STREAMRECORDER_GST_LINK;
+ goto pipeline_creation_error;
+ }
+ gst_object_unref(pad);
+ pad = NULL;
+ } else {
+ /* for stillshot */
+ pad = gst_element_get_request_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "image");
+ if (gst_element_add_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst, gst_ghost_pad_new("image_sink0", pad)) < 0) {
+ gst_object_unref(pad);
+ pad = NULL;
+ _mmstreamrec_dbg_err("failed to create ghost image_sink0 on _MMSTREAMRECORDER_ENCSINK_BIN.");
+ err = MM_ERROR_STREAMRECORDER_GST_LINK;
+ goto pipeline_creation_error;
+ }
+ gst_object_unref(pad);
+ pad = NULL;
+ }
+
+ _mmstreamrec_dbg_log("Get pad complete");
+
+ /* Link internal element */
+ if (!_mmstreamrecorder_link_elements(element_list)) {
+ _mmstreamrec_dbg_err("element link error.");
+ err = MM_ERROR_STREAMRECORDER_GST_LINK;
+ goto pipeline_creation_error;
+ }
+
+ if (element_list) {
+ g_list_free(element_list);
+ element_list = NULL;
+ }
+
+ _mmstreamrec_dbg_log("done");
+
+ return MM_ERROR_NONE;
+
+ pipeline_creation_error:
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_ENCBIN);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_SRC);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_FILT);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_VENC);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_AENC);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_IENC);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_MUX);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_SINK);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_BIN);
+
+ if (element_list) {
+ g_list_free(element_list);
+ element_list = NULL;
+ }
+
+ return err;
+}
+
+int _mmstreamrecorder_destroy_encodesink_bin(MMHandleType handle)
+{
+ GstPad *reqpad = NULL;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ _mmstreamrec_dbg_log("");
+
+ if (sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst != NULL) {
+ /* release request pad */
+ reqpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "audio");
+ if (reqpad) {
+ gst_element_release_request_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, reqpad);
+ gst_object_unref(reqpad);
+ reqpad = NULL;
+ }
+
+ reqpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "video");
+ if (reqpad) {
+ gst_element_release_request_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, reqpad);
+ gst_object_unref(reqpad);
+ reqpad = NULL;
+ }
+
+ /* release encode main pipeline */
+ gst_object_unref(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst);
+
+ _mmstreamrec_dbg_log("Encoder pipeline removed");
+ }
+
+ return MM_ERROR_NONE;
+}
+
+int _mmstreamrecorder_create_audiosrc_bin(MMHandleType handle)
+{
+ int err = MM_ERROR_NONE;
+ int val = 0;
+ int rate = 0;
+ int format = 0;
+ int channel = 0;
+ unsigned int a_enc = MM_AUDIO_CODEC_INVALID;
+ unsigned int file_format = MM_FILE_FORMAT_INVALID;
+ char *err_name = NULL;
+ int rec_mode = 0;
+
+ GstCaps *caps = NULL;
+ GstPad *pad = NULL;
+ GList *element_list = NULL;
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderGstElement *last_element = NULL;
+ /* type_element *AudiosrcElement = NULL; */
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ _mmstreamrec_dbg_log("");
+
+ err = mm_streamrecorder_get_attributes(handle, &err_name, MMSTR_AUDIO_ENCODER, &a_enc, MMSTR_AUDIO_BITRATE, &val, MMSTR_AUDIO_SAMPLERATE, &rate, MMSTR_AUDIO_SOURCE_FORMAT, &format, MMSTR_AUDIO_CHANNEL, &channel, MMSTR_FILE_FORMAT, &file_format, MMSTR_RECORDER_MODE, &rec_mode, NULL);
+
+ if (err != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_warn("Get attrs fail. (%s:%x)", err_name, err);
+ SAFE_FREE(err_name);
+ return err;
+ }
+
+ err = _mmstreamrecorder_check_audiocodec_fileformat_compatibility(a_enc, file_format);
+ if (err != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_err("error name :%s , audio format %d , fileformat %d. error : %x)", err_name, a_enc, file_format, err);
+ SAFE_FREE(err_name);
+ return err;
+ }
+
+ /* Check existence */
+ if (sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst) {
+ if (((GObject *) sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst)->ref_count > 0)
+ gst_object_unref(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst);
+
+ _mmstreamrec_dbg_log("_MMSTREAMRECORDER_AUDIOSRC_BIN is Already existed. Unref once...");
+ }
+
+ /* Create bin element */
+ _MMSTREAMRECORDER_BIN_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_AUDIOSRC_BIN, "audiosource_bin", err);
+
+ _MMSTREAMRECORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_AUDIOSRC_SRC, "appsrc", hstreamrecorder->ini.name_of_audio_src, element_list, err);
+
+ _MMSTREAMRECORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_AUDIOSRC_FILT, "capsfilter", "audiosrc_capsfilter", element_list, err);
+
+ /* Set basic infomation */
+ if (a_enc != MM_AUDIO_CODEC_VORBIS) {
+ int depth = 0;
+
+ if (format == MM_STREAMRECORDER_AUDIO_FORMAT_PCM_S16_LE) {
+ depth = 16;
+ } else { /* MM_STREAMRECORDER_AUDIO_FORMAT_PCM_U8 */
+ depth = 8;
+ }
+
+ caps = gst_set_audiosrcpad_caps(rate, channel, depth, 16, 1);
+
+ _mmstreamrec_dbg_log("caps [x-raw-int, rate:%d, channel:%d, depth:%d]", rate, channel, depth);
+ } else {
+ /* what are the audio encoder which should get audio/x-raw-float? */
+ caps = gst_caps_new_simple("audio/x-raw-float", "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channel, "endianness", G_TYPE_INT, BYTE_ORDER, "width", G_TYPE_INT, 32, NULL);
+ _mmstreamrec_dbg_log("caps [x-raw-float, rate:%d, channel:%d, endianness:%d, width:32]", rate, channel, BYTE_ORDER);
+ }
+
+ if (caps) {
+ if (rec_mode == MM_STREAMRECORDER_MODE_MEDIABUFFER) {
+ MMSTREAMRECORDER_G_OBJECT_SET((sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst), "caps", caps);
+ }
+ MMSTREAMRECORDER_G_OBJECT_SET((sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_FILT].gst), "caps", caps);
+ {
+ gchar *type = gst_caps_to_string(caps);
+
+ _mmstreamrec_dbg_err("_MMSTREAMRECORDER_AUDIOSRC_FILT %s", type);
+
+ }
+ gst_caps_unref(caps);
+ caps = NULL;
+ } else {
+ _mmstreamrec_dbg_err("create caps error");
+ err = MM_ERROR_STREAMRECORDER_RESOURCE_CREATION;
+ goto pipeline_creation_error;
+ }
+
+ if (rec_mode == MM_STREAMRECORDER_MODE_SCREENRECORD) {
+#if 1 /* mic mode */
+ MMSTREAMRECORDER_G_OBJECT_SET((sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst), "do-timestamp", TRUE);
+#else /* speaker mode with alsasrc */
+ MMSTREAMRECORDER_G_OBJECT_SET((sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst), "device", "hw:0,8");
+ MMSTREAMRECORDER_G_OBJECT_SET((sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst), "latency-time", 256000);
+ MMSTREAMRECORDER_G_OBJECT_SET((sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst), "buffer-time", 10000);
+ MMSTREAMRECORDER_G_OBJECT_SET((sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst), "do-timestamp", FALSE);
+#endif
+ } else {
+ MMSTREAMRECORDER_G_OBJECT_SET((sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst), "do-timestamp", FALSE);
+ }
+
+ if (!_mmstreamrecorder_add_elements_to_bin(GST_BIN(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst), element_list)) {
+ _mmstreamrec_dbg_err("element add error.");
+ err = MM_ERROR_STREAMRECORDER_RESOURCE_CREATION;
+ goto pipeline_creation_error;
+ }
+
+ if (!_mmstreamrecorder_link_elements(element_list)) {
+ _mmstreamrec_dbg_err("element link error.");
+ err = MM_ERROR_STREAMRECORDER_GST_LINK;
+ goto pipeline_creation_error;
+ }
+
+ last_element = (_MMStreamRecorderGstElement *) (g_list_last(element_list)->data);
+ pad = gst_element_get_static_pad(last_element->gst, "src");
+ if ((gst_element_add_pad(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst, gst_ghost_pad_new("src", pad))) < 0) {
+ gst_object_unref(pad);
+ pad = NULL;
+ _mmstreamrec_dbg_err("failed to create ghost pad on _MMSTREAMRECORDER_AUDIOSRC_BIN.");
+ err = MM_ERROR_STREAMRECORDER_GST_LINK;
+ goto pipeline_creation_error;
+ }
+
+ gst_object_unref(pad);
+ pad = NULL;
+
+ if (element_list) {
+ g_list_free(element_list);
+ element_list = NULL;
+ }
+
+ return MM_ERROR_NONE;
+
+ pipeline_creation_error:
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_AUDIOSRC_SRC);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_AUDIOSRC_FILT);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_AUDIOSRC_BIN);
+
+ if (element_list) {
+ g_list_free(element_list);
+ element_list = NULL;
+ }
+
+ return err;
+}
+
+int _mmstreamrecorder_destroy_audiosrc_bin(MMHandleType handle)
+{
+ GstPad *srcpad = NULL;
+ GstPad *sinkpad = NULL;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ _mmstreamrec_dbg_log("");
+
+ if (sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst != NULL) {
+ srcpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst, "src");
+ sinkpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst, "audio_sink0");
+ _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad);
+
+ /* release audiosrc bin */
+ gst_bin_remove(GST_BIN(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst), sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst);
+
+ _mmstreamrecorder_remove_element_handle(handle, (void *)sc->encode_element, _MMSTREAMRECORDER_AUDIOSRC_BIN, _MMSTREAMRECORDER_AUDIOSRC_FILT);
+
+ _mmstreamrec_dbg_log("Audio pipeline removed");
+ }
+
+ return MM_ERROR_NONE;
+}
+
+/* COMMAND - VIDEO */
+int _mmstreamrecorder_video_command(MMHandleType handle, int command)
+{
+ int ret = MM_ERROR_NONE;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderVideoInfo *info = NULL;
+ _MMStreamRecorderAudioInfo *info_audio = NULL;
+ _MMStreamRecorderFileInfo *finfo = NULL;
+ _MMStreamRecorderSubContext *sc = NULL;
+ GstElement *pipeline = NULL;
+ GstPad *pad = NULL;
+ guint count = 0;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc && sc->encode_element, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ mmf_return_val_if_fail(sc->info_video, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ if (sc->audio_enable == TRUE) {
+ mmf_return_val_if_fail(sc->info_audio, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ }
+ mmf_return_val_if_fail(sc->info_file, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ info = sc->info_video;
+ if (sc->audio_enable == TRUE)
+ info_audio = sc->info_audio;
+
+ finfo = sc->info_file;
+
+ _mmstreamrec_dbg_log("command %d", command);
+
+ pipeline = sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst;
+
+ switch (command) {
+ case _MM_STREAMRECORDER_CMD_RECORD:
+ {
+
+ /* Recording */
+ _mmstreamrec_dbg_log("Record Start");
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
+
+ /* Adjust display FPS */
+ info->video_frame_count = 0;
+ if (info_audio)
+ info_audio->audio_frame_count = 0;
+
+ info->filesize = 0;
+ sc->ferror_send = FALSE;
+ sc->ferror_count = 0;
+ sc->error_occurs = FALSE;
+ sc->bget_eos = FALSE;
+
+ ret = _mmstreamrecorder_gst_set_state(handle, sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_PLAYING);
+ if (ret != MM_ERROR_NONE) {
+ /* Remove recorder pipeline and recording file which size maybe zero */
+ ret = _mmstreamrecorder_destroy_recorder_pipeline(handle);
+
+ if (finfo->filename) {
+ _mmstreamrec_dbg_log("file delete(%s)", finfo->filename);
+ unlink(finfo->filename);
+ g_free(finfo->filename);
+ finfo->filename = NULL;
+ }
+ goto _ERR_STREAMRECORDER_VIDEO_COMMAND;
+ }
+
+ }
+ break;
+ case _MM_STREAMRECORDER_CMD_PAUSE:
+ {
+
+ if (info->b_commiting) {
+ _mmstreamrec_dbg_warn("now on commiting previous file!!(command : %d)", command);
+ return MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING;
+ }
+
+ for (count = 0; count <= hstreamrecorder->ini.retrial_count; count++) {
+ if (sc->audio_enable == FALSE) {
+ /* check only video frame */
+ if (info->video_frame_count >= hstreamrecorder->ini.minimum_frame) {
+ break;
+ } else if (count == hstreamrecorder->ini.retrial_count) {
+ _mmstreamrec_dbg_err("Pause fail, frame count %" G_GUINT64_FORMAT "", info->video_frame_count);
+ return MM_ERROR_STREAMRECORDER_INVALID_CONDITION;
+ } else {
+ _mmstreamrec_dbg_warn("Waiting for enough video frame, retrial[%d], frame %" G_GUINT64_FORMAT "", count, info->video_frame_count);
+ }
+
+ usleep(hstreamrecorder->ini.video_frame_wait_time);
+ } else {
+ /* check both of video and audio frame */
+ if (info->video_frame_count >= hstreamrecorder->ini.minimum_frame && info_audio->audio_frame_count) {
+ break;
+ } else if (count == hstreamrecorder->ini.retrial_count) {
+ _mmstreamrec_dbg_err("Pause fail, frame count VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]", info->video_frame_count, info_audio->audio_frame_count);
+ return MM_ERROR_STREAMRECORDER_INVALID_CONDITION;
+ } else {
+ _mmstreamrec_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]", count, info->video_frame_count, info_audio->audio_frame_count);
+ }
+
+ usleep(hstreamrecorder->ini.video_frame_wait_time);
+ }
+ }
+ /* tee block */
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE);
+
+ break;
+ }
+ break;
+ case _MM_STREAMRECORDER_CMD_CANCEL:
+ {
+ if (info->b_commiting) {
+ _mmstreamrec_dbg_warn("now on commiting previous file!!(command : %d)", command);
+ return MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING;
+ }
+
+ ret = _mmstreamrecorder_destroy_recorder_pipeline(handle);
+ if (ret != MM_ERROR_NONE)
+ goto _ERR_STREAMRECORDER_VIDEO_COMMAND;
+
+ /* remove target file */
+ if (finfo->filename) {
+ _mmstreamrec_dbg_log("file delete(%s)", finfo->filename);
+ unlink(finfo->filename);
+ g_free(finfo->filename);
+ finfo->filename = NULL;
+ }
+
+ sc->isMaxsizePausing = FALSE;
+ sc->isMaxtimePausing = FALSE;
+
+ info->video_frame_count = 0;
+ if (info_audio)
+ info_audio->audio_frame_count = 0;
+
+ info->filesize = 0;
+ break;
+ }
+ break;
+ case _MM_STREAMRECORDER_CMD_COMMIT:
+ /* video recording command */
+ {
+
+ if (info->b_commiting) {
+ _mmstreamrec_dbg_err("now on commiting previous file!!(command : %d)", command);
+ return MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING;
+ } else {
+ _mmstreamrec_dbg_log("_MM_STREAMRECORDER_CMD_COMMIT : start");
+ info->b_commiting = TRUE;
+ }
+
+ for (count = 0; count <= hstreamrecorder->ini.retrial_count; count++) {
+ if (sc->audio_enable == FALSE) {
+ /* check only video frame */
+ if (info->video_frame_count >= hstreamrecorder->ini.minimum_frame) {
+ break;
+ } else if (count == hstreamrecorder->ini.retrial_count) {
+ _mmstreamrec_dbg_err("Commit fail, frame count is %" G_GUINT64_FORMAT "", info->video_frame_count);
+ info->b_commiting = FALSE;
+ return MM_ERROR_STREAMRECORDER_INVALID_CONDITION;
+ } else {
+ _mmstreamrec_dbg_warn("Waiting for enough video frame, retrial [%d], frame %" G_GUINT64_FORMAT "", count, info->video_frame_count);
+ }
+
+ usleep(hstreamrecorder->ini.video_frame_wait_time);
+ } else {
+ /* check both of video and audio frame */
+ if (info->video_frame_count >= hstreamrecorder->ini.minimum_frame && info_audio->audio_frame_count) {
+ break;
+ } else if (count == hstreamrecorder->ini.retrial_count) {
+ _mmstreamrec_dbg_err("Commit fail, VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]", info->video_frame_count, info_audio->audio_frame_count);
+
+ info->b_commiting = FALSE;
+ return MM_ERROR_STREAMRECORDER_INVALID_CONDITION;
+ } else {
+ _mmstreamrec_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]", count, info->video_frame_count, info_audio->audio_frame_count);
+ }
+
+ usleep(hstreamrecorder->ini.video_frame_wait_time);
+ }
+ }
+
+ if (sc->error_occurs) {
+ GstPad *video = NULL;
+ GstPad *audio = NULL;
+
+ _mmstreamrec_dbg_err("Committing Error case");
+#if 0
+ video = gst_element_get_static_pad(sc->element[_MMSTREAMRECORDER_VIDEOSINK_SINK].gst, "sink");
+ ret = gst_pad_send_event(video, gst_event_new_eos());
+ _mmstreamrec_dbg_err("Sending EOS video sink : %d", ret);
+ gst_object_unref(video);
+#endif
+ video = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_VENC].gst, "src");
+ gst_pad_push_event(video, gst_event_new_flush_start());
+ gst_pad_push_event(video, gst_event_new_flush_stop(TRUE));
+ ret = gst_pad_push_event(video, gst_event_new_eos());
+ _mmstreamrec_dbg_err("Sending EOS video encoder src pad : %d", ret);
+ gst_object_unref(video);
+
+ if (sc->audio_enable == TRUE) {
+ audio = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC].gst, "src");
+ gst_pad_push_event(audio, gst_event_new_flush_start());
+ gst_pad_push_event(audio, gst_event_new_flush_stop(TRUE));
+ ret = gst_element_send_event(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst, gst_event_new_eos());
+ _mmstreamrec_dbg_err("Sending EOS audio encoder src pad : %d", ret);
+ gst_object_unref(audio);
+ }
+ } else {
+ if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SRC].gst != NULL) {
+ ret = gst_element_send_event(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SRC].gst, gst_event_new_eos());
+ _mmstreamrec_dbg_warn("send eos to appsrc result : %d", ret);
+ }
+
+ if (sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst != NULL) {
+ pad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst, "src");
+ ret = gst_element_send_event(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst, gst_event_new_eos());
+ gst_object_unref(pad);
+ pad = NULL;
+
+ _mmstreamrec_dbg_warn("send eos to audiosrc result : %d", ret);
+ }
+ }
+
+ /* Wait EOS */
+ _mmstreamrec_dbg_log("Start to wait EOS");
+ ret = _mmstreamrecorder_get_eos_message(handle);
+ if (ret != MM_ERROR_NONE) {
+ info->b_commiting = FALSE;
+ goto _ERR_STREAMRECORDER_VIDEO_COMMAND;
+ }
+ }
+ break;
+ default:
+ ret = MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT;
+ break;
+ }
+ return MM_ERROR_NONE;
+
+ _ERR_STREAMRECORDER_VIDEO_COMMAND:
+ if (ret != MM_ERROR_NONE)
+ _mmstreamrec_dbg_err("Current Videosrc status");
+
+ return ret;
+}
+
+int _mmstreamrecorder_video_handle_eos(MMHandleType handle)
+{
+ int ret = MM_ERROR_NONE;
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderVideoInfo *info = NULL;
+ _MMStreamRecorderAudioInfo *info_audio = NULL;
+ _MMStreamRecorderFileInfo *finfo = NULL;
+ _MMStreamRecorderMsgItem msg;
+ MMStreamRecordingReport *report = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, FALSE);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, FALSE);
+ mmf_return_val_if_fail(sc->info_video, FALSE);
+ if (sc->audio_enable == TRUE)
+ mmf_return_val_if_fail(sc->info_audio, FALSE);
+
+ mmf_return_val_if_fail(sc->info_file, FALSE);
+
+ info = sc->info_video;
+ if (sc->audio_enable == TRUE)
+ info_audio = sc->info_audio;
+
+ finfo = sc->info_file;
+
+ _mmstreamrec_dbg_err("");
+
+ /* remove blocking part */
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
+
+ ret = _mmstreamrecorder_destroy_recorder_pipeline(handle);
+ if (ret != MM_ERROR_NONE)
+ _mmstreamrec_dbg_warn("_mmstreamrecorder_destroy_recorder_pipeline failed. error[%x]", ret);
+
+ /* Send recording report to application */
+ msg.id = MM_MESSAGE_STREAMRECORDER_VIDEO_CAPTURED;
+ report = (MMStreamRecordingReport *) malloc(sizeof(MMStreamRecordingReport));
+ if (!report) {
+ _mmstreamrec_dbg_err("Recording report fail(%s). Out of memory.", finfo->filename);
+ } else {
+ report->recording_filename = strdup(finfo->filename);
+ msg.param.data = report;
+ msg.param.code = 1;
+ _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg);
+ }
+
+ /* Finishing */
+ sc->pipeline_time = 0;
+ sc->pause_time = 0;
+ sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */
+ sc->isMaxtimePausing = FALSE;
+ sc->error_occurs = FALSE;
+
+ info->video_frame_count = 0;
+ if (info_audio)
+ info_audio->audio_frame_count = 0;
+
+ info->filesize = 0;
+ g_free(finfo->filename);
+ finfo->filename = NULL;
+ info->b_commiting = FALSE;
+
+ _mmstreamrec_dbg_err("_mmstreamrecorder_video_handle_eos : end");
+
+ return TRUE;
+}
+
+/* AUDIO */
+
+int _mmstreamrecorder_create_audio_pipeline(MMHandleType handle)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ return _mmstreamrecorder_create_audiop_with_encodebin(handle);
+}
+
+/**
+ * This function destroy audio pipeline.
+ *
+ * @param[in] handle Handle of streamrecorder.
+ * @return void
+ * @remarks
+ * @see _mmstreamrecorder_destroy_audio_pipeline()
+ *
+ */
+void _mmstreamrecorder_destroy_audio_pipeline(MMHandleType handle)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderAudioInfo *info = NULL;
+ mmf_return_if_fail(hstreamrecorder);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+
+ mmf_return_if_fail(sc && sc->info_audio);
+
+ info = sc->info_audio;
+
+ _mmstreamrec_dbg_log("start");
+
+ if (sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst) {
+ _mmstreamrec_dbg_warn("release audio pipeline");
+
+ _mmstreamrecorder_gst_set_state(handle, sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst, GST_STATE_NULL);
+
+ _mmstreamrecorder_remove_all_handlers((MMHandleType) hstreamrecorder, _MMSTREAMRECORDER_HANDLER_CATEGORY_ALL);
+
+ if (info->bMuxing) {
+ GstPad *reqpad = NULL;
+ /* FIXME:
+ Release request pad
+ The ref_count of mux is always # of streams in here, i don't know why it happens.
+ So, i unref the mux manually
+ */
+ reqpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "audio");
+ gst_element_release_request_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, reqpad);
+ gst_object_unref(reqpad);
+
+ if (GST_IS_ELEMENT(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst) && GST_OBJECT_REFCOUNT(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst) > 1) {
+ gst_object_unref(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst);
+ }
+ }
+ gst_object_unref(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst);
+ }
+
+ _mmstreamrec_dbg_log("done");
+
+ return;
+}
+
+int _mmstreamrecorder_create_audiop_with_encodebin(MMHandleType handle)
+{
+ int err = MM_ERROR_NONE;
+ char *aenc_name = NULL;
+ char *mux_name = NULL;
+ char *err_name = NULL;
+ int rec_mode = 0;
+
+ GstBus *bus = NULL;
+ GstPad *srcpad = NULL;
+ GstPad *sinkpad = NULL;
+ GList *element_list = NULL;
+
+ _MMStreamRecorderAudioInfo *info = NULL;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ /* type_element *aenc_elem = NULL; */
+ /* type_element *mux_elem = NULL; */
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ mmf_return_val_if_fail(sc->info_audio, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ info = (_MMStreamRecorderAudioInfo *) sc->info_audio;
+
+ _mmstreamrec_dbg_log("");
+
+ err = mm_streamrecorder_get_attributes(handle, &err_name, MMSTR_RECORDER_MODE, &rec_mode, NULL);
+
+ if (!mux_name || !strcmp(mux_name, "wavenc")) {
+ /* IF MUX in not chosen then record in raw file */
+ _mmstreamrec_dbg_log("Record without muxing.");
+ info->bMuxing = FALSE;
+ } else {
+ _mmstreamrec_dbg_log("Record with mux.");
+ info->bMuxing = TRUE;
+ }
+
+ /* Create GStreamer pipeline */
+ _MMSTREAMRECORDER_PIPELINE_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_ENCODE_MAIN_PIPE, "recorder_pipeline", err);
+
+ err = _mmstreamrecorder_create_audiosrc_bin(handle);
+ if (err != MM_ERROR_NONE)
+ return err;
+
+ if (info->bMuxing) {
+ /* Muxing. can use encodebin. */
+ err = _mmstreamrecorder_create_encodesink_bin((MMHandleType) hstreamrecorder, MM_STREAMRECORDER_ENCBIN_PROFILE_AUDIO);
+ if (err != MM_ERROR_NONE)
+ return err;
+
+ } else {
+ /* without muxing. can't use encodebin. */
+
+ _MMSTREAMRECORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_ENCSINK_AQUE, "queue", NULL, element_list, err);
+
+ if (rec_mode == MM_STREAMRECORDER_MODE_MEDIABUFFER) {
+ if (strcmp(hstreamrecorder->ini.name_of_encsink_bin_audio_encoder, "wavenc") != 0) {
+ _MMSTREAMRECORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_ENCSINK_CONV, "audioconvert", NULL, element_list, err);
+ }
+ }
+
+ _MMSTREAMRECORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_ENCSINK_AENC, aenc_name, NULL, element_list, err);
+
+ _MMSTREAMRECORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMSTREAMRECORDER_ENCSINK_SINK, hstreamrecorder->ini.name_of_encsink_sink, NULL, element_list, err);
+ }
+
+ /* Add and link elements */
+ if (info->bMuxing) {
+ /* IF MUX is indicated create MUX */
+ gst_bin_add_many(GST_BIN(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst), sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst, NULL);
+
+ srcpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst, "src");
+ sinkpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_BIN].gst, "audio_sink0");
+ _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
+ } else {
+ /* IF MUX in not chosen then record in raw amr file */
+ if (!strcmp(aenc_name, "wavenc")) {
+ gst_bin_add_many(GST_BIN(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst), sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SINK].gst, NULL);
+
+ if (!_MM_GST_ELEMENT_LINK_MANY(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SINK].gst, NULL)) {
+ err = MM_ERROR_STREAMRECORDER_GST_LINK;
+ goto pipeline_creation_error;
+ }
+ } else {
+ if (rec_mode == MM_STREAMRECORDER_MODE_MEDIABUFFER) {
+ gst_bin_add_many(GST_BIN(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst), sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_CONV].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SINK].gst, NULL);
+
+ if (!_MM_GST_ELEMENT_LINK_MANY(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_CONV].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SINK].gst, NULL)) {
+ err = MM_ERROR_STREAMRECORDER_GST_LINK;
+ goto pipeline_creation_error;
+ }
+ } else {
+ gst_bin_add_many(GST_BIN(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst), sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SINK].gst, NULL);
+
+ if (!_MM_GST_ELEMENT_LINK_MANY(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_BIN].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC].gst, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SINK].gst, NULL)) {
+ err = MM_ERROR_STREAMRECORDER_GST_LINK;
+ goto pipeline_creation_error;
+ }
+ }
+ }
+ }
+
+ if (info->bMuxing) {
+ MMSTREAMRECORDER_SIGNAL_CONNECT(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_MUX].gst, _MMSTREAMRECORDER_HANDLER_AUDIOREC, "pad-added", __mmstreamrecorder_audiorec_pad_added_cb, hstreamrecorder);
+ } else {
+ srcpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AENC].gst, "src");
+ MMSTREAMRECORDER_ADD_BUFFER_PROBE(srcpad, _MMSTREAMRECORDER_HANDLER_AUDIOREC, __mmstreamrecorder_audio_dataprobe_record, hstreamrecorder);
+ gst_object_unref(srcpad);
+ srcpad = NULL;
+ }
+
+ bus = gst_pipeline_get_bus(GST_PIPELINE(sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst));
+
+ /* register message callback */
+ hstreamrecorder->pipeline_cb_event_id = gst_bus_add_watch(bus, (GstBusFunc) _mmstreamrecorder_pipeline_cb_message, hstreamrecorder);
+
+ /* set sync callback */
+ gst_bus_set_sync_handler(bus, gst_bus_sync_signal_handler, hstreamrecorder, NULL);
+
+ gst_object_unref(bus);
+ bus = NULL;
+
+ if (element_list) {
+ g_list_free(element_list);
+ element_list = NULL;
+ }
+
+ return MM_ERROR_NONE;
+
+ pipeline_creation_error:
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCODE_MAIN_PIPE);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_AUDIOSRC_BIN);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_AQUE);
+ if (rec_mode == MM_STREAMRECORDER_MODE_MEDIABUFFER) {
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_CONV);
+ }
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_AENC);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_SINK);
+ _MMSTREAMRECORDER_ELEMENT_REMOVE(sc->encode_element, _MMSTREAMRECORDER_ENCSINK_BIN);
+
+ if (element_list) {
+ g_list_free(element_list);
+ element_list = NULL;
+ }
+
+ return err;
+}
+
+int _mmstreamrecorder_audio_command(MMHandleType handle, int command)
+{
+ int cmd = command;
+ int ret = MM_ERROR_NONE;
+ int err = 0;
+ guint64 free_space = 0;
+ guint64 cal_space = 0;
+ char *dir_name = NULL;
+ char *err_attr_name = NULL;
+ guint count = 0;
+ int size = 0;
+
+ GstElement *pipeline = NULL;
+ GstElement *audioSrc = NULL;
+
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderAudioInfo *info = NULL;
+ _MMStreamRecorderFileInfo *finfo = NULL;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ mmf_return_val_if_fail(sc->info_audio, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ mmf_return_val_if_fail(sc->info_file, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+ pipeline = sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst;
+ info = sc->info_audio;
+ finfo = sc->info_file;
+
+ _mmstreamrec_dbg_log("");
+
+ pipeline = sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst;
+ audioSrc = sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst;
+ switch (cmd) {
+ case _MM_STREAMRECORDER_CMD_RECORD:
+ /* check status for resume case */
+ {
+ guint imax_size = 0;
+ guint imax_time = 0;
+ char *temp_filename = NULL;
+
+ if (sc->pipeline_time)
+ gst_element_set_start_time((GstElement *) GST_PIPELINE(pipeline), sc->pipeline_time);
+
+ sc->pipeline_time = hstreamrecorder->ini.reset_pause_time;
+
+ ret = mm_streamrecorder_get_attributes(handle, &err_attr_name, MMSTR_TARGET_MAX_SIZE, &imax_size, MMSTR_TARGET_TIME_LIMIT, &imax_time, MMSTR_FILE_FORMAT, &(finfo->fileformat), MMSTR_FILENAME, &temp_filename, &size, NULL);
+ if (ret != MM_ERROR_NONE) {
+ _mmstreamrec_dbg_warn("failed to get attribute. (%s:%x)", err_attr_name, ret);
+ SAFE_FREE(err_attr_name);
+ goto _ERR_STREAMRECORDER_AUDIO_COMMAND;
+ }
+
+ finfo->filename = strdup(temp_filename);
+ if (!finfo->filename) {
+ _mmstreamrec_dbg_err("STRDUP was failed");
+ goto _ERR_STREAMRECORDER_AUDIO_COMMAND;
+ }
+
+ _mmstreamrec_dbg_log("Record start : set file name using attribute - %s\n ", finfo->filename);
+
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SINK].gst, "location", finfo->filename);
+
+ sc->ferror_send = FALSE;
+ sc->ferror_count = 0;
+ sc->bget_eos = FALSE;
+ info->filesize = 0;
+
+ /* set max size */
+ if (imax_size <= 0)
+ info->max_size = 0; /* do not check */
+ else
+ info->max_size = ((guint64) imax_size) << 10; /* to byte */
+
+ /* set max time */
+ if (imax_time <= 0)
+ info->max_time = 0; /* do not check */
+ else
+ info->max_time = ((guint64) imax_time) * 1000; /* to millisecond */
+
+ /* TODO : check free space before recording start, need to more discussion */
+ dir_name = g_path_get_dirname(finfo->filename);
+ err = _mmstreamrecorder_get_freespace(dir_name, &free_space);
+
+ _mmstreamrec_dbg_warn("current space for recording - %s : [%" G_GUINT64_FORMAT "]", dir_name, free_space);
+
+ if (dir_name) {
+ g_free(dir_name);
+ dir_name = NULL;
+ }
+ cal_space = (guint64)(hstreamrecorder->ini.audio_frame_minimum_space);
+ cal_space = cal_space + (5 * 1024);
+ if ((err == -1) || free_space <= cal_space) {
+ _mmstreamrec_dbg_err("No more space for recording");
+ return MM_MESSAGE_STREAMRECORDER_NO_FREE_SPACE;
+ }
+ }
+
+ ret = _mmstreamrecorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
+ if (ret != MM_ERROR_NONE)
+ goto _ERR_STREAMRECORDER_AUDIO_COMMAND;
+
+ break;
+
+ case _MM_STREAMRECORDER_CMD_PAUSE:
+ {
+ GstClock *l_clock = NULL;
+
+ if (info->b_commiting) {
+ _mmstreamrec_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd);
+ return MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING;
+ }
+
+ for (count = 0; count <= hstreamrecorder->ini.retrial_count; count++) {
+ if (info->filesize > 0) {
+ break;
+ } else if (count == hstreamrecorder->ini.retrial_count) {
+ _mmstreamrec_dbg_err("Pause fail, wait 200 ms, but file size is %lld", info->filesize);
+ return MM_ERROR_STREAMRECORDER_INVALID_CONDITION;
+ } else {
+ _mmstreamrec_dbg_warn("Wait for enough audio frame, retry count[%d], file size is %lld", count, info->filesize);
+ }
+ usleep(hstreamrecorder->ini.audio_frame_wait_time);
+ }
+
+ ret = _mmstreamrecorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED);
+ if (ret != MM_ERROR_NONE)
+ goto _ERR_STREAMRECORDER_AUDIO_COMMAND;
+
+ /* FIXME: consider delay. */
+ l_clock = gst_pipeline_get_clock(GST_PIPELINE(pipeline));
+ sc->pipeline_time = gst_clock_get_time(l_clock) - gst_element_get_base_time(GST_ELEMENT(pipeline));
+ break;
+ }
+
+ case _MM_STREAMRECORDER_CMD_CANCEL:
+ if (info->b_commiting) {
+ _mmstreamrec_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd);
+ return MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING;
+ }
+
+ ret = _mmstreamrecorder_gst_set_state(handle, pipeline, GST_STATE_READY);
+ if (ret != MM_ERROR_NONE)
+ goto _ERR_STREAMRECORDER_AUDIO_COMMAND;
+
+ if (info->bMuxing) {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
+ } else {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, "empty-buffers", FALSE);
+ }
+
+ _mmstreamrecorder_gst_set_state(handle, sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SINK].gst, GST_STATE_NULL);
+
+ sc->pipeline_time = 0;
+ sc->pause_time = 0;
+ sc->isMaxsizePausing = FALSE;
+ sc->isMaxtimePausing = FALSE;
+
+ if (finfo->filename) {
+ _mmstreamrec_dbg_log("file delete(%s)", finfo->filename);
+ unlink(finfo->filename);
+ g_free(finfo->filename);
+ finfo->filename = NULL;
+ }
+ break;
+
+ case _MM_STREAMRECORDER_CMD_COMMIT:
+ {
+
+ _mmstreamrec_dbg_log("_MM_STREAMRECORDER_CMD_COMMIT");
+
+ if (info->b_commiting) {
+ _mmstreamrec_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd);
+ return MM_ERROR_STREAMRECORDER_CMD_IS_RUNNING;
+ } else {
+ _mmstreamrec_dbg_log("_MM_STREAMRECORDER_CMD_COMMIT : start");
+ info->b_commiting = TRUE;
+ }
+
+ for (count = 0; count <= hstreamrecorder->ini.retrial_count; count++) {
+ if (info->filesize > 0) {
+ break;
+ } else if (count == hstreamrecorder->ini.retrial_count) {
+ _mmstreamrec_dbg_err("Commit fail, waited 200 ms, but file size is %lld", info->filesize);
+ info->b_commiting = FALSE;
+ return MM_ERROR_STREAMRECORDER_INVALID_CONDITION;
+ } else {
+ _mmstreamrec_dbg_warn("Waiting for enough audio frame, re-count[%d], file size is %lld", count, info->filesize);
+ }
+ usleep(hstreamrecorder->ini.audio_frame_wait_time);
+ }
+
+ if (audioSrc) {
+ GstPad *pad = gst_element_get_static_pad(audioSrc, "src");
+ ret = gst_element_send_event(audioSrc, gst_event_new_eos());
+ gst_object_unref(pad);
+ pad = NULL;
+ /* for pause -> commit case */
+ /*if (_mmstreamrecorder_get_state((MMHandleType)hstreamrecorder) == MM_STREAMRECORDER_STATE_PAUSED) {
+ ret = _mmstreamrecorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING);
+ if (ret != MM_ERROR_NONE) {
+ goto _ERR_STREAMRECORDER_AUDIO_COMMAND;
+ }
+ } */
+ }
+
+ /* wait until finishing EOS */
+ _mmstreamrec_dbg_log("Start to wait EOS");
+ if ((ret = _mmstreamrecorder_get_eos_message(handle)) != MM_ERROR_NONE)
+ goto _ERR_STREAMRECORDER_AUDIO_COMMAND;
+
+ break;
+ }
+ default:
+ ret = MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT;
+ break;
+ }
+
+ _ERR_STREAMRECORDER_AUDIO_COMMAND:
+ return ret;
+}
+
+int _mmstreamrecorder_audio_handle_eos(MMHandleType handle)
+{
+ int err = MM_ERROR_NONE;
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderAudioInfo *info = NULL;
+ _MMStreamRecorderFileInfo *finfo = NULL;
+ GstElement *pipeline = NULL;
+ _MMStreamRecorderMsgItem msg;
+ MMStreamRecordingReport *report;
+
+ mmf_return_val_if_fail(hstreamrecorder, FALSE);
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+
+ mmf_return_val_if_fail(sc, FALSE);
+ mmf_return_val_if_fail(sc->info_audio, FALSE);
+ mmf_return_val_if_fail(sc->info_file, FALSE);
+
+ _mmstreamrec_dbg_err("");
+
+ info = sc->info_audio;
+ finfo = sc->info_file;
+
+ pipeline = sc->encode_element[_MMSTREAMRECORDER_ENCODE_MAIN_PIPE].gst;
+
+ err = _mmstreamrecorder_gst_set_state(handle, pipeline, GST_STATE_READY);
+
+ if (err != MM_ERROR_NONE)
+ _mmstreamrec_dbg_warn("Failed:_MM_STREAMRECORDER_CMD_COMMIT:GST_STATE_READY. err[%x]", err);
+
+ /* Send recording report message to application */
+ msg.id = MM_MESSAGE_STREAMRECORDER_AUDIO_CAPTURED;
+ report = (MMStreamRecordingReport *) malloc(sizeof(MMStreamRecordingReport));
+ if (!report) {
+ _mmstreamrec_dbg_err("Recording report fail(%s). Out of memory.", finfo->filename);
+ return FALSE;
+ }
+
+ /* START TAG HERE */
+ /* MM_AUDIO_CODEC_AAC + MM_FILE_FORMAT_MP4 */
+ if (finfo->fileformat == MM_FILE_FORMAT_3GP || finfo->fileformat == MM_FILE_FORMAT_MP4)
+ _mmstreamrecorder_audio_add_metadata_info_m4a(handle);
+ /* END TAG HERE */
+
+ report->recording_filename = strdup(finfo->filename);
+ msg.param.data = report;
+
+ _mmstreamrecorder_send_message(handle, &msg);
+
+ if (info->bMuxing) {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_ENCBIN].gst, "block", FALSE);
+ } else {
+ MMSTREAMRECORDER_G_OBJECT_SET(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_AQUE].gst, "empty-buffers", FALSE);
+ }
+
+ _mmstreamrecorder_gst_set_state(handle, pipeline, GST_STATE_NULL);
+
+ sc->pipeline_time = 0;
+ sc->pause_time = 0;
+ sc->isMaxsizePausing = FALSE;
+ sc->isMaxtimePausing = FALSE;
+
+ g_free(finfo->filename);
+ finfo->filename = NULL;
+
+ _mmstreamrec_dbg_err("_MM_STREAMRECORDER_CMD_COMMIT : end");
+
+ info->b_commiting = FALSE;
+
+ return TRUE;
+}
+
+int _mmstreamrecorder_push_videostream_buffer(MMHandleType handle, unsigned long timestamp, GstBuffer *buffer, int size)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ GstPad *srcpad = NULL;
+ GstCaps *srccaps = NULL;
+ char *err_name = NULL;
+ int video_fps = 0;
+ int video_src = 0;
+ int video_width = 0;
+ int video_height = 0;
+ int ret = MM_ERROR_NONE;
+ int video_source_format = 0;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ if (buffer == NULL || size == 0) {
+ _mmstreamrec_dbg_err("video : Buffer is %p , size %d, time stamp is %ld", buffer, size, timestamp);
+ return MM_ERROR_STREAMRECORDER_RESOURCE_CREATION;
+ }
+
+ _mmstreamrec_dbg_log("video : Buffer is %p , size %d, time stamp is %ld", buffer, size, timestamp);
+
+ /* check element availability */
+ ret = mm_streamrecorder_get_attributes(handle, &err_name, MMSTR_VIDEO_FRAMERATE, &video_fps, MMSTR_VIDEO_SOURCE_FORMAT, &video_src, MMSTR_VIDEO_RESOLUTION_WIDTH, &video_width, MMSTR_VIDEO_RESOLUTION_HEIGHT, &video_height, MMSTR_VIDEO_SOURCE_FORMAT, &video_source_format, NULL);
+
+ if (sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SRC].gst) {
+
+ /*_mmstreamrec_dbg_log("Buffer Push start , time stamp %ld",timestamp);*/
+ srcpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SRC].gst, "src");
+ srccaps = gst_pad_get_current_caps(srcpad);
+ srccaps = gst_set_videosrcpad_caps(video_src, video_width, video_height, video_fps, 1);
+ gst_app_src_set_caps((GstAppSrc *) sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SRC].gst, srccaps);
+ /*_mmstreamrec_dbg_err("newbuf streamrecorder(%p) ",newbuf);*/
+
+ ret = gst_app_src_push_buffer((GstAppSrc *) sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SRC].gst, buffer);
+ if (ret) {
+ _mmstreamrec_dbg_err("video gst_app_src_push_buffer %d", ret);
+ ret = MM_ERROR_STREAMRECORDER_VIDEOBUFFER_PUSH;
+ }
+
+ /* g_signal_emit_by_name(sc->encode_element[_MMSTREAMRECORDER_ENCSINK_SRC].gst, "push-buffer", newbuf, &ret); */
+ }
+
+ return ret;
+}
+
+int _mmstreamrecorder_push_audiostream_buffer(MMHandleType handle, unsigned long timestamp, GstBuffer *buffer, int size)
+{
+ mmf_streamrecorder_t *hstreamrecorder = MMF_STREAMRECORDER(handle);
+ _MMStreamRecorderSubContext *sc = NULL;
+ _MMStreamRecorderAudioInfo *info = NULL;
+ GstFlowReturn err = GST_FLOW_OK;
+ GstPad *srcpad = NULL;
+ GstCaps *srccaps = NULL;
+ int rate = 0;
+ int channel = 0;
+ int depth = 0;
+
+ mmf_return_val_if_fail(hstreamrecorder, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ sc = MMF_STREAMRECORDER_SUBCONTEXT(handle);
+ mmf_return_val_if_fail(sc, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ info = (_MMStreamRecorderAudioInfo *) sc->info_audio;
+ mmf_return_val_if_fail(info, MM_ERROR_STREAMRECORDER_NOT_INITIALIZED);
+
+ rate = info->iSamplingRate;
+ depth = info->audio_encode_depth;
+ channel = info->iChannels;
+
+ /*_mmstreamrec_dbg_log("Audio Buffer Push start , time stamp %ld",timestamp); */
+
+ if (sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst) {
+
+ srcpad = gst_element_get_static_pad(sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst, "src");
+ /* TODO : CHANNEL , WIDTH, DATATYPE */
+ srccaps = gst_pad_get_current_caps(srcpad);
+ srccaps = gst_set_audiosrcpad_caps(rate, channel, depth, 16, 1);
+ gst_base_src_set_caps(GST_BASE_SRC(srcpad), srccaps);
+
+ err = gst_app_src_push_buffer((GstAppSrc *) sc->encode_element[_MMSTREAMRECORDER_AUDIOSRC_SRC].gst, buffer);
+
+ if (err) {
+ _mmstreamrec_dbg_err("Audio gst_app_src_push_buffer %d", err);
+ return MM_ERROR_STREAMRECORDER_AUDIOBUFFER_PUSH;
+ }
+ }
+
+ return MM_ERROR_NONE;
+}
+
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <sys/vfs.h> /* struct statfs */
+
+#include "mm_streamrecorder_util.h"
+#include <mm_types.h>
+#include <mm_error.h>
+#include <glib.h>
+#include <stdlib.h>
+#include "iniparser.h"
+#include <glib/gstdio.h>
+#include <gst/video/video-info.h>
+
+/*-----------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS for internal |
+-----------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------
+| LOCAL VARIABLE DEFINITIONS for internal |
+-----------------------------------------------------------------------*/
+#define TIME_STRING_MAX_LEN 64
+
+/*---------------------------------------------------------------------------
+| LOCAL FUNCTION PROTOTYPES: |
+---------------------------------------------------------------------------*/
+/* STATIC INTERNAL FUNCTION */
+
+/* static gint skip_mdat(FILE *f); */
+
+/*===========================================================================================
+| |
+| FUNCTION DEFINITIONS |
+========================================================================================== */
+/*---------------------------------------------------------------------------
+| GLOBAL FUNCTION DEFINITIONS: |
+---------------------------------------------------------------------------*/
+
+gint32 _mmstreamrecorder_double_to_fix(gdouble d_number)
+{
+ return (gint32) (d_number * 65536.0);
+}
+
+int _mmstreamrecorder_get_freespace(const gchar *path, guint64 *free_space)
+{
+ struct statfs fs;
+
+ g_assert(path);
+
+ if (!g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
+ _mmstreamrec_dbg_log("File(%s) doesn't exist.", path);
+ return -2;
+ }
+
+ if (-1 == statfs(path, &fs)) {
+ _mmstreamrec_dbg_log("Getting free space is failed.(%s)", path);
+ return -1;
+ }
+
+ *free_space = (guint64) fs.f_bsize * fs.f_bavail;
+ return 1;
+}
+
+int _mmstreamrecorder_get_file_size(const char *filename, guint64 * size)
+{
+ struct stat buf;
+
+ if (stat(filename, &buf) != 0)
+ return -1;
+ *size = (guint64) buf.st_size;
+ return 1;
+}
+
+void _mmstreamrecorder_err_trace_write(char *str_filename, char *func_name, int line_num, char *fmt, ...)
+{
+ FILE *f = NULL;
+ va_list ap = { 0 };
+ char time_string[TIME_STRING_MAX_LEN] = { '\0', };
+
+ time_t current_time;
+ struct tm new_time;
+
+ mmf_return_if_fail(str_filename);
+
+ current_time = time(NULL);
+ localtime_r(¤t_time, &new_time);
+
+ f = fopen(str_filename, "a");
+ if (f == NULL) {
+ _mmstreamrec_dbg_warn("Failed to open file.[%s]", str_filename);
+ return;
+ }
+
+ asctime_r(&new_time, time_string);
+ fprintf(f, "[%.19s][%05d][%s]", time_string, line_num, func_name);
+
+ va_start(ap, fmt);
+ vfprintf(f, fmt, ap);
+ va_end(ap);
+
+ fprintf(f, "\n");
+
+ fclose(f);
+}
+
+int _mmstreamrecorder_get_pixel_format(GstCaps *caps)
+{
+ const GstStructure *structure;
+ const char *media_type = NULL;
+ MMPixelFormatType type = 0;
+ unsigned int fourcc = 0;
+ GstVideoInfo media_info;
+
+ mmf_return_val_if_fail(caps != NULL, MM_PIXEL_FORMAT_INVALID);
+
+ structure = gst_caps_get_structure(caps, 0);
+ media_type = gst_structure_get_name(structure);
+
+ if (media_type == NULL) {
+ _mmstreamrec_dbg_log("failed to get media_type");
+ return MM_PIXEL_FORMAT_INVALID;
+ }
+
+ if (!strcmp(media_type, "image/jpeg")) {
+ _mmstreamrec_dbg_log("It is jpeg.");
+ type = MM_PIXEL_FORMAT_ENCODED;
+ } else if (!strcmp(media_type, "video/x-raw-yuv")) {
+ _mmstreamrec_dbg_log("It is yuv.");
+ gst_video_info_init(&media_info);
+ gst_video_info_from_caps(&media_info, caps);
+ fourcc = gst_video_format_to_fourcc(GST_VIDEO_INFO_FORMAT(&media_info));
+ type = _mmstreamrecorder_get_pixtype(fourcc);
+ } else if (!strcmp(media_type, "video/x-raw-rgb")) {
+ _mmstreamrec_dbg_log("It is rgb.");
+ type = MM_PIXEL_FORMAT_RGB888;
+ } else {
+ _mmstreamrec_dbg_err("Not supported format");
+ type = MM_PIXEL_FORMAT_INVALID;
+ }
+
+ _mmstreamrec_dbg_log("Type [%d]", type);
+
+ gst_caps_unref(caps);
+ caps = NULL;
+
+ return type;
+}
+
+unsigned int _mmstreamrecorder_get_fourcc(int pixtype, int codectype, int use_zero_copy_format)
+{
+ unsigned int fourcc = 0;
+
+ _mmstreamrec_dbg_log("pixtype(%d)", pixtype);
+
+ switch (pixtype) {
+ case MM_PIXEL_FORMAT_NV12:
+ if (use_zero_copy_format)
+ fourcc = GST_MAKE_FOURCC('S', 'N', '1', '2');
+ else
+ fourcc = GST_MAKE_FOURCC('N', 'V', '1', '2');
+ break;
+ case MM_PIXEL_FORMAT_YUYV:
+ if (use_zero_copy_format)
+ fourcc = GST_MAKE_FOURCC('S', 'U', 'Y', 'V');
+ else
+ fourcc = GST_MAKE_FOURCC('Y', 'U', 'Y', '2');
+ break;
+ case MM_PIXEL_FORMAT_UYVY:
+ if (use_zero_copy_format)
+ fourcc = GST_MAKE_FOURCC('S', 'Y', 'V', 'Y');
+ else
+ fourcc = GST_MAKE_FOURCC('U', 'Y', 'V', 'Y');
+
+ break;
+ case MM_PIXEL_FORMAT_I420:
+ if (use_zero_copy_format)
+ fourcc = GST_MAKE_FOURCC('S', '4', '2', '0');
+ else
+ fourcc = GST_MAKE_FOURCC('I', '4', '2', '0');
+ break;
+ case MM_PIXEL_FORMAT_YV12:
+ fourcc = GST_MAKE_FOURCC('Y', 'V', '1', '2');
+ break;
+ case MM_PIXEL_FORMAT_422P:
+ fourcc = GST_MAKE_FOURCC('4', '2', '2', 'P');
+ break;
+ case MM_PIXEL_FORMAT_RGB565:
+ fourcc = GST_MAKE_FOURCC('R', 'G', 'B', 'P');
+ break;
+ case MM_PIXEL_FORMAT_RGB888:
+ fourcc = GST_MAKE_FOURCC('R', 'G', 'B', ' ');
+ break;
+ case MM_PIXEL_FORMAT_ENCODED:
+ if (codectype == MM_IMAGE_CODEC_JPEG) {
+ fourcc = GST_MAKE_FOURCC('J', 'P', 'E', 'G');
+ } else if (codectype == MM_IMAGE_CODEC_JPEG_SRW) {
+ fourcc = GST_MAKE_FOURCC('J', 'P', 'E', 'G'); /*TODO: JPEG+SamsungRAW format */
+ } else if (codectype == MM_IMAGE_CODEC_SRW) {
+ fourcc = GST_MAKE_FOURCC('J', 'P', 'E', 'G'); /*TODO: SamsungRAW format */
+ } else if (codectype == MM_IMAGE_CODEC_PNG) {
+ fourcc = GST_MAKE_FOURCC('P', 'N', 'G', ' ');
+ } else {
+ /* Please let us know what other fourcces are. ex) BMP, GIF? */
+ fourcc = GST_MAKE_FOURCC('J', 'P', 'E', 'G');
+ }
+ break;
+ case MM_PIXEL_FORMAT_ITLV_JPEG_UYVY:
+ fourcc = GST_MAKE_FOURCC('I', 'T', 'L', 'V');
+ break;
+ default:
+ _mmstreamrec_dbg_log("Not proper pixel type[%d]. Set default - I420", pixtype);
+ if (use_zero_copy_format)
+ fourcc = GST_MAKE_FOURCC('S', '4', '2', '0');
+ else
+ fourcc = GST_MAKE_FOURCC('I', '4', '2', '0');
+ break;
+ }
+
+ return fourcc;
+}
+
+int _mmstreamrecorder_get_pixtype(unsigned int fourcc)
+{
+ int pixtype = MM_PIXEL_FORMAT_INVALID;
+/*
+ char *pfourcc = (char*)&fourcc;
+ _mmstreamrec_dbg_log("fourcc(%c%c%c%c)", pfourcc[0], pfourcc[1], pfourcc[2], pfourcc[3]);
+*/
+ switch (fourcc) {
+ case GST_MAKE_FOURCC('S', 'N', '1', '2'):
+ case GST_MAKE_FOURCC('N', 'V', '1', '2'):
+ pixtype = MM_PIXEL_FORMAT_NV12;
+ break;
+ case GST_MAKE_FOURCC('S', 'U', 'Y', 'V'):
+ case GST_MAKE_FOURCC('Y', 'U', 'Y', 'V'):
+ case GST_MAKE_FOURCC('Y', 'U', 'Y', '2'):
+ pixtype = MM_PIXEL_FORMAT_YUYV;
+ break;
+ case GST_MAKE_FOURCC('S', 'Y', 'V', 'Y'):
+ case GST_MAKE_FOURCC('U', 'Y', 'V', 'Y'):
+ pixtype = MM_PIXEL_FORMAT_UYVY;
+ break;
+ case GST_MAKE_FOURCC('S', '4', '2', '0'):
+ case GST_MAKE_FOURCC('I', '4', '2', '0'):
+ pixtype = MM_PIXEL_FORMAT_I420;
+ break;
+ case GST_MAKE_FOURCC('Y', 'V', '1', '2'):
+ pixtype = MM_PIXEL_FORMAT_YV12;
+ break;
+ case GST_MAKE_FOURCC('4', '2', '2', 'P'):
+ pixtype = MM_PIXEL_FORMAT_422P;
+ break;
+ case GST_MAKE_FOURCC('R', 'G', 'B', 'P'):
+ pixtype = MM_PIXEL_FORMAT_RGB565;
+ break;
+ case GST_MAKE_FOURCC('R', 'G', 'B', '3'):
+ pixtype = MM_PIXEL_FORMAT_RGB888;
+ break;
+ case GST_MAKE_FOURCC('A', 'R', 'G', 'B'):
+ case GST_MAKE_FOURCC('x', 'R', 'G', 'B'):
+ pixtype = MM_PIXEL_FORMAT_ARGB;
+ break;
+ case GST_MAKE_FOURCC('B', 'G', 'R', 'A'):
+ case GST_MAKE_FOURCC('B', 'G', 'R', 'x'):
+ pixtype = MM_PIXEL_FORMAT_RGBA;
+ break;
+ case GST_MAKE_FOURCC('J', 'P', 'E', 'G'):
+ case GST_MAKE_FOURCC('P', 'N', 'G', ' '):
+ pixtype = MM_PIXEL_FORMAT_ENCODED;
+ break;
+ /*FIXME*/ case GST_MAKE_FOURCC('I', 'T', 'L', 'V'):
+ pixtype = MM_PIXEL_FORMAT_ITLV_JPEG_UYVY;
+ break;
+ default:
+ _mmstreamrec_dbg_log("Not supported fourcc type(%x)", fourcc);
+ pixtype = MM_PIXEL_FORMAT_INVALID;
+ break;
+ }
+
+ return pixtype;
+}
+
+guint16 get_language_code(const char *str)
+{
+ return (guint16) (((str[0] - 0x60) & 0x1F) << 10) + (((str[1] - 0x60) & 0x1F) << 5) + ((str[2] - 0x60) & 0x1F);
+}
+
+gchar *str_to_utf8(const gchar * str)
+{
+ return g_convert(str, -1, "UTF-8", "ASCII", NULL, NULL, NULL);
+}
+
+inline gboolean write_tag(FILE *f, const gchar *tag)
+{
+ while (*tag)
+ FPUTC_CHECK(*tag++, f);
+
+ return TRUE;
+}
+
+inline gboolean write_to_32(FILE *f, guint val)
+{
+ FPUTC_CHECK(val >> 24, f);
+ FPUTC_CHECK(val >> 16, f);
+ FPUTC_CHECK(val >> 8, f);
+ FPUTC_CHECK(val, f);
+ return TRUE;
+}
+
+inline gboolean write_to_16(FILE *f, guint val)
+{
+ FPUTC_CHECK(val >> 8, f);
+ FPUTC_CHECK(val, f);
+ return TRUE;
+}
+
+inline gboolean write_to_24(FILE *f, guint val)
+{
+ write_to_16(f, val >> 8);
+ FPUTC_CHECK(val, f);
+ return TRUE;
+}
--- /dev/null
+/*
+ * libmm-streamrecorder
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 <mm_types.h>
+#include <mm_error.h>
+#include "mm_streamrecorder_video.h"
+#include "mm_streamrecorder_util.h"
+
+/*---------------------------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS for internal |
+---------------------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------------------
+| LOCAL VARIABLE DEFINITIONS for internal |
+---------------------------------------------------------------------------------------*/
+
+/*-----------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS for internal |
+-----------------------------------------------------------------------*/
+/* Table for compatibility between video codec and file format */
+gboolean common_videocodec_fileformat_compatibility_table[MM_VIDEO_CODEC_NUM][MM_FILE_FORMAT_NUM] = {
+ /* 3GP ASF AVI MATROSKA MP4 OGG NUT QT REAL AMR AAC MP3 AIFF AU WAV MID MMF DIVX FLV VOB IMELODY WMA WMV JPG */
+ /*NONE*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*H263*/ {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*H264*/ {1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*H26L*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MPEG4*/ {1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MPEG1*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*WMV*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*DIVX*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*XVID*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*H261*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*H262*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*H263V2*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*H263V3*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*MJPEG*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MPEG2*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MPEG4_SIMPLE*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MPEG4_ADV*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MPEG4_MAIN*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MPEG4_CORE*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MPEG4_ACE*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MPEG4_ARTS*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*MPEG4_AVC*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*REAL*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+/*VC1*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*AVS*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*CINEPAK*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*INDEO*/ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+ /*THEORA*/ {0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}
+ ,
+};
+
+/*---------------------------------------------------------------------------------------
+| LOCAL FUNCTION PROTOTYPES: |
+---------------------------------------------------------------------------------------*/
+/* STATIC INTERNAL FUNCTION */
+
+/*=======================================================================================
+| FUNCTION DEFINITIONS |
+=======================================================================================*/
+/*---------------------------------------------------------------------------------------
+| GLOBAL FUNCTION DEFINITIONS: |
+---------------------------------------------------------------------------------------*/
+int _mmstreamrecorder_check_videocodec_fileformat_compatibility(unsigned int video_codec, unsigned int file_format)
+{
+ /* Check compatibility between audio codec and file format */
+ if (video_codec < MM_VIDEO_CODEC_NUM && file_format < MM_FILE_FORMAT_NUM) {
+ if (common_videocodec_fileformat_compatibility_table[video_codec][file_format] == 0) {
+ _mmstreamrec_dbg_err("Video codec[%d] and file format[%d] compatibility FAILED.", video_codec, file_format);
+ return MM_ERROR_STREAMRECORDER_ENCODER_WRONG_TYPE;
+ }
+
+ _mmstreamrec_dbg_log("Video codec[%d] and file format[%d] compatibility SUCCESS.", video_codec, file_format);
+ } else {
+ _mmstreamrec_dbg_err("Video codec[%d] or file format[%d] is INVALID.", video_codec, file_format);
+ return MM_ERROR_STREAMRECORDER_ENCODER_WRONG_TYPE;
+ }
+
+ return MM_ERROR_NONE;
+}
--- /dev/null
+bin_PROGRAMS = mm_streamrecorder_testsuite
+
+mm_streamrecorder_testsuite_SOURCES = mm_streamrecorder_testsuite.c
+
+mm_streamrecorder_testsuite_CFLAGS = -I$(srcdir)/../src/include \
+ $(GLIB_CFLAGS)\
+ $(GST_CFLAGS)\
+ $(MM_COMMON_CFLAGS)\
+ $(MM_SOUND_CFLAGS)\
+ $(MDM_CFLAGS)
+
+
+############################################
+#mm_streamrecorder_testsuite_CFLAGS += -DAPPSRC_TEST
+############################################
+
+mm_streamrecorder_testsuite_DEPENDENCIES = $(top_builddir)/src/libmmfstreamrecorder.la
+mm_streamrecorder_testsuite_LDADD = $(top_builddir)/src/libmmfstreamrecorder.la \
+ $(GLIB_LIBS)\
+ $(GST_LIBS)\
+ $(MM_COMMON_LIBS)\
+ $(MM_SOUND_LIBS)\
+ $(MDM_LIBS)
+
+
--- /dev/null
+/*
+ * mm_streamrecorder_testsuite
+ *
+ * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Hyuntae Kim <ht1211.kim@samsung.com>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <gst/gst.h>
+#include <sys/time.h>
+#include "../src/include/mm_streamrecorder.h"
+#include "../src/include/mm_streamrecorder_internal.h"
+#include "../src/include/mm_streamrecorder_util.h"
+#include "../src/include/mm_streamrecorder_attribute.h"
+#include <gst/video/colorbalance.h>
+
+/*-----------------------------------------------------------------------
+| GLOBAL VARIABLE DEFINITIONS: |
+-----------------------------------------------------------------------*/
+#define EXPORT_API __attribute__((__visibility__("default")))
+
+#define PACKAGE "mm_streamrecorder_testsuite"
+
+GMainLoop *g_loop;
+GIOChannel *stdin_channel;
+int resolution_set;
+int g_current_state;
+int src_w, src_h;
+GstCaps *filtercaps;
+bool isMultishot;
+int multishot_num;
+static int audio_stream_cb_cnt;
+static int video_stream_cb_cnt;
+static GTimer *timer = NULL;
+int g_state;
+
+enum {
+ STREAMRECORDER_NULL,
+ STREAMRECORDER_NONE,
+ STREAMRECORDER_CREATED,
+ STREAMRECORDER_STARTED,
+ STREAMRECORDER_COMMITED
+};
+
+void streamrecorder_set_state(int new_state)
+{
+ g_state = new_state;
+ return;
+}
+
+int streamrecorder_get_state()
+{
+ return g_state;
+}
+
+
+
+/*-----------------------------------------------------------------------
+| GLOBAL CONSTANT DEFINITIONS: |
+-----------------------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------------------
+| IMPORTED VARIABLE DECLARATIONS: |
+-----------------------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------------------
+| IMPORTED FUNCTION DECLARATIONS: |
+-----------------------------------------------------------------------*/
+
+
+/*-----------------------------------------------------------------------
+| LOCAL #defines: |
+-----------------------------------------------------------------------*/
+#define test_ffmux_mp4
+
+#define DISPLAY_X_0 0 /* for direct FB */
+#define DISPLAY_Y_0 0 /* 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 STILL_CAPTURE_FILE_PATH_NAME "/opt/StillshotCapture"
+#define MULTI_CAPTURE_FILE_PATH_NAME "/opt/MultishotCapture"
+#define TARGET_FILENAME_PATH "/opt/"
+#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 */
+/*
+ * D E B U G M E S S A G E
+ */
+#define MMF_DEBUG "** (mmstreamrecorder testsuite) DEBUG: "
+#define MMF_ERR "** (mmstreamrecorder testsuite) ERROR: "
+#define MMF_INFO "** (mmstreamrecorder testsuite) INFO: "
+#define MMF_WARN "** (mmstreamrecorder testsuite) WARNING: "
+#define MMF_TIME "** (mmstreamrecorder testsuite) TIME: "
+
+#define CHECK_MM_ERROR(expr) \
+do {\
+ int ret = 0; \
+ ret = expr; \
+ if (ret != MM_ERROR_NONE) {\
+ printf("[%s:%d] error code : %x \n", __func__, __LINE__, ret); \
+ return; \
+ } \
+} while (0)
+
+#define time_msg_t(fmt, arg...) \
+do { \
+ fprintf(stderr, "\x1b[44m\x1b[37m"MMF_TIME"[%s:%05d] " fmt , __func__, __LINE__, ##arg); \
+ fprintf(stderr, "\x1b[0m\n"); \
+} while (0)
+
+#define debug_msg_t(fmt, arg...)\
+do { \
+ fprintf(stderr, MMF_DEBUG"[%s:%05d] " fmt "\n", __func__, __LINE__, ##arg); \
+} while (0)
+
+#define err_msg_t(fmt, arg...) \
+do { \
+ fprintf(stderr, MMF_ERR"[%s:%05d] " fmt "\n", __func__, __LINE__, ##arg); \
+} while (0)
+
+#define info_msg_t(fmt, arg...) \
+do { \
+ fprintf(stderr, MMF_INFO"[%s:%05d] " fmt "\n", __func__, __LINE__, ##arg); \
+} while (0)
+
+#define warn_msg_t(fmt, arg...) \
+do { \
+ fprintf(stderr, MMF_WARN"[%s:%05d] " fmt "\n", __func__, __LINE__, ##arg); \
+} while (0)
+
+#ifndef SAFE_FREE
+#define SAFE_FREE(x) if (x) {g_free(x); x = NULL; }
+#endif
+
+
+GTimeVal previous;
+GTimeVal current;
+GTimeVal result;
+/* temporary buffer */
+char buffer[460800] = {0x0,};
+
+
+/**
+ * Enumerations for command
+ */
+#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_VIDEO_CAPTURE, /* recording and image capture mode */
+ MODE_AUDIO, /* audio recording*/
+ MODE_NUM,
+};
+
+enum {
+ MENU_STATE_MAIN,
+ MENU_STATE_SETTING,
+ MENU_STATE_NUM,
+};
+
+/*-----------------------------------------------------------------------
+| LOCAL DATA TYPE DEFINITIONS: |
+-----------------------------------------------------------------------*/
+typedef struct _streamrecorder_handle {
+ MMHandleType streamrecorder;
+ int mode; /* image(capture)/video(recording) mode */
+ bool isMultishot; /* flag for multishot mode */
+ int stillshot_count; /* total stillshot count */
+ int multishot_count; /* total multishot count */
+ const char *stillshot_filename; /* stored filename of stillshot */
+ const char *multishot_filename; /* stored filename of multishot */
+ int menu_state;
+ int fps;
+ bool isMute;
+ unsigned long long elapsed_time;
+} streamrecorder_handle_t;
+
+typedef struct _str_xypair {
+ char* attr_subcat_x;
+ char* attr_subcat_y;
+ int x;
+ int y;
+} str_xypair_t;
+
+/*---------------------------------------------------------------------------
+| LOCAL VARIABLE DEFINITIONS: |
+---------------------------------------------------------------------------*/
+static streamrecorder_handle_t *hstreamrecorder ;
+
+const char *image_fmt[SENSOR_IMAGE_FORMAT] = {
+ "NV12",
+ "NV12T",
+ "NV16",
+ "NV21",
+ "YUYV",
+ "UYVY",
+ "422P",
+ "I420",
+ "YV12",
+};
+
+const char *face_zoom_mode[] = {
+ "Face Zoom OFF",
+ "Face Zoom ON",
+};
+
+const char *display_mode[] = {
+ "Default",
+ "Primary Video ON and Secondary Video Full Screen",
+ "Primary Video OFF and Secondary Video Full Screen",
+};
+
+const char *output_mode[] = {
+ "Letter Box mode",
+ "Original Size mode",
+ "Full Screen mode",
+ "Cropped Full Screen mode",
+ "ROI mode",
+};
+
+const char *rotate_mode[] = {
+ "0",
+ "90",
+ "180",
+ "270",
+};
+
+const char* strobe_mode[] = {
+ "Strobe OFF",
+ "Strobe ON",
+ "Strobe Auto",
+ "Strobe RedEyeReduction",
+ "Strobe SlowSync",
+ "Strobe FrontCurtain",
+ "Strobe RearCurtain",
+ "Strobe Permanent",
+};
+
+const char *detection_mode[2] = {
+ "Face Detection OFF",
+ "Face Detection ON",
+};
+
+const char *wdr_mode[] = {
+ "WDR OFF",
+ "WDR ON",
+ "WDR AUTO",
+};
+
+const char *hdr_mode[] = {
+ "HDR OFF",
+ "HDR ON",
+ "HDR ON and Original",
+};
+
+const char *ahs_mode[] = {
+ "Anti-handshake OFF",
+ "Anti-handshake ON",
+ "Anti-handshake AUTO",
+ "Anti-handshake MOVIE",
+};
+
+const char *vs_mode[] = {
+ "Video-stabilization OFF",
+ "Video-stabilization ON",
+};
+
+const char *visible_mode[] = {
+ "Display OFF",
+ "Display ON",
+};
+
+
+/*---------------------------------------------------------------------------
+| LOCAL FUNCTION PROTOTYPES: |
+---------------------------------------------------------------------------*/
+static void print_menu();
+void get_me_out();
+static gboolean cmd_input(GIOChannel *channel);
+static gboolean init(int type);
+static gboolean mode_change();
+int streamrecordertest_set_attr_int(const char* attr_subcategory, int value);
+
+
+static inline void flush_stdin()
+{
+ int ch;
+ while ((ch = getchar()) != EOF && ch != '\n');
+}
+
+#if 0
+static gboolean test_idle_capture_start()
+{
+ int err;
+
+ streamrecordertest_set_attr_int(MMSTR_VIDEO_SOURCE_FORMAT, MM_STREAMRECORDER_INPUT_FORMAT_NV12);
+ streamrecordertest_set_attr_int(MMSTR_VIDEO_ENCODER, MM_VIDEO_CODEC_H264);
+ streamrecordertest_set_attr_int(MMSTR_AUDIO_SOURCE_FORMAT, MM_STREAMRECORDER_AUDIO_FORMAT_PCM_U8);
+ streamrecordertest_set_attr_int(MMSTR_AUDIO_ENCODER, MM_AUDIO_CODEC_AAC);
+
+ g_timer_reset(timer);
+ err = mm_streamrecorder_record(hstreamrecorder->streamrecorder);
+
+ return FALSE;
+}
+#endif
+
+int streamrecordertest_set_attr_int(const char * attr_subcategory, int value)
+{
+ char * err_attr_name = NULL;
+ int err;
+
+ if (hstreamrecorder) {
+ if (hstreamrecorder->streamrecorder) {
+ debug_msg_t("streamrecordertest_set_attr_int(%s, %d)", attr_subcategory, value);
+
+ err = mm_streamrecorder_set_attributes(hstreamrecorder->streamrecorder, &err_attr_name, attr_subcategory, value, NULL);
+ if (err != MM_ERROR_NONE) {
+ err_msg_t("streamrecordertest_set_attr_int : Error(%s:%x)!!!!!!!", err_attr_name, err);
+ SAFE_FREE(err_attr_name);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ debug_msg_t("streamrecordertest_set_attr_int(!hstreamrecorder->streamrecorder)");
+ }
+
+ debug_msg_t("streamrecordertest_set_attr_int(!hstreamrecorder)");
+
+ return FALSE;
+}
+
+int streamrecordertest_set_attr_string(const char * attr_subcategory, char *value)
+{
+ char * err_attr_name = NULL;
+ int err;
+ if (value == NULL) {
+ err_msg_t("streamrecordertest_set_attr_string : value is null !");
+ return FALSE;
+ }
+ if (hstreamrecorder) {
+ if (hstreamrecorder->streamrecorder) {
+ debug_msg_t("streamrecordertest_set_attr_string(%s, %s)", attr_subcategory, value);
+
+ err = mm_streamrecorder_set_attributes(hstreamrecorder->streamrecorder, &err_attr_name, attr_subcategory, value, NULL);
+ if (err != MM_ERROR_NONE) {
+ err_msg_t("streamrecordertest_set_attr_string : Error(%s:%x)!!!!!!!", err_attr_name, err);
+ SAFE_FREE(err_attr_name);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ debug_msg_t("streamrecordertest_set_attr_string(!hstreamrecorder->streamrecorder)");
+ }
+
+ debug_msg_t("streamrecordertest_set_attr_string(!hstreamrecorder)");
+
+ return FALSE;
+}
+
+int streamrecordertest_set_attr_xypair(str_xypair_t pair)
+{
+ char * err_attr_name = NULL;
+ int err;
+
+ if (hstreamrecorder) {
+ if (hstreamrecorder->streamrecorder) {
+ debug_msg_t("streamrecordertest_set_attr_xypair((%s, %s), (%d, %d))", pair.attr_subcat_x, pair.attr_subcat_y, pair.x, pair.y);
+
+ err = mm_streamrecorder_set_attributes(hstreamrecorder->streamrecorder, &err_attr_name,
+ pair.attr_subcat_x, pair.x,
+ pair.attr_subcat_y, pair.y,
+ NULL);
+ if (err < 0) {
+ err_msg_t("streamrecordertest_set_attr_xypair : Error(%s:%x)!!", err_attr_name, err);
+ SAFE_FREE(err_attr_name);
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ debug_msg_t("streamrecordertest_set_attr_xypair(!hstreamrecorder->streamrecorder)");
+ }
+
+ debug_msg_t("streamrecordertest_set_attr_xypair(!hstreamrecorder)");
+ return FALSE;
+}
+
+int streamrecordertest_get_attr_valid_intarray(const char * attr_name, int ** array, int *count)
+{
+ MMStreamRecorderAttrsInfo info;
+ int err = MM_ERROR_NONE;
+
+ if (hstreamrecorder) {
+ if (hstreamrecorder->streamrecorder) {
+ debug_msg_t("streamrecordertest_get_attr_valid_intarray(%s)", attr_name);
+
+ err = mm_streamrecorder_get_attribute_info(hstreamrecorder->streamrecorder, attr_name, &info);
+ if (err != MM_ERROR_NONE) {
+ err_msg_t("streamrecordertest_get_attr_valid_intarray : Error(%x)!!", err);
+ return FALSE;
+ } else {
+ if (info.type == MM_STR_REC_ATTRS_TYPE_INT) {
+ if (info.validity_type == MM_STR_REC_ATTRS_VALID_TYPE_INT_ARRAY) {
+ *array = info.int_array.array;
+ *count = info.int_array.count;
+ debug_msg_t("INT ARRAY - default value : %d", info.int_array.def);
+ return TRUE;
+ }
+ }
+
+ err_msg_t("streamrecordertest_get_attr_valid_intarray : Type mismatched!!");
+ return FALSE;
+ }
+ }
+
+ debug_msg_t("streamrecordertest_get_attr_valid_intarray(!hstreamrecorder->streamrecorder)");
+ }
+
+
+ debug_msg_t("streamrecordertest_get_attr_valid_intarray(!hstreamrecorder)");
+ return FALSE;
+}
+
+int streamrecordertest_get_attr_valid_intrange(const char * attr_name, int *min, int *max)
+{
+ MMStreamRecorderAttrsInfo info;
+ int err = MM_ERROR_NONE;
+
+ if (hstreamrecorder) {
+ if (hstreamrecorder->streamrecorder) {
+ debug_msg_t("streamrecordertest_get_attr_valid_intrange(%s)", attr_name);
+
+ err = mm_streamrecorder_get_attribute_info(hstreamrecorder->streamrecorder, attr_name, &info);
+ if (err != MM_ERROR_NONE) {
+ err_msg_t("streamrecordertest_get_attr_valid_intarray : Error(%x)!!", err);
+ return FALSE;
+ } else {
+ if (info.type == MM_STR_REC_ATTRS_TYPE_INT) {
+ if (info.validity_type == MM_STR_REC_ATTRS_VALID_TYPE_INT_RANGE) {
+ *min = info.int_range.min;
+ *max = info.int_range.max;
+ debug_msg_t("INT RANGE - default : %d", info.int_range.def);
+ return TRUE;
+ }
+ }
+
+ err_msg_t("streamrecordertest_get_attr_valid_intarray : Type mismatched!!");
+ return FALSE;
+ }
+
+ }
+
+ debug_msg_t("streamrecordertest_get_attr_valid_intarray(!hstreamrecorder->streamrecorder)");
+ }
+
+ debug_msg_t("streamrecordertest_get_attr_valid_intarray(!hstreamrecorder)");
+ return FALSE;
+}
+
+
+void get_me_out()
+{
+}
+
+static void print_menu()
+{
+ switch (hstreamrecorder->menu_state) {
+ case MENU_STATE_MAIN:
+ g_print("\n\t=======================================\n");
+ g_print("\t Stream Recorder Menu \n");
+ g_print("\t=======================================\n");
+ if (hstreamrecorder->mode == MODE_VIDEO_CAPTURE) {
+ if (streamrecorder_get_state() <= STREAMRECORDER_CREATED) {
+ g_print("\t '1' Start Recording\n");
+ g_print("\t '2' Setting\n");
+ g_print("\t '3' Print frame rate\n");
+ g_print("\t 'b' back\n");
+ } else if (streamrecorder_get_state() == STREAMRECORDER_STARTED) {
+ g_print("\t 'r' Resume\n");
+ g_print("\t 'c' Cancel Recording\n");
+ g_print("\t 's' Save\n");
+ }
+ } else if (hstreamrecorder->mode == MODE_AUDIO) {
+ if (streamrecorder_get_state() <= STREAMRECORDER_CREATED) {
+ g_print("\t '1' Start Recording\n");
+ g_print("\t 'b' back\n");
+ } else if (streamrecorder_get_state() == STREAMRECORDER_STARTED) {
+ g_print("\t 'r' Resume Recording\n");
+ g_print("\t 'c' Cancel Recording\n");
+ g_print("\t 's' Save Recording\n");
+ }
+ }
+ break;
+ case MENU_STATE_SETTING:
+ g_print("\n\t=======================================\n");
+ g_print("\t Stream Recorder > Setting\n");
+ g_print("\t=======================================\n");
+ g_print("\t >>>>>>>>>>>>>>>>>>>>>>>>>>>> [Stream Recorder] \n");
+ g_print("\t 'T' videobuffer type \n");
+ g_print("\t 'F' videosource format \n");
+ g_print("\t 'A' video framerate \n");
+ g_print("\t 'B' video bitrate \n");
+ g_print("\t 'D' audio source format\n");
+ g_print("\t 'I' audio bitrate \n");
+ g_print("\t 'S' audio samplerate \n");
+ g_print("\t 'O' video encoder \n");
+ g_print("\t 'C' audio encoder \n");
+ g_print("\t 'N' audio channel count \n");
+ g_print("\t 'm' file format\n");
+ g_print("\t 'b' back \n");
+ g_print("\t=======================================\n");
+ break;
+ default:
+ warn_msg_t("unknow menu state !!\n");
+ break;
+ }
+
+ return;
+}
+
+static void main_menu(gchar buf)
+{
+ int err = 0;
+
+ if (hstreamrecorder->mode == MODE_VIDEO_CAPTURE) {
+ if (streamrecorder_get_state() == STREAMRECORDER_CREATED) {
+ switch (buf) {
+ case '1': /* Start Recording */
+ g_print("*Recording start!\n");
+ video_stream_cb_cnt = 0;
+ audio_stream_cb_cnt = 0;
+
+ g_timer_reset(timer);
+ err = mm_streamrecorder_record(hstreamrecorder->streamrecorder);
+
+ mm_streamrecorder_push_stream_buffer(hstreamrecorder->streamrecorder, MM_STREAM_TYPE_VIDEO, 1000, buffer, (640*480*3/2));
+ mm_streamrecorder_push_stream_buffer(hstreamrecorder->streamrecorder, MM_STREAM_TYPE_VIDEO, 2000, buffer, (640*480*3/2));
+ mm_streamrecorder_push_stream_buffer(hstreamrecorder->streamrecorder, MM_STREAM_TYPE_VIDEO, 3000, buffer, (640*480*3/2));
+ mm_streamrecorder_push_stream_buffer(hstreamrecorder->streamrecorder, MM_STREAM_TYPE_VIDEO, 4000, buffer, (640*480*3/2));
+ mm_streamrecorder_push_stream_buffer(hstreamrecorder->streamrecorder, MM_STREAM_TYPE_VIDEO, 5000, buffer, (640*480*3/2));
+ mm_streamrecorder_push_stream_buffer(hstreamrecorder->streamrecorder, MM_STREAM_TYPE_VIDEO, 6000, buffer, (640*480*3/2));
+ mm_streamrecorder_push_stream_buffer(hstreamrecorder->streamrecorder, MM_STREAM_TYPE_VIDEO, 7000, buffer, (640*480*3/2));
+ mm_streamrecorder_push_stream_buffer(hstreamrecorder->streamrecorder, MM_STREAM_TYPE_VIDEO, 8000, buffer, (640*480*3/2));
+ mm_streamrecorder_push_stream_buffer(hstreamrecorder->streamrecorder, MM_STREAM_TYPE_VIDEO, 9000, buffer, (640*480*3/2));
+ mm_streamrecorder_push_stream_buffer(hstreamrecorder->streamrecorder, MM_STREAM_TYPE_VIDEO, 10000, buffer, (640*480*3/2));
+ mm_streamrecorder_push_stream_buffer(hstreamrecorder->streamrecorder, MM_STREAM_TYPE_VIDEO, 11000, buffer, (640*480*3/2));
+
+ if (err != MM_ERROR_NONE)
+ warn_msg_t("Rec start mm_streamrecorder_record 0x%x", err);
+
+ streamrecorder_set_state(STREAMRECORDER_STARTED);
+ break;
+
+ case '2': /* Setting */
+ hstreamrecorder->menu_state = MENU_STATE_SETTING;
+ break;
+
+ case '3': /* Print frame rate */
+ break;
+
+ case 'b': /* back */
+ hstreamrecorder->menu_state = MENU_STATE_MAIN;
+ mode_change();
+ break;
+
+ default:
+ g_print("\t Invalid input \n");
+ break;
+ }
+ } else if (streamrecorder_get_state() == STREAMRECORDER_STARTED) {
+ switch (buf) {
+ case 'r': /* Resume Recording */
+ g_print("*Resume!\n");
+ break;
+
+ case 'c': /* Cancel */
+ g_print("*Cancel Recording !\n");
+ err = mm_streamrecorder_cancel(hstreamrecorder->streamrecorder);
+
+ if (err < 0)
+ warn_msg_t("Cancel recording mm_streamrecorder_cancel = %x", err);
+
+ break;
+
+ case 's': /* Save */
+ g_print("*Save Recording!\n");
+ g_timer_reset(timer);
+
+ err = mm_streamrecorder_commit(hstreamrecorder->streamrecorder);
+ streamrecorder_set_state(STREAMRECORDER_CREATED);
+
+ if (err < 0)
+ warn_msg_t("Save recording mm_streamrecorder_commit = %x", err);
+
+ break;
+
+ case 'n': /* Capture video snapshot */
+ break;
+
+ default:
+ g_print("\t Invalid input \n");
+ break;
+ } /* switch */
+ } else {
+ err_msg_t("Wrong streamrecorder state, check status!!");
+ }
+ } else if (hstreamrecorder->mode == MODE_AUDIO) {
+ switch (buf) {
+ case '1': /* Start Recording */
+ g_print("*Recording start!\n");
+ g_timer_reset(timer);
+ err = mm_streamrecorder_record(hstreamrecorder->streamrecorder);
+
+ if (err < 0)
+ warn_msg_t("Rec start mm_streamrecorder_record = %x", err);
+
+ break;
+
+ case 'b': /* back */
+ hstreamrecorder->menu_state = MENU_STATE_MAIN;
+ mode_change();
+ break;
+
+ default:
+ g_print("\t Invalid input \n");
+ break;
+ }
+ } else {
+ g_print("\t Invalid mode, back to upper menu \n");
+ hstreamrecorder->menu_state = MENU_STATE_MAIN;
+ mode_change();
+ }
+}
+
+
+static void setting_menu(gchar buf)
+{
+ gboolean bret = FALSE;
+ int index_menu = 0;
+ int min = 0;
+ int max = 0;
+ int width_count = 0;
+ int height_count = 0;
+ int i = 0;
+ int count = 0;
+ int value = 0;
+ int* array = NULL;
+ int *width_array = NULL;
+ int *height_array = NULL;
+ char *err_attr_name = NULL;
+ str_xypair_t input_pair;
+ char filename[100];
+ int err = MM_ERROR_NONE;
+ int x = 0, y = 0, width = 0, height = 0;
+
+ if (hstreamrecorder->mode == MODE_VIDEO_CAPTURE) {
+ switch (buf) {
+ case '0': /* Setting */
+ g_print("*Select the preview resolution!\n");
+ streamrecordertest_get_attr_valid_intarray(MMSTR_VIDEO_RESOLUTION_WIDTH, &width_array, &width_count);
+ streamrecordertest_get_attr_valid_intarray(MMSTR_VIDEO_RESOLUTION_HEIGHT, &height_array, &height_count);
+
+ if (width_count != height_count) {
+ err_msg_t("System has wrong information!!\n");
+ } else if (width_count == 0) {
+ g_print("Not supported!!\n");
+ } else {
+ flush_stdin();
+
+ for (i = 0; i < width_count; i++)
+ g_print("\t %d. %d*%d\n", i+1, width_array[i], height_array[i]);
+
+ err = scanf("%d", &index_menu);
+ if (err == EOF) {
+ printf("\nscanf error : errno %d\n", errno);
+ } else {
+ if (index_menu > 0 && index_menu <= width_count) {
+ input_pair.x = width_array[index_menu-1];
+ input_pair.y = height_array[index_menu-1];
+ bret = streamrecordertest_set_attr_xypair(input_pair);
+ }
+ }
+ }
+ break;
+
+ case '1': /* Setting > Capture Resolution setting */
+ break;
+
+ case 'r': /* Setting > Rotate input when recording */
+ g_print("Not supported !! \n");
+ break;
+
+ case 'H': /* Setting > Hybrid mode */
+ g_print("* Hybrid mode\n");
+
+ g_print("\t 0. DISABLE\n");
+ g_print("\t 1. ENABLE\n");
+
+ flush_stdin();
+ err = scanf("%d", &index_menu);
+
+ if (index_menu < 0 || index_menu > 1)
+ g_print("Wrong INPUT[%d]!! \n", index_menu);
+
+ break;
+
+ case 'R': /* Setting > Stream Recorder-rotation setting */
+ g_print("*Stream Recorder-Rotation setting!\n");
+
+ g_print("\t0. 0 degree\n");
+ g_print("\t1. 90 degree\n");
+ g_print("\t2. 180 degree\n");
+ g_print("\t3. 270 degree\n");
+ flush_stdin();
+ err = scanf("%d", &index_menu);
+ if (index_menu < 0 || index_menu > 3)
+ g_print("Wrong Input[%d] !!\n\n", index_menu);
+
+ g_print("*Stream Recorder-Flip setting!\n");
+ g_print("\t0. NONE\n");
+ g_print("\t1. HORIZONTAL\n");
+ g_print("\t2. VERTICAL\n");
+ g_print("\t3. BOTH\n");
+ flush_stdin();
+ err = scanf("%d", &index_menu);
+ if (index_menu < 0 || index_menu > 3)
+ g_print("Wrong Input[%d] !!\n\n", index_menu);
+
+ break;
+
+ case 'T': /* Setting > videobuffer-type setting */
+ g_print("*videobuffer type !\n");
+ streamrecordertest_get_attr_valid_intrange("videobuffer-type", &min, &max);
+
+ if (min >= max) {
+ g_print("Not supported !! \n");
+ } else {
+ flush_stdin();
+ g_print("\n Select videobuffer type (%d ~ %d)\n", min, max);
+ err = scanf("%d", &index_menu);
+ bret = streamrecordertest_set_attr_int("videobuffer-type", index_menu);
+ }
+ break;
+
+ case 'F': /* Setting > videosource-format setting */
+ g_print("*videosource format !\n");
+ streamrecordertest_get_attr_valid_intrange("videosource-format", &min, &max);
+
+ if (min >= max) {
+ g_print("Not supported !! \n");
+ } else {
+ flush_stdin();
+ g_print("\n Select videosource-format (%d ~ %d)\n", min, max);
+ err = scanf("%d", &index_menu);
+ bret = streamrecordertest_set_attr_int("videosource-format", index_menu);
+ }
+ break;
+
+ case 'A': /* Setting > video framerate setting */
+ g_print("*video framerate !\n");
+ streamrecordertest_get_attr_valid_intrange("video-framerate", &min, &max);
+
+ if (min >= max) {
+ g_print("Not supported !! \n");
+ } else {
+ flush_stdin();
+ g_print("\n Select video-framerate (%d ~ %d)\n", min, max);
+ err = scanf("%d", &index_menu);
+ bret = streamrecordertest_set_attr_int("video-framerate", index_menu);
+ }
+ break;
+
+ case 'B': /* Setting > video bitrate setting */
+ g_print("*video bitrate !\n");
+ streamrecordertest_get_attr_valid_intrange("video-bitrate", &min, &max);
+
+ if (min >= max) {
+ g_print("Not supported !! \n");
+ } else {
+ flush_stdin();
+ g_print("\n Select video-bitrate (%d ~ %d)\n", min, max);
+ err = scanf("%d", &index_menu);
+ bret = streamrecordertest_set_attr_int("video-bitrate", index_menu);
+ }
+ break;
+
+ case 'D': /* Setting > audio-source-format setting */
+ g_print("*audio-source-format !\n");
+ streamrecordertest_get_attr_valid_intrange("audio-source-format", &min, &max);
+
+ if (min >= max) {
+ g_print("Not supported !! \n");
+ } else {
+ flush_stdin();
+ g_print("\n Select audio-source-format (%d ~ %d)\n", min, max);
+ err = scanf("%d", &index_menu);
+ bret = streamrecordertest_set_attr_int("audio-source-format", index_menu);
+ }
+ break;
+
+ case 'I': /* Setting > audio-bitrate setting */
+ g_print("*audio-bitrate !\n");
+ streamrecordertest_get_attr_valid_intrange("audio-bitrate", &min, &max);
+
+ if (min >= max) {
+ g_print("Not supported !! \n");
+ } else {
+ flush_stdin();
+ g_print("\n Select audio-bitrate (%d ~ %d)\n", min, max);
+ err = scanf("%d", &index_menu);
+ bret = streamrecordertest_set_attr_int("audio-bitrate", index_menu);
+ }
+ break;
+
+ case 'S': /* Setting > audio-samplerate setting */
+ g_print("*audio-samplerate !\n");
+ streamrecordertest_get_attr_valid_intrange("audio-samplerate", &min, &max);
+
+ if (min >= max) {
+ g_print("Not supported !! \n");
+ } else {
+ flush_stdin();
+ g_print("\n Select audio-samplerate (%d ~ %d)\n", min, max);
+ err = scanf("%d", &index_menu);
+ bret = streamrecordertest_set_attr_int("audio-samplerate", index_menu);
+ }
+ break;
+
+ case 'O': /* Setting > video-encoder setting */
+ g_print("*video-encoder!\n");
+ streamrecordertest_get_attr_valid_intrange("video-encoder", &min, &max);
+
+ if (min >= max) {
+ g_print("Not supported !! \n");
+ } else {
+ flush_stdin();
+ g_print("\n Select video-encoder (%d ~ %d)\n", min, max);
+ err = scanf("%d", &index_menu);
+ bret = streamrecordertest_set_attr_int("video-encoder", index_menu);
+ }
+ break;
+
+ case 'C': /* Setting >audio-encoder setting */
+ g_print("*audio-encoder!\n");
+ streamrecordertest_get_attr_valid_intrange("audio-encoder", &min, &max);
+
+ if (min >= max) {
+ g_print("Not supported !! \n");
+ } else {
+ flush_stdin();
+ g_print("\n Select audio-encoder (%d ~ %d)\n", min, max);
+ err = scanf("%d", &index_menu);
+ bret = streamrecordertest_set_attr_int("audio-encoder", index_menu);
+ }
+ break;
+
+ case 'N': /* Setting >audio-channel-count setting */
+ g_print("*audio-channel-count!\n");
+ streamrecordertest_get_attr_valid_intrange("audio-channel-count", &min, &max);
+
+ if (min >= max) {
+ g_print("Not supported !! \n");
+ } else {
+ flush_stdin();
+ g_print("\n Select audio-channel-count(%d ~ %d)\n", min, max);
+ err = scanf("%d", &index_menu);
+ bret = streamrecordertest_set_attr_int("audio-channel-count", index_menu);
+ }
+ break;
+
+ case 'b': /* back */
+ hstreamrecorder->menu_state = MENU_STATE_MAIN;
+ break;
+
+ default:
+ g_print("\t Invalid input \n");
+ break;
+ }
+ } else {
+ g_print("\t Invalid mode, back to upper menu \n");
+ hstreamrecorder->menu_state = MENU_STATE_MAIN;
+ }
+}
+
+
+/**
+ * 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;
+
+ debug_msg_t("ENTER");
+
+ g_io_channel_read_line(channel, &buf, &read_size, NULL, &g_error);
+ if (g_error) {
+ debug_msg_t("g_io_channel_read_chars error");
+ g_error_free(g_error);
+ g_error = NULL;
+ }
+
+ if (buf) {
+ g_strstrip(buf);
+
+ debug_msg_t("Menu Status : %d", hstreamrecorder->menu_state);
+ switch (hstreamrecorder->menu_state) {
+ case MENU_STATE_MAIN:
+ main_menu(buf[0]);
+ break;
+ case MENU_STATE_SETTING:
+ setting_menu(buf[0]);
+ break;
+ default:
+ break;
+ }
+
+ g_free(buf);
+ buf = NULL;
+
+ print_menu();
+ } else {
+ debug_msg_t("No read input");
+ }
+
+ return TRUE;
+}
+
+/**
+ * This function is to initiate streamrecorder attributes .
+ *
+ * @param type [in] image(capture)/video(recording) mode
+ *
+ * @return This function returns TRUE/FALSE
+ * @remark
+ * @see other functions
+ */
+static gboolean init(int type)
+{
+ MMHandleType str_handle = 0;
+
+ char *err_attr_name = NULL;
+ int video_codec = MM_VIDEO_CODEC_INVALID;
+ int audio_codec = MM_AUDIO_CODEC_INVALID;
+ int file_format = MM_FILE_FORMAT_INVALID;
+ int audio_enc = MM_AUDIO_CODEC_INVALID;
+ int channel = 0;
+ int v_bitrate = 0;
+ int a_bitrate = 0;
+ int video_width = 0;
+ int video_height = 0;
+ int video_fps = 0;
+ int audio_samplerate = 0;
+ int audio_src_format = 0;
+ int video_src_format = 0;
+ int rec_mode = 0;
+ const char *filename = "/opt/usr/media/test.mp4";
+
+ if (!hstreamrecorder)
+ return FALSE;
+
+ if (!hstreamrecorder->streamrecorder)
+ return FALSE;
+
+ str_handle = (MMHandleType)(hstreamrecorder->streamrecorder);
+
+ /*================================================================================
+ Video capture mode
+ *=================================================================================*/
+ if (type == MODE_VIDEO_CAPTURE) {
+ video_codec = MM_VIDEO_CODEC_MPEG4;
+ /*audio_codec = MM_AUDIO_CODEC_AAC;*/
+ file_format = MM_FILE_FORMAT_MP4;
+ /*audio_enc = MM_AUDIO_CODEC_PCM;*/
+ /*channel = 1;
+ v_bitrate = 8000000;
+ /*a_bitrate = 64000;*/
+ video_width = 640;
+ video_height = 480;
+ video_fps = 30;
+ /*audio_samplerate = 48000;*/
+ /*audio_src_format = 2;*/
+ rec_mode = 0;
+ video_src_format = MM_STREAMRECORDER_INPUT_FORMAT_NV12;
+ mm_streamrecorder_set_attributes((MMHandleType)str_handle, &err_attr_name,
+ MMSTR_VIDEO_ENABLE, TRUE,
+ MMSTR_AUDIO_ENABLE, FALSE,
+ NULL);
+
+ mm_streamrecorder_set_attributes((MMHandleType)str_handle, &err_attr_name,
+ MMSTR_VIDEO_ENCODER, video_codec,
+ /*MMSTR_AUDIO_ENCODER, audio_codec,*/
+ MMSTR_FILE_FORMAT, file_format,
+ MMSTR_VIDEO_BITRATE, v_bitrate,
+ MMSTR_VIDEO_RESOLUTION_WIDTH , video_width,
+ MMSTR_VIDEO_RESOLUTION_HEIGHT, video_height,
+ MMSTR_VIDEO_FRAMERATE, video_fps,
+ /*MMSTR_AUDIO_CHANNEL, channel,*/
+ /*MMSTR_AUDIO_SAMPLERATE, audio_samplerate,*/
+ /*MMSTR_AUDIO_BITRATE, a_bitrate,*/
+ /*MMSTR_AUDIO_SOURCE_FORMAT, audio_src_format,*/
+ MMSTR_VIDEO_SOURCE_FORMAT, video_src_format,
+ MMSTR_RECORDER_MODE, rec_mode,
+ NULL);
+ mm_streamrecorder_set_attributes((MMHandleType)str_handle, &err_attr_name,
+ MMSTR_FILENAME, filename, strlen(filename), NULL);
+
+
+ }
+ /*================================================================================
+ Audio mode
+ *=================================================================================*/
+ debug_msg_t("Init DONE.");
+
+ return TRUE;
+}
+
+static gboolean init_handle()
+{
+ hstreamrecorder->mode = MODE_VIDEO_CAPTURE; /* image(capture)/video(recording) mode */
+ hstreamrecorder->isMultishot = FALSE;
+ hstreamrecorder->stillshot_count = 0; /* total stillshot count */
+ hstreamrecorder->multishot_count = 0; /* total multishot count */
+ hstreamrecorder->stillshot_filename = STILL_CAPTURE_FILE_PATH_NAME; /* stored filename of stillshot */
+ hstreamrecorder->multishot_filename = MULTI_CAPTURE_FILE_PATH_NAME; /* stored filename of multishot */
+ hstreamrecorder->menu_state = MENU_STATE_MAIN;
+ hstreamrecorder->isMute = FALSE;
+ hstreamrecorder->elapsed_time = 0;
+ hstreamrecorder->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 = MM_ERROR_NONE;
+ int state = STREAMRECORDER_NONE;
+ int device_count = 0;
+ int facing_direction = 0;
+ char media_type = '\0';
+ char *evassink_name = NULL;
+ bool check = FALSE;
+
+ state = streamrecorder_get_state();
+ debug_msg_t("MMStreamrecorder State : %d", state);
+ if (state != STREAMRECORDER_NULL) {
+ if ((state == STREAMRECORDER_STARTED)) {
+ debug_msg_t("mm_streamrecorder_cancel");
+ err = mm_streamrecorder_cancel(hstreamrecorder->streamrecorder);
+
+ if (err < 0) {
+ warn_msg_t("exit mm_streamrecorder_cancel = %x", err);
+ return FALSE;
+ }
+ }
+
+ state = streamrecorder_get_state();
+ if (state == STREAMRECORDER_CREATED) {
+ debug_msg_t("mm_streamreorder_unrealize");
+ mm_streamrecorder_unrealize(hstreamrecorder->streamrecorder);
+ streamrecorder_set_state(STREAMRECORDER_NONE);
+ }
+
+ state = streamrecorder_get_state();
+ if (state == STREAMRECORDER_NONE) {
+ debug_msg_t("mm_streamrecorder_destroy");
+ mm_streamrecorder_destroy(hstreamrecorder->streamrecorder);
+
+ streamrecorder_set_state(STREAMRECORDER_NULL);
+ }
+ }
+
+ init_handle();
+ while (!check) {
+ g_print("\n\t=======================================\n");
+ g_print("\t MM_STREAMRECORDER_TESTSUIT\n");
+ g_print("\t=======================================\n");
+ g_print("\t '1' STREAM RECORDER CREATE\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);
+
+ switch (media_type) {
+ case '1':
+ hstreamrecorder->mode = MODE_VIDEO_CAPTURE;
+ check = TRUE;
+ break;
+ case '2':
+ hstreamrecorder->mode = MODE_VIDEO_CAPTURE;
+ check = TRUE;
+ break;
+ case '3':
+ hstreamrecorder->mode = MODE_AUDIO;
+ check = TRUE;
+ break;
+ case '4':
+ hstreamrecorder->mode = MODE_VIDEO_CAPTURE;
+ check = TRUE;
+ break;
+ case 'q':
+ g_print("\t Quit streamrecorder Testsuite!!\n");
+ hstreamrecorder->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;
+ }
+ }
+
+ debug_msg_t("mm_streamrecorder_create");
+ g_get_current_time(&previous);
+ g_timer_reset(timer);
+
+ FILE *fp = NULL;
+ size_t nread;
+ fp = fopen("/opt/usr/media/test.nv12", "a+");
+ if (!fp)
+ return -1;
+ nread = fread(&buffer, sizeof(char), sizeof(buffer), fp);
+ time_msg_t("mm_streamrecorder_create() : nread %d, sizeof(buffer) %d", nread, sizeof(buffer));
+ fclose(fp);
+
+ err = mm_streamrecorder_create(&hstreamrecorder->streamrecorder);
+ time_msg_t("mm_streamrecorder_create() : %12.6lfs", g_timer_elapsed(timer, NULL));
+
+ if (err != MM_ERROR_NONE) {
+ err_msg_t("mmstreamrecorder_create = %x", err);
+ return -1;
+ } else {
+
+ }
+
+ debug_msg_t("evassink name[%s], device count[%d], facing direction[%d]", evassink_name, device_count, facing_direction);
+
+ if (!init(hstreamrecorder->mode)) {
+ err_msg_t("testsuite init() failed.");
+ return -1;
+ }
+
+ debug_msg_t("mm_streamrecorder_realize");
+
+ g_timer_reset(timer);
+
+ err = mm_streamrecorder_realize(hstreamrecorder->streamrecorder);
+ streamrecorder_set_state(STREAMRECORDER_CREATED);
+ time_msg_t("mm_streamrecorder_realize() : %12.6lfs", g_timer_elapsed(timer, NULL));
+ if (err != MM_ERROR_NONE) {
+ err_msg_t("mm_streamrecorder_realize = %x", err);
+ return -1;
+ }
+
+ g_timer_reset(timer);
+
+ g_get_current_time(¤t);
+ timersub(¤t, &previous, &result);
+ time_msg_t("streamrecorder Starting Time : %ld.%lds", result.tv_sec, result.tv_usec);
+
+ return TRUE;
+}
+
+
+/**
+ * This function is the example main function for mmstreamrecorder 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);
+
+ time_msg_t("gst_init() : %12.6lfs", g_timer_elapsed(timer, NULL));
+
+ hstreamrecorder = (streamrecorder_handle_t *) g_malloc0(sizeof(streamrecorder_handle_t));
+
+ 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);
+
+ debug_msg_t("RUN main loop");
+
+ g_main_loop_run(g_loop);
+
+ debug_msg_t("STOP main loop");
+
+ if (timer) {
+ g_timer_stop(timer);
+ g_timer_destroy(timer);
+ timer = NULL;
+ }
+
+ g_free(hstreamrecorder);
+ g_main_loop_unref(g_loop);
+ g_io_channel_unref(stdin_channel);
+
+ return bret;
+}
+
+/*EOF*/