From ec26bef8c238b9a97feb8ecd831d8f16a9ee6882 Mon Sep 17 00:00:00 2001 From: "Hyuntae, Kim" Date: Thu, 10 Dec 2015 18:37:40 +0900 Subject: [PATCH 2/7] [libmm-streamrecorder] initial code for new feature of streamrecorder Change-Id: I1e25fb02ca03ce19b96ce512fea55ea835d3543a --- AUTHORS | 3 + LICENSE.APLv2 | 206 +++ Makefile.am | 8 + NOTICE | 3 + autogen.sh | 7 + configure.ac | 82 + libmm-streamrecorder.manifest | 8 + m4/lt~obsolete.m4 | 92 ++ mm-streamrecorder.pc.in | 11 + packaging/libmm-streamrecorder.spec | 68 + src/Makefile.am | 57 + src/include/mm_streamrecorder.h | 640 ++++++++ src/include/mm_streamrecorder_attribute.h | 254 ++++ src/include/mm_streamrecorder_audio.h | 81 + src/include/mm_streamrecorder_buffer_manager.h | 75 + src/include/mm_streamrecorder_fileinfo.h | 126 ++ src/include/mm_streamrecorder_gstcommon.h | 253 ++++ src/include/mm_streamrecorder_gstdispatch.h | 246 +++ src/include/mm_streamrecorder_ini.h | 217 +++ src/include/mm_streamrecorder_internal.h | 483 ++++++ src/include/mm_streamrecorder_recorder.h | 197 +++ src/include/mm_streamrecorder_util.h | 184 +++ src/include/mm_streamrecorder_video.h | 59 + src/mm_streamrecorder.c | 231 +++ src/mm_streamrecorder_attribute.c | 1153 ++++++++++++++ src/mm_streamrecorder_audio.c | 168 ++ src/mm_streamrecorder_buffer_manager.c | 57 + src/mm_streamrecorder_fileinfo.c | 350 +++++ src/mm_streamrecorder_gstcommon.c | 376 +++++ src/mm_streamrecorder_gstdispatch.c | 1399 +++++++++++++++++ src/mm_streamrecorder_ini.c | 367 +++++ src/mm_streamrecorder_internal.c | 803 ++++++++++ src/mm_streamrecorder_recorder.c | 1937 ++++++++++++++++++++++++ src/mm_streamrecorder_util.c | 345 +++++ src/mm_streamrecorder_video.c | 129 ++ test/Makefile.am | 25 + test/mm_streamrecorder_testsuite.c | 1280 ++++++++++++++++ 37 files changed, 11980 insertions(+) create mode 100644 AUTHORS create mode 100644 LICENSE.APLv2 create mode 100644 Makefile.am create mode 100644 NOTICE create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 libmm-streamrecorder.manifest create mode 100644 m4/lt~obsolete.m4 create mode 100644 mm-streamrecorder.pc.in create mode 100644 packaging/libmm-streamrecorder.spec create mode 100644 src/Makefile.am create mode 100644 src/include/mm_streamrecorder.h create mode 100644 src/include/mm_streamrecorder_attribute.h create mode 100644 src/include/mm_streamrecorder_audio.h create mode 100644 src/include/mm_streamrecorder_buffer_manager.h create mode 100644 src/include/mm_streamrecorder_fileinfo.h create mode 100644 src/include/mm_streamrecorder_gstcommon.h create mode 100644 src/include/mm_streamrecorder_gstdispatch.h create mode 100644 src/include/mm_streamrecorder_ini.h create mode 100644 src/include/mm_streamrecorder_internal.h create mode 100644 src/include/mm_streamrecorder_recorder.h create mode 100644 src/include/mm_streamrecorder_util.h create mode 100644 src/include/mm_streamrecorder_video.h create mode 100644 src/mm_streamrecorder.c create mode 100644 src/mm_streamrecorder_attribute.c create mode 100644 src/mm_streamrecorder_audio.c create mode 100644 src/mm_streamrecorder_buffer_manager.c create mode 100644 src/mm_streamrecorder_fileinfo.c create mode 100644 src/mm_streamrecorder_gstcommon.c create mode 100644 src/mm_streamrecorder_gstdispatch.c create mode 100644 src/mm_streamrecorder_ini.c create mode 100644 src/mm_streamrecorder_internal.c create mode 100644 src/mm_streamrecorder_recorder.c create mode 100644 src/mm_streamrecorder_util.c create mode 100644 src/mm_streamrecorder_video.c create mode 100644 test/Makefile.am create mode 100644 test/mm_streamrecorder_testsuite.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..3e37b5d --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +Jeongmo Yang +Hyuntae Kim +Heechul Jeon diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100644 index 0000000..bbe9d02 --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,206 @@ +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..3839fb0 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,8 @@ +ACLOCAL_AMFLAGS='-I m4' + +SUBDIRS = src test + +pcfiles = mm-streamrecorder.pc +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = $(pcfiles) +EXTRA_DIST = $(pcfiles) diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..0e0f016 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE.APLv2 file for Apache License terms and conditions. diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..d5ce106 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,7 @@ +#! /bin/sh + +libtoolize --copy --force +aclocal -I m4 +autoheader +autoconf +automake -a -c diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..91eadff --- /dev/null +++ b/configure.ac @@ -0,0 +1,82 @@ +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 diff --git a/libmm-streamrecorder.manifest b/libmm-streamrecorder.manifest new file mode 100644 index 0000000..8ea72a2 --- /dev/null +++ b/libmm-streamrecorder.manifest @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4 new file mode 100644 index 0000000..637bb20 --- /dev/null +++ b/m4/lt~obsolete.m4 @@ -0,0 +1,92 @@ +# 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])]) diff --git a/mm-streamrecorder.pc.in b/mm-streamrecorder.pc.in new file mode 100644 index 0000000..799aca2 --- /dev/null +++ b/mm-streamrecorder.pc.in @@ -0,0 +1,11 @@ +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 diff --git a/packaging/libmm-streamrecorder.spec b/packaging/libmm-streamrecorder.spec new file mode 100644 index 0000000..1a1897f --- /dev/null +++ b/packaging/libmm-streamrecorder.spec @@ -0,0 +1,68 @@ +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 diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..13d6b6c --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,57 @@ +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) + diff --git a/src/include/mm_streamrecorder.h b/src/include/mm_streamrecorder.h new file mode 100644 index 0000000..6414668 --- /dev/null +++ b/src/include/mm_streamrecorder.h @@ -0,0 +1,640 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * 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 + +#include +#include +#include + +#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 + +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 + +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 + +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 + +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 + +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 + +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__ */ diff --git a/src/include/mm_streamrecorder_attribute.h b/src/include/mm_streamrecorder_attribute.h new file mode 100644 index 0000000..4438ae3 --- /dev/null +++ b/src/include/mm_streamrecorder_attribute.h @@ -0,0 +1,254 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * 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 +#include +#include +#include +#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__ */ diff --git a/src/include/mm_streamrecorder_audio.h b/src/include/mm_streamrecorder_audio.h new file mode 100644 index 0000000..0899880 --- /dev/null +++ b/src/include/mm_streamrecorder_audio.h @@ -0,0 +1,81 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * 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 + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ +/** + * MMStreamRecorder information for audio mode + */ +typedef struct { + int iAudioEncoder; /** + * + * 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 +#include + +#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__ */ diff --git a/src/include/mm_streamrecorder_fileinfo.h b/src/include/mm_streamrecorder_fileinfo.h new file mode 100644 index 0000000..c40a841 --- /dev/null +++ b/src/include/mm_streamrecorder_fileinfo.h @@ -0,0 +1,126 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * 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__ */ diff --git a/src/include/mm_streamrecorder_gstcommon.h b/src/include/mm_streamrecorder_gstcommon.h new file mode 100644 index 0000000..2b832ea --- /dev/null +++ b/src/include/mm_streamrecorder_gstcommon.h @@ -0,0 +1,253 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * 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 + +#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__ */ diff --git a/src/include/mm_streamrecorder_gstdispatch.h b/src/include/mm_streamrecorder_gstdispatch.h new file mode 100644 index 0000000..53a7ed9 --- /dev/null +++ b/src/include/mm_streamrecorder_gstdispatch.h @@ -0,0 +1,246 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * 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 +#include +#include +#include + +#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__ */ diff --git a/src/include/mm_streamrecorder_ini.h b/src/include/mm_streamrecorder_ini.h new file mode 100644 index 0000000..7fbaca5 --- /dev/null +++ b/src/include/mm_streamrecorder_ini.h @@ -0,0 +1,217 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * 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 +#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 diff --git a/src/include/mm_streamrecorder_internal.h b/src/include/mm_streamrecorder_internal.h new file mode 100644 index 0000000..1e0e6ec --- /dev/null +++ b/src/include/mm_streamrecorder_internal.h @@ -0,0 +1,483 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "mm_streamrecorder.h" +#include + +/* 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__ */ diff --git a/src/include/mm_streamrecorder_recorder.h b/src/include/mm_streamrecorder_recorder.h new file mode 100644 index 0000000..f4f74db --- /dev/null +++ b/src/include/mm_streamrecorder_recorder.h @@ -0,0 +1,197 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * 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 +#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__ */ diff --git a/src/include/mm_streamrecorder_util.h b/src/include/mm_streamrecorder_util.h new file mode 100644 index 0000000..f0806eb --- /dev/null +++ b/src/include/mm_streamrecorder_util.h @@ -0,0 +1,184 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * 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 +#include +#include +#include "mm_debug.h" +#include +#include + +#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__ */ diff --git a/src/include/mm_streamrecorder_video.h b/src/include/mm_streamrecorder_video.h new file mode 100644 index 0000000..6e8329e --- /dev/null +++ b/src/include/mm_streamrecorder_video.h @@ -0,0 +1,59 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * 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 + +#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__ */ diff --git a/src/mm_streamrecorder.c b/src/mm_streamrecorder.c new file mode 100644 index 0000000..7e867fa --- /dev/null +++ b/src/mm_streamrecorder.c @@ -0,0 +1,231 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* ============================================================================== +| INCLUDE FILES | +===============================================================================*/ +#include +#include + +#include + +#include +#include "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; +} diff --git a/src/mm_streamrecorder_attribute.c b/src/mm_streamrecorder_attribute.c new file mode 100644 index 0000000..d8bc8fd --- /dev/null +++ b/src/mm_streamrecorder_attribute.c @@ -0,0 +1,1153 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include + +#include "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); +} diff --git a/src/mm_streamrecorder_audio.c b/src/mm_streamrecorder_audio.c new file mode 100644 index 0000000..4b6b342 --- /dev/null +++ b/src/mm_streamrecorder_audio.c @@ -0,0 +1,168 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include +#include +#include +#include "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; +} diff --git a/src/mm_streamrecorder_buffer_manager.c b/src/mm_streamrecorder_buffer_manager.c new file mode 100644 index 0000000..35d264f --- /dev/null +++ b/src/mm_streamrecorder_buffer_manager.c @@ -0,0 +1,57 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include +#include +#include +#include "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; +} diff --git a/src/mm_streamrecorder_fileinfo.c b/src/mm_streamrecorder_fileinfo.c new file mode 100644 index 0000000..61d9968 --- /dev/null +++ b/src/mm_streamrecorder_fileinfo.c @@ -0,0 +1,350 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include +#include +#include /* 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 */ diff --git a/src/mm_streamrecorder_gstcommon.c b/src/mm_streamrecorder_gstcommon.c new file mode 100644 index 0000000..1a437fa --- /dev/null +++ b/src/mm_streamrecorder_gstcommon.c @@ -0,0 +1,376 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include +#include + +#include "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; +} diff --git a/src/mm_streamrecorder_gstdispatch.c b/src/mm_streamrecorder_gstdispatch.c new file mode 100644 index 0000000..45b42f1 --- /dev/null +++ b/src/mm_streamrecorder_gstdispatch.c @@ -0,0 +1,1399 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include +#include +#include /* 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; + } +} diff --git a/src/mm_streamrecorder_ini.c b/src/mm_streamrecorder_ini.c new file mode 100644 index 0000000..5b9b3bb --- /dev/null +++ b/src/mm_streamrecorder_ini.c @@ -0,0 +1,367 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include +#include +#include +#include +#include +#include +#include "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; +} diff --git a/src/mm_streamrecorder_internal.c b/src/mm_streamrecorder_internal.c new file mode 100644 index 0000000..5532002 --- /dev/null +++ b/src/mm_streamrecorder_internal.c @@ -0,0 +1,803 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ +#include +#include +#include +#include + +#include "mm_streamrecorder_internal.h" +#include "mm_streamrecorder_recorder.h" +#include "mm_streamrecorder_attribute.h" +#include "mm_streamrecorder_gstdispatch.h" + +#include + +/*--------------------------------------------------------------------------------------- +| 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; +} diff --git a/src/mm_streamrecorder_recorder.c b/src/mm_streamrecorder_recorder.c new file mode 100644 index 0000000..02cb2b1 --- /dev/null +++ b/src/mm_streamrecorder_recorder.c @@ -0,0 +1,1937 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * 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 +#include +#include +#include + + +/*--------------------------------------------------------------------------------------- +| 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; +} + diff --git a/src/mm_streamrecorder_util.c b/src/mm_streamrecorder_util.c new file mode 100644 index 0000000..d7a5b96 --- /dev/null +++ b/src/mm_streamrecorder_util.c @@ -0,0 +1,345 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include +#include +#include /* struct statfs */ + +#include "mm_streamrecorder_util.h" +#include +#include +#include +#include +#include "iniparser.h" +#include +#include + +/*----------------------------------------------------------------------- +| 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; +} diff --git a/src/mm_streamrecorder_video.c b/src/mm_streamrecorder_video.c new file mode 100644 index 0000000..3300283 --- /dev/null +++ b/src/mm_streamrecorder_video.c @@ -0,0 +1,129 @@ +/* + * libmm-streamrecorder + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include +#include +#include "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; +} diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..5cd87f7 --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,25 @@ +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) + + diff --git a/test/mm_streamrecorder_testsuite.c b/test/mm_streamrecorder_testsuite.c new file mode 100644 index 0000000..91403ca --- /dev/null +++ b/test/mm_streamrecorder_testsuite.c @@ -0,0 +1,1280 @@ +/* + * mm_streamrecorder_testsuite + * + * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Hyuntae Kim + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include +#include +#include +#include +#include +#include "../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 + +/*----------------------------------------------------------------------- +| 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*/ -- 2.7.4 From 5cf88d7dd2e2ff8ffbd83ba21f0a9b768a7851ef Mon Sep 17 00:00:00 2001 From: "Hyuntae, Kim" Date: Wed, 13 Jan 2016 16:42:37 +0900 Subject: [PATCH 3/7] [libmm-streamrecorder] UTC issue fixes Change-Id: I5aed7121f2d9b6ce175ed8406c0f29ead6f5aa8a --- packaging/libmm-streamrecorder.spec | 2 +- src/mm_streamrecorder_attribute.c | 2 +- src/mm_streamrecorder_gstdispatch.c | 5 ---- src/mm_streamrecorder_ini.c | 52 ++++++++++++++++++------------------- src/mm_streamrecorder_recorder.c | 2 -- 5 files changed, 28 insertions(+), 35 deletions(-) diff --git a/packaging/libmm-streamrecorder.spec b/packaging/libmm-streamrecorder.spec index 1a1897f..9d9abb5 100644 --- a/packaging/libmm-streamrecorder.spec +++ b/packaging/libmm-streamrecorder.spec @@ -1,6 +1,6 @@ Name: libmm-streamrecorder Summary: Media Stream Recorder library -Version: 0.0.1 +Version: 0.0.2 Release: 0 Group: Multimedia/Other License: Apache-2.0 diff --git a/src/mm_streamrecorder_attribute.c b/src/mm_streamrecorder_attribute.c index d8bc8fd..40d7c91 100644 --- a/src/mm_streamrecorder_attribute.c +++ b/src/mm_streamrecorder_attribute.c @@ -558,7 +558,7 @@ int _mmstreamrecorder_get_audio_codec_format(MMHandleType handle, const char *na else if (!strcmp(name, "AAC")) codec_index = MM_AUDIO_CODEC_AAC; else if (!strcmp(name, "PCM")) - codec_index = MM_AUDIO_CODEC_PCM; + codec_index = MM_AUDIO_CODEC_WAVE; else if (!strcmp(name, "VORBIS")) codec_index = MM_AUDIO_CODEC_VORBIS; diff --git a/src/mm_streamrecorder_gstdispatch.c b/src/mm_streamrecorder_gstdispatch.c index 45b42f1..32b6b56 100644 --- a/src/mm_streamrecorder_gstdispatch.c +++ b/src/mm_streamrecorder_gstdispatch.c @@ -420,11 +420,6 @@ gboolean _mmstreamrecorder_remove_message_all(MMHandleType handle) 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); diff --git a/src/mm_streamrecorder_ini.c b/src/mm_streamrecorder_ini.c index 5b9b3bb..89c4dfa 100644 --- a/src/mm_streamrecorder_ini.c +++ b/src/mm_streamrecorder_ini.c @@ -213,43 +213,43 @@ int _mm_streamrecorder_ini_load(mm_streamrecorder_ini_t *ini) iniparser_freedict(dict); /* dump structure */ - _mmstreamrec_dbg_log("Stream Recorder initial settings.......................................\n"); + _mmstreamrec_dbg_log("[Stream Recorder initial setting][Start]"); /* 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); + _mmstreamrec_dbg_log("encsink_src_islive : %d", ini->encsink_src_islive); + _mmstreamrec_dbg_log("retrial_count : %d", ini->retrial_count); + _mmstreamrec_dbg_log("minimum_frame : %d", ini->minimum_frame); + _mmstreamrec_dbg_log("convert_output_buffer_num : %d", ini->convert_output_buffer_num); + _mmstreamrec_dbg_log("reset_pause_time : %d", ini->reset_pause_time); + _mmstreamrec_dbg_log("screen_record : %d", 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); + _mmstreamrec_dbg_log("encode bin profile : %d", ini->encsink_bin_profile); + _mmstreamrec_dbg_log("encode bin auto audio resample property : %d", ini->encsink_bin_auto_audio_resample); + _mmstreamrec_dbg_log("encode bin auto colorspace property : %d", ini->encsink_bin_auto_colorspace); + _mmstreamrec_dbg_log("encode bin use video toggle property : %d", ini->encsink_bin_use_video_toggle); + _mmstreamrec_dbg_log("encode bin auto audio convert property : %d", 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); + _mmstreamrec_dbg_log("name_of_encodebin_source : %s", ini->name_of_encsink_src); + _mmstreamrec_dbg_log("name_of_audio_source : %s", ini->name_of_audio_src); + _mmstreamrec_dbg_log("name_of_h264_video_encoder : %s", ini->h264_video_encoder); + _mmstreamrec_dbg_log("name_of_h263_video_encoder : %s", ini->h263_video_encoder); + _mmstreamrec_dbg_log("name_of_mpeg4_video_encoder : %s", ini->mpeg4_video_encoder); + _mmstreamrec_dbg_log("name_of_audio_encoder : %s", ini->name_of_encsink_bin_audio_encoder); + _mmstreamrec_dbg_log("name_of_video_converter : %s", ini->name_of_encsink_bin_video_converter); + _mmstreamrec_dbg_log("name_of_3GP_muxer : %s", ini->name_of_encsink_bin_3GPMUXER); + _mmstreamrec_dbg_log("name_of_MP4_muxer : %s", ini->name_of_encsink_bin_MP4MUXER); + _mmstreamrec_dbg_log("name_of_sink : %s", 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); + _mmstreamrec_dbg_log("audio_frame_minimum_space : %d", ini->audio_frame_minimum_space); + _mmstreamrec_dbg_log("audio_frame_wait_time : %d", ini->audio_frame_wait_time); /* video parameter */ - _mmstreamrec_dbg_log("video_frame_wait_time : %d\n", ini->video_frame_wait_time); + _mmstreamrec_dbg_log("video_frame_wait_time : %d", ini->video_frame_wait_time); - _mmstreamrec_dbg_log("---------------------------------------------------\n"); + _mmstreamrec_dbg_log("[Stream Recorder initial setting][End]"); loaded = TRUE; diff --git a/src/mm_streamrecorder_recorder.c b/src/mm_streamrecorder_recorder.c index 02cb2b1..94a8cc8 100644 --- a/src/mm_streamrecorder_recorder.c +++ b/src/mm_streamrecorder_recorder.c @@ -502,8 +502,6 @@ int _mmstreamrecorder_create_encodesink_bin(MMHandleType handle, MMStreamRecorde 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); -- 2.7.4 From aec00500fc6b92a4b891edbd659b8bcda44e8ec2 Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Thu, 10 Mar 2016 10:33:02 +0900 Subject: [PATCH 4/7] Memory free after message send Signed-off-by: SeokHoon Lee Change-Id: I5bec74b5710890d049d28f663a25bc081ed335db --- packaging/libmm-streamrecorder.spec | 2 +- src/mm_streamrecorder_gstdispatch.c | 21 ++++++++++++++++++--- src/mm_streamrecorder_internal.c | 2 +- src/mm_streamrecorder_recorder.c | 12 ++++++------ 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/packaging/libmm-streamrecorder.spec b/packaging/libmm-streamrecorder.spec index 9d9abb5..e30c202 100644 --- a/packaging/libmm-streamrecorder.spec +++ b/packaging/libmm-streamrecorder.spec @@ -1,6 +1,6 @@ Name: libmm-streamrecorder Summary: Media Stream Recorder library -Version: 0.0.2 +Version: 0.0.3 Release: 0 Group: Multimedia/Other License: Apache-2.0 diff --git a/src/mm_streamrecorder_gstdispatch.c b/src/mm_streamrecorder_gstdispatch.c index 32b6b56..e53c821 100644 --- a/src/mm_streamrecorder_gstdispatch.c +++ b/src/mm_streamrecorder_gstdispatch.c @@ -297,7 +297,10 @@ gboolean _mmstreamrecorder_msg_callback(void *data) mmf_return_val_if_fail(item, FALSE); hstreamrecorder = MMF_STREAMRECORDER(item->handle); - mmf_return_val_if_fail(hstreamrecorder, FALSE); + if(hstreamrecorder == NULL) { + _mmstreamrec_dbg_warn("msg id:0x%x, item:%p, handle is NULL", item->id, item); + goto MSG_CALLBACK_DONE; + } /* _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); @@ -311,9 +314,21 @@ gboolean _mmstreamrecorder_msg_callback(void *data) if (hstreamrecorder->msg_data) hstreamrecorder->msg_data = g_list_remove(hstreamrecorder->msg_data, item); - free(item); - item = NULL; _MMSTREAMRECORDER_UNLOCK((MMHandleType) hstreamrecorder); + +MSG_CALLBACK_DONE: + /* release allocated memory */ + if (item->id == MM_MESSAGE_STREAMRECORDER_VIDEO_CAPTURED || + item->id == MM_MESSAGE_STREAMRECORDER_AUDIO_CAPTURED) { + MMStreamRecordingReport *report = (MMStreamRecordingReport *)item->param.data; + if (report) { + SAFE_FREE(report->recording_filename); + item->param.data = NULL; + } + SAFE_FREE(report); + } + SAFE_FREE(item); + /* For not being called again */ return FALSE; } diff --git a/src/mm_streamrecorder_internal.c b/src/mm_streamrecorder_internal.c index 5532002..435f5d5 100644 --- a/src/mm_streamrecorder_internal.c +++ b/src/mm_streamrecorder_internal.c @@ -156,7 +156,7 @@ void _mmstreamrecorder_set_state(MMHandleType handle, int state) mmf_streamrecorder_t *streamrecorder = MMF_STREAMRECORDER(handle); _MMStreamRecorderMsgItem msg; - mmf_return_val_if_fail(streamrecorder, MM_ERROR_STREAMRECORDER_INVALID_ARGUMENT); + mmf_return_if_fail(streamrecorder); /*_mmstreamrec_dbg_log("");*/ diff --git a/src/mm_streamrecorder_recorder.c b/src/mm_streamrecorder_recorder.c index 94a8cc8..2d5c083 100644 --- a/src/mm_streamrecorder_recorder.c +++ b/src/mm_streamrecorder_recorder.c @@ -647,7 +647,7 @@ int _mmstreamrecorder_create_encodesink_bin(MMHandleType handle, MMStreamRecorde else info->max_time = ((guint64) imax_time) * 1000; /* to millisecond */ - finfo->filename = strdup(temp_filename); + finfo->filename = g_strdup(temp_filename); if (!finfo->filename) { _mmstreamrec_dbg_err("strdup was failed"); return err; @@ -1293,11 +1293,11 @@ int _mmstreamrecorder_video_handle_eos(MMHandleType handle) /* Send recording report to application */ msg.id = MM_MESSAGE_STREAMRECORDER_VIDEO_CAPTURED; - report = (MMStreamRecordingReport *) malloc(sizeof(MMStreamRecordingReport)); + report = (MMStreamRecordingReport *) g_malloc(sizeof(MMStreamRecordingReport)); if (!report) { _mmstreamrec_dbg_err("Recording report fail(%s). Out of memory.", finfo->filename); } else { - report->recording_filename = strdup(finfo->filename); + report->recording_filename = g_strdup(finfo->filename); msg.param.data = report; msg.param.code = 1; _mmstreamrecorder_send_message((MMHandleType) hstreamrecorder, &msg); @@ -1597,7 +1597,7 @@ int _mmstreamrecorder_audio_command(MMHandleType handle, int command) goto _ERR_STREAMRECORDER_AUDIO_COMMAND; } - finfo->filename = strdup(temp_filename); + finfo->filename = g_strdup(temp_filename); if (!finfo->filename) { _mmstreamrec_dbg_err("STRDUP was failed"); goto _ERR_STREAMRECORDER_AUDIO_COMMAND; @@ -1798,7 +1798,7 @@ int _mmstreamrecorder_audio_handle_eos(MMHandleType handle) /* Send recording report message to application */ msg.id = MM_MESSAGE_STREAMRECORDER_AUDIO_CAPTURED; - report = (MMStreamRecordingReport *) malloc(sizeof(MMStreamRecordingReport)); + report = (MMStreamRecordingReport *) g_malloc(sizeof(MMStreamRecordingReport)); if (!report) { _mmstreamrec_dbg_err("Recording report fail(%s). Out of memory.", finfo->filename); return FALSE; @@ -1810,7 +1810,7 @@ int _mmstreamrecorder_audio_handle_eos(MMHandleType handle) _mmstreamrecorder_audio_add_metadata_info_m4a(handle); /* END TAG HERE */ - report->recording_filename = strdup(finfo->filename); + report->recording_filename = g_strdup(finfo->filename); msg.param.data = report; _mmstreamrecorder_send_message(handle, &msg); -- 2.7.4 From b710713d0427bbe3158e3f900077e3d10ba018e5 Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Wed, 16 Mar 2016 10:44:18 +0900 Subject: [PATCH 5/7] Check build warning Signed-off-by: SeokHoon Lee Change-Id: I2685f28a53e4bf796b290a34418dd9596d802aa3 --- packaging/libmm-streamrecorder.spec | 2 +- src/include/mm_streamrecorder_ini.h | 72 ------------------------------------- src/mm_streamrecorder_attribute.c | 5 ++- src/mm_streamrecorder_ini.c | 30 +--------------- src/mm_streamrecorder_internal.c | 6 ++-- src/mm_streamrecorder_recorder.c | 3 +- test/mm_streamrecorder_testsuite.c | 26 ++++---------- 7 files changed, 19 insertions(+), 125 deletions(-) diff --git a/packaging/libmm-streamrecorder.spec b/packaging/libmm-streamrecorder.spec index e30c202..2bb8a53 100644 --- a/packaging/libmm-streamrecorder.spec +++ b/packaging/libmm-streamrecorder.spec @@ -1,6 +1,6 @@ Name: libmm-streamrecorder Summary: Media Stream Recorder library -Version: 0.0.3 +Version: 0.0.4 Release: 0 Group: Multimedia/Other License: Apache-2.0 diff --git a/src/include/mm_streamrecorder_ini.h b/src/include/mm_streamrecorder_ini.h index 7fbaca5..a65453e 100644 --- a/src/include/mm_streamrecorder_ini.h +++ b/src/include/mm_streamrecorder_ini.h @@ -133,78 +133,6 @@ typedef struct __mm_streamrecorder_ini { #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); diff --git a/src/mm_streamrecorder_attribute.c b/src/mm_streamrecorder_attribute.c index 40d7c91..61464d6 100644 --- a/src/mm_streamrecorder_attribute.c +++ b/src/mm_streamrecorder_attribute.c @@ -277,6 +277,9 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /*----------------------------------------------------------------------- | LOCAL FUNCTION PROTOTYPES: | -----------------------------------------------------------------------*/ +int _mmstreamrecorder_get_available_format(MMHandleType handle, int type, int ** format); + + /* STATIC INTERNAL FUNCTION */ static int __mmstreamrecorder_set_conf_to_valid_info(MMHandleType handle) { @@ -692,7 +695,7 @@ _mmstreamrecorder_get_available_format(MMHandleType handle, int type, int ** for int count = 0; int i = 0; int fmt = 0; - const char *name = NULL; + char *name = NULL; mmf_return_val_if_fail(hstreamrecorder, 0); diff --git a/src/mm_streamrecorder_ini.c b/src/mm_streamrecorder_ini.c index 89c4dfa..7160ec1 100644 --- a/src/mm_streamrecorder_ini.c +++ b/src/mm_streamrecorder_ini.c @@ -30,9 +30,6 @@ 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); @@ -78,31 +75,6 @@ do { \ } \ } 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; @@ -160,7 +132,7 @@ int _mm_streamrecorder_ini_load(mm_streamrecorder_ini_t *ini) 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_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); diff --git a/src/mm_streamrecorder_internal.c b/src/mm_streamrecorder_internal.c index 435f5d5..b9f6da6 100644 --- a/src/mm_streamrecorder_internal.c +++ b/src/mm_streamrecorder_internal.c @@ -46,10 +46,13 @@ /*--------------------------------------------------------------------------------------- | LOCAL FUNCTION PROTOTYPES: | ---------------------------------------------------------------------------------------*/ +void _mmstreamrecorder_set_state(MMHandleType handle, int state); + /*======================================================================================= | FUNCTION DEFINITIONS | =======================================================================================*/ + /*--------------------------------------------------------------------------------------- | GLOBAL FUNCTION DEFINITIONS: | ---------------------------------------------------------------------------------------*/ @@ -375,7 +378,6 @@ int _mmstreamrecorder_record(MMHandleType handle) 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; @@ -442,7 +444,7 @@ int _mmstreamrecorder_push_stream_buffer(MMHandleType handle, MMStreamRecorderSt 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)); + buffer, size, 0, size, stream_buffer, _mmstreamrecorder_buffer_destroy)); ret = _mmstreamrecorder_push_audiostream_buffer(handle, timestamp, stream_buffer->buffer, size); } else { gst_buffer_unmap(stream_buffer->buffer, &map); diff --git a/src/mm_streamrecorder_recorder.c b/src/mm_streamrecorder_recorder.c index 2d5c083..402118e 100644 --- a/src/mm_streamrecorder_recorder.c +++ b/src/mm_streamrecorder_recorder.c @@ -1271,8 +1271,9 @@ int _mmstreamrecorder_video_handle_eos(MMHandleType handle) 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) + if (sc->audio_enable == TRUE) { mmf_return_val_if_fail(sc->info_audio, FALSE); + } mmf_return_val_if_fail(sc->info_file, FALSE); diff --git a/test/mm_streamrecorder_testsuite.c b/test/mm_streamrecorder_testsuite.c index 91403ca..5564ff6 100644 --- a/test/mm_streamrecorder_testsuite.c +++ b/test/mm_streamrecorder_testsuite.c @@ -686,16 +686,10 @@ static void setting_menu(gchar buf) 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) { @@ -992,17 +986,11 @@ static gboolean init(int type) 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"; @@ -1020,17 +1008,17 @@ static gboolean init(int type) *=================================================================================*/ if (type == MODE_VIDEO_CAPTURE) { video_codec = MM_VIDEO_CODEC_MPEG4; - /*audio_codec = MM_AUDIO_CODEC_AAC;*/ + /* 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;*/ + /* 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;*/ + /* 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, -- 2.7.4 From 8d8b63818516c682fc07491d72aa27f8a1048efd Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Wed, 16 Mar 2016 16:08:27 +0900 Subject: [PATCH 6/7] migration /usr/etc directory to sysconfdir(/etc)/multimedia Signed-off-by: SeokHoon Lee Change-Id: Ibcb1fb2ab848a8baf086da081d99f2adbd4965dc --- packaging/libmm-streamrecorder.spec | 3 ++- src/include/mm_streamrecorder_ini.h | 2 +- src/include/mm_streamrecorder_util.h | 4 ---- src/mm_streamrecorder_ini.c | 4 ++-- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/packaging/libmm-streamrecorder.spec b/packaging/libmm-streamrecorder.spec index 2bb8a53..cbbfafb 100644 --- a/packaging/libmm-streamrecorder.spec +++ b/packaging/libmm-streamrecorder.spec @@ -1,6 +1,6 @@ Name: libmm-streamrecorder Summary: Media Stream Recorder library -Version: 0.0.4 +Version: 0.0.5 Release: 0 Group: Multimedia/Other License: Apache-2.0 @@ -35,6 +35,7 @@ Media Stream Recorder development library %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" +export CFLAGS+=" -DSYSCONFDIR=\\\"%{_sysconfdir}\\\"" ./autogen.sh %configure --disable-static make %{?jobs:-j%jobs} diff --git a/src/include/mm_streamrecorder_ini.h b/src/include/mm_streamrecorder_ini.h index a65453e..09fcfcd 100644 --- a/src/include/mm_streamrecorder_ini.h +++ b/src/include/mm_streamrecorder_ini.h @@ -31,7 +31,7 @@ extern "C" { #endif -#define MM_STREAMRECORDER_INI_DEFAULT_PATH "/usr/etc/mmfw_streamrecorder.ini" +#define MM_STREAMRECORDER_INI_DEFAULT_PATH SYSCONFDIR"/multimedia/mmfw_streamrecorder.ini" #define STREAMRECORDER_INI_MAX_STRLEN 256 #define STREAMRECORDER_INI_MAX_ELEMENT 10 diff --git a/src/include/mm_streamrecorder_util.h b/src/include/mm_streamrecorder_util.h index f0806eb..387badc 100644 --- a/src/include/mm_streamrecorder_util.h +++ b/src/include/mm_streamrecorder_util.h @@ -127,10 +127,6 @@ enum { }\ } -#if 0 -#define MM_STREAMRECORDER_INI_DEFAULT_PATH "/usr/etc/mmfw_transcode.ini" -#define STREAMRECORDER_INI_MAX_STRLEN 100 -#endif /*======================================================================================= | ENUM DEFINITIONS | ========================================================================================*/ diff --git a/src/mm_streamrecorder_ini.c b/src/mm_streamrecorder_ini.c index 7160ec1..3a67847 100644 --- a/src/mm_streamrecorder_ini.c +++ b/src/mm_streamrecorder_ini.c @@ -316,10 +316,10 @@ void __mm_streamrecorder_ini_check_status(void) 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"); + _mmstreamrec_dbg_err("failed to get mmfw_streamrecorder.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); + _mmstreamrec_dbg_err("mmfw_streamrecorder.ini file size=%d, Corrupted! So, Removed\n", (int)ini_buff.st_size); g_remove(MM_STREAMRECORDER_INI_DEFAULT_PATH); } } -- 2.7.4 From 931c3609d3b59bf8fc211e9cd7d1cb5034a9b8d8 Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Tue, 5 Apr 2016 11:42:52 +0900 Subject: [PATCH 7/7] mm_streamrecorder_get_attribute_info move to streamrecorder from streamrecorder_attribute, because of warning in mediastreamrecorder package Signed-off-by: SeokHoon Lee Change-Id: I1c12339df727d68467b95f6c6a7f61611bee74cf --- packaging/libmm-streamrecorder.spec | 2 +- src/include/mm_streamrecorder.h | 20 ++++++++++++++ src/include/mm_streamrecorder_attribute.h | 22 +--------------- src/mm_streamrecorder.c | 5 ++++ src/mm_streamrecorder_attribute.c | 43 ++++++++++++++----------------- src/mm_streamrecorder_ini.c | 16 ++++++------ 6 files changed, 54 insertions(+), 54 deletions(-) diff --git a/packaging/libmm-streamrecorder.spec b/packaging/libmm-streamrecorder.spec index cbbfafb..1b9de95 100644 --- a/packaging/libmm-streamrecorder.spec +++ b/packaging/libmm-streamrecorder.spec @@ -1,6 +1,6 @@ Name: libmm-streamrecorder Summary: Media Stream Recorder library -Version: 0.0.5 +Version: 0.0.6 Release: 0 Group: Multimedia/Other License: Apache-2.0 diff --git a/src/include/mm_streamrecorder.h b/src/include/mm_streamrecorder.h index 6414668..a369d7b 100644 --- a/src/include/mm_streamrecorder.h +++ b/src/include/mm_streamrecorder.h @@ -613,6 +613,26 @@ int mm_streamrecorder_get_attributes(MMHandleType streamrecorder, char **err_att int mm_streamrecorder_set_attributes(MMHandleType streamrecorder, char **err_attr_name, const char *attribute_name, ...) G_GNUC_NULL_TERMINATED; /** + * 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); + +/** * 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. diff --git a/src/include/mm_streamrecorder_attribute.h b/src/include/mm_streamrecorder_attribute.h index 4438ae3..4f80184 100644 --- a/src/include/mm_streamrecorder_attribute.h +++ b/src/include/mm_streamrecorder_attribute.h @@ -90,7 +90,7 @@ typedef bool(*mmf_streamrecorder_commit_func_t) (MMHandleType handle, int attr_i ========================================================================================*/ typedef struct { MMStreamRecorderAttrsID attrid; - const char *name; + char *name; int value_type; int flags; union { @@ -226,26 +226,6 @@ bool _mmstreamrecorder_commit_audio_bitrate(MMHandleType handle, int attr_idx, c */ 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 diff --git a/src/mm_streamrecorder.c b/src/mm_streamrecorder.c index 7e867fa..ec4c9b6 100644 --- a/src/mm_streamrecorder.c +++ b/src/mm_streamrecorder.c @@ -229,3 +229,8 @@ int mm_streamrecorder_set_attributes(MMHandleType streamrecorder, char **err_att return ret; } + +int mm_streamrecorder_get_attribute_info(MMHandleType streamrecorder, const char *attribute_name, MMStreamRecorderAttrsInfo * info) +{ + return _mmstreamrecorder_get_attribute_info(streamrecorder, attribute_name, info); +} diff --git a/src/mm_streamrecorder_attribute.c b/src/mm_streamrecorder_attribute.c index 61464d6..9d8fbe3 100644 --- a/src/mm_streamrecorder_attribute.c +++ b/src/mm_streamrecorder_attribute.c @@ -43,7 +43,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 0 */ { MM_STR_VIDEO_BUFFER_TYPE, /* ID */ - "videobuffer-type", /* Name */ + (char *)"videobuffer-type", /* Name */ MMF_VALUE_TYPE_INT, /* Type */ MM_ATTRS_FLAG_RW, /* Flag */ {(void *)MM_STREAMRECORDER_VIDEO_TYPE_TBM_BO}, /* Default value */ @@ -54,7 +54,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { }, /* 1 */ {MM_STR_VIDEO_FORMAT, - "videosource-format", + (char *)"videosource-format", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)MM_STREAMRECORDER_INPUT_FORMAT_NV12}, @@ -66,7 +66,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 2 */ { MM_STR_VIDEO_FRAMERATE, - "video-framerate", + (char *)"video-framerate", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)0}, @@ -78,7 +78,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 3 */ { MM_STR_VIDEO_ENCODER_BITRATE, - "video-bitrate", + (char *)"video-bitrate", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)0}, @@ -90,7 +90,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 4 */ { MM_STR_VIDEO_RESOLUTION_WIDTH, - "video-resolution-width", + (char *)"video-resolution-width", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)0}, @@ -102,7 +102,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 5 */ { MM_STR_VIDEO_RESOLUTION_HEIGHT, - "video-resolution-height", + (char *)"video-resolution-height", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)0}, @@ -114,7 +114,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 6 */ { MM_STR_AUDIO_FORMAT, - "audio-source-format", + (char *)"audio-source-format", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)MM_STREAMRECORDER_AUDIO_FORMAT_PCM_S16_LE}, @@ -126,7 +126,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 7 */ { MM_STR_AUDIO_ENCODER_BITRATE, - "audio-bitrate", + (char *)"audio-bitrate", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)128000}, @@ -138,7 +138,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 8 */ { MM_STR_AUDIO_SAMPLERATE, - "audio-samplerate", + (char *)"audio-samplerate", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)0}, @@ -150,7 +150,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 9 */ { MM_STR_VIDEO_ENCODER, - "video-encoder", + (char *)"video-encoder", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)0}, @@ -162,7 +162,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 10 */ { MM_STR_AUDIO_ENCODER, - "audio-encoder", + (char *)"audio-encoder", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)0}, @@ -174,7 +174,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 11 */ { MM_STR_AUDIO_CHENNEL_COUNT, - "audio-channel-count", + (char *)"audio-channel-count", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)2}, @@ -186,7 +186,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 12 */ { MM_STR_FILE_FORMAT, - "file-format", + (char *)"file-format", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)0}, @@ -198,7 +198,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 13 */ { MM_STR_TARGET_FILE_NAME, - "filename", + (char *)"filename", MMF_VALUE_TYPE_STRING, MM_ATTRS_FLAG_RW, {NULL}, @@ -210,7 +210,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 14 */ { MM_STR_VIDEO_ENABLE, - "video-enable", + (char *)"video-enable", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)FALSE}, @@ -222,7 +222,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 15 */ { MM_STR_AUDIO_ENABLE, - "audio-enable", + (char *)"audio-enable", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)FALSE}, @@ -234,7 +234,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /* 16 */ { MM_STR_MODE, - "recorder-mode", + (char *)"recorder-mode", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)MM_STREAMRECORDER_MODE_MEDIABUFFER}, @@ -246,7 +246,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /*17*/ { MM_STR_TARGET_MAX_SIZE, - "target-max-size", + (char *)"target-max-size", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)0}, @@ -258,7 +258,7 @@ mm_streamrecorder_attr_construct_info stream_attrs_const_info[] = { /*18*/ { MM_STR_TARGET_TIME_LIMIT, - "target-time-limit", + (char *)"target-time-limit", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, {(void *)0}, @@ -1149,8 +1149,3 @@ bool _mmstreamrecorder_commit_audio_channel(MMHandleType handle, int attr_idx, c 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); -} diff --git a/src/mm_streamrecorder_ini.c b/src/mm_streamrecorder_ini.c index 3a67847..49571f3 100644 --- a/src/mm_streamrecorder_ini.c +++ b/src/mm_streamrecorder_ini.c @@ -132,11 +132,11 @@ int _mm_streamrecorder_ini_load(mm_streamrecorder_ini_t *ini) 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); + MMSTREAMRECORDER_INI_GET_INT_FROM_LIST(dict, ini->supported_video_width, STREAMRECORDER_ATTRIBUTE_NUM_MAX, "attribute:supported width", (char *)DEFAULT_SUPPORTED_WIDTH); + MMSTREAMRECORDER_INI_GET_INT_FROM_LIST(dict, ini->supported_video_height, STREAMRECORDER_ATTRIBUTE_NUM_MAX, "attribute:supported height", (char *)DEFAULT_SUPPORTED_HEIGHT); + __get_element_list(ini, iniparser_getstring(dict, "attribute:supported audio encoders", (char*)DEFAULT_SUPPORTED_AUDIO_ENCODERS), KEYWORD_AUDIO_ENCODERS); + __get_element_list(ini, iniparser_getstring(dict, "attribute:supported video encoders", (char*)DEFAULT_SUPPORTED_VIDEO_ENCODERS), KEYWORD_VIDEO_ENCODERS); + __get_element_list(ini, iniparser_getstring(dict, "attribute:supported file formats", (char*)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"); @@ -176,9 +176,9 @@ int _mm_streamrecorder_ini_load(mm_streamrecorder_ini_t *ini) 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); + __get_element_list(ini, (char *)DEFAULT_SUPPORTED_AUDIO_ENCODERS, KEYWORD_AUDIO_ENCODERS); + __get_element_list(ini, (char *)DEFAULT_SUPPORTED_VIDEO_ENCODERS, KEYWORD_VIDEO_ENCODERS); + __get_element_list(ini, (char *)DEFAULT_SUPPORTED_FILE_FORMATS, KEYWORD_FILE_FORMATS); } /* free dict as we got our own structure */ -- 2.7.4