From 020c1d5863c4608a1fce14425a0bc0ddde110388 Mon Sep 17 00:00:00 2001 From: Jinkun Jang Date: Wed, 13 Mar 2013 01:49:54 +0900 Subject: [PATCH] Tizen 2.1 base --- AUTHORS | 2 + LICENSE.APLv2 | 206 +++ NOTICE | 3 + configure.ac | 11 + libmm-camcorder.manifest | 5 + packaging/libmm-camcorder.spec | 38 +- sounds/capture_shutter_01.wav | Bin 31228 -> 22772 bytes sounds/capture_shutter_02.wav | Bin 24152 -> 22772 bytes sounds/recording_start_01.wav | Bin 26584 -> 34228 bytes sounds/recording_stop_01.wav | Bin 26584 -> 11500 bytes src/Makefile.am | 6 + src/include/mm_camcorder.h | 313 ++++- src/include/mm_camcorder_attribute.h | 67 +- src/include/mm_camcorder_audiorec.h | 1 + src/include/mm_camcorder_gstcommon.h | 23 +- src/include/mm_camcorder_internal.h | 211 ++- src/include/mm_camcorder_platform.h | 22 +- src/include/mm_camcorder_sound.h | 35 +- src/include/mm_camcorder_stillshot.h | 34 +- src/include/mm_camcorder_util.h | 71 +- src/include/mm_camcorder_videorec.h | 4 +- src/mm_camcorder_attribute.c | 2449 ++++++++++++++++++++-------------- src/mm_camcorder_audiorec.c | 110 +- src/mm_camcorder_configure.c | 595 ++++----- src/mm_camcorder_exifinfo.c | 228 ++-- src/mm_camcorder_gstcommon.c | 898 ++++++++----- src/mm_camcorder_internal.c | 1216 +++++++++++------ src/mm_camcorder_platform.c | 256 +++- src/mm_camcorder_sound.c | 724 ++++++---- src/mm_camcorder_stillshot.c | 1606 +++++++++++----------- src/mm_camcorder_util.c | 372 ++++-- src/mm_camcorder_videorec.c | 434 +++--- test/Makefile.am | 1 + test/mm_camcorder_testsuite.c | 1962 ++++++++++----------------- 34 files changed, 6923 insertions(+), 4980 deletions(-) create mode 100644 AUTHORS create mode 100644 LICENSE.APLv2 create mode 100644 NOTICE create mode 100644 libmm-camcorder.manifest mode change 100755 => 100644 test/Makefile.am diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..fdd00d0 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Jeongmo Yang +Jonghyuk Choi diff --git a/LICENSE.APLv2 b/LICENSE.APLv2 new file mode 100644 index 0000000..bbe9d02 --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,206 @@ +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..0e0f016 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE.APLv2 file for Apache License terms and conditions. diff --git a/configure.ac b/configure.ac index e15e812..ae545e5 100644 --- a/configure.ac +++ b/configure.ac @@ -53,6 +53,10 @@ PKG_CHECK_MODULES(MM_SOUND, mm-sound) AC_SUBST(MM_SOUND_CFLAGS) AC_SUBST(MM_SOUND_LIBS) +PKG_CHECK_MODULES(AVSYSTEM, avsysaudio) +AC_SUBST(AVSYSTEM_CFLAGS) +AC_SUBST(AVSYSTEM_LIBS) + #PKG_CHECK_MODULES(INIPARSER, iniparser) #AC_SUBST(INIPARSER_CFLAGS) #AC_SUBST(INIPARSER_LIBS) @@ -77,6 +81,10 @@ PKG_CHECK_MODULES(MMSOUND, mm-sound) AC_SUBST(MMSOUND_CFLAGS) AC_SUBST(MMSOUND_LIBS) +PKG_CHECK_MODULES(MMUTIL_IMGP, mmutil-imgp) +AC_SUBST(MMUTIL_IMGP_CFLAGS) +AC_SUBST(MMUTIL_IMGP_LIBS) + PKG_CHECK_MODULES(SNDFILE, sndfile) AC_SUBST(SNDFILE_CFLAGS) AC_SUBST(SNDFILE_LIBS) @@ -85,6 +93,9 @@ PKG_CHECK_MODULES(CAMSRCJPEGENC, camsrcjpegenc) AC_SUBST(CAMSRCJPEGENC_CFLAGS) AC_SUBST(CAMSRCJPEGENC_LIBS) +PKG_CHECK_MODULES(VCONF, vconf) +AC_SUBST(VCONF_CFLAGS) +AC_SUBST(VCONF_LIBS) # Checks for header files. AC_HEADER_STDC diff --git a/libmm-camcorder.manifest b/libmm-camcorder.manifest new file mode 100644 index 0000000..a76fdba --- /dev/null +++ b/libmm-camcorder.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/packaging/libmm-camcorder.spec b/packaging/libmm-camcorder.spec index 6f323f0..b284020 100644 --- a/packaging/libmm-camcorder.spec +++ b/packaging/libmm-camcorder.spec @@ -1,42 +1,41 @@ Name: libmm-camcorder -Summary: camcorder library -Version: 0.5.5 -Release: 1 +Summary: Camera and recorder library +Version: 0.7.7 +Release: 0 Group: libs -License: Samsung -URL: N/A +License: Apache-2.0 Source0: %{name}-%{version}.tar.gz +Requires(post): /usr/bin/vconftool Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig BuildRequires: pkgconfig(mm-common) BuildRequires: pkgconfig(mm-sound) +BuildRequires: pkgconfig(avsystem) BuildRequires: pkgconfig(libexif) BuildRequires: pkgconfig(mmutil-imgp) -BuildRequires: pkgconfig(elementary) -BuildRequires: pkgconfig(appcore-efl) -BuildRequires: pkgconfig(vconf) BuildRequires: pkgconfig(mm-log) BuildRequires: pkgconfig(gstreamer-plugins-base-0.10) BuildRequires: pkgconfig(mm-ta) +BuildRequires: pkgconfig(sndfile) BuildRequires: pkgconfig(mm-session) BuildRequires: pkgconfig(audio-session-mgr) -BuildRequires: pkgconfig(gstreamer-floatcast-0.10) -BuildRequires: pkgconfig(gstreamer-check-0.10) BuildRequires: pkgconfig(camsrcjpegenc) +BuildRequires: pkgconfig(libpulse) +BuildRequires: pkgconfig(vconf) BuildRequires: gst-plugins-base-devel %description -camcorder library. +Camera and recorder library. %package devel -Summary: camcorder development library +Summary: Camera and recorder development library Group: libdevel Version: %{version} Requires: %{name} = %{version}-%{release} %description devel -camcorder development library. +Camera and recorder development library. %prep @@ -44,27 +43,36 @@ camcorder development library. %build +export CFLAGS+=" -DGST_EXT_TIME_ANALYSIS" ./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 -%post -p /sbin/ldconfig +%post +/sbin/ldconfig + +vconftool set -t int memory/camera/state 0 -i -u 5000 +vconftool set -t int file/camera/shutter_sound_policy 0 -u 5000 %postun -p /sbin/ldconfig %files +%manifest libmm-camcorder.manifest %defattr(-,root,root,-) %{_bindir}/* %{_libdir}/*.so.* -%{_datadir}/edje/* /usr/share/sounds/mm-camcorder/* +%{_datadir}/license/%{name} %files devel +%manifest libmm-camcorder.manifest %defattr(-,root,root,-) %{_includedir}/mmf/mm_camcorder.h %{_libdir}/pkgconfig/mm-camcorder.pc diff --git a/sounds/capture_shutter_01.wav b/sounds/capture_shutter_01.wav index 3752fc4b9fc11f74fefe7b6485bd3e7da5fa14f7..cc46565aa7696285fde160e586f65180ed1aa50f 100644 GIT binary patch literal 22772 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 diff --git a/sounds/recording_stop_01.wav b/sounds/recording_stop_01.wav index 5f89edd80c68ea6c62c822dd2d279f65dde61332..0346d4a2fe46e7446bdc54df09404181773cc40d 100644 GIT binary patch delta 1421 zcmY+Ec}&xH0L8z*9>3njw$OvKQdEwDRmdxM>jJ`p|;8xu1v zzYhD7F3SJB9uUV;lK=$(U?nUBAAAbRfetXCKHv-VcpA3kn6W>x*E(eQEhvu~#Ta5G zu@5t0I2y3*7gk;@T`@!(pO_O+GdYY^x9Xa}%AexeXeWrrmMBA^?xFUvUT*S7-C;kM za91t6Vfjg0bi*axKEY2XRiT$7jxIhxf2r5B5u)7d- zL@7~1JRv%W1p*_kZ-`Pu&Pr$i1_WUubcCLufC%s-m;l?MBB&o)fZjlHP%7{uzQ-Oq zx)E<%y+vbgF;`d$Y?mBK#0PQ>y@(^>H@b<$WnwQ;pGxf^zKN@h{|Gn&r+SAB?Lu++BH5{FOFr3=6sWZJp+7&pk zePVb%6iKCh>BjU`%V|nM#O{bw%6j>O)nwNO%Ir$+Ov%8$wu?;*uR0ny&3oV3M)v9> zv25;r?_4=Oyl7irbmg|7@K$+(Pn}BypiclwK(Glu?5p zZF&}F3O%(!9Z=?7$@_(zX7-x9JaVe%QoFLXs_kXh^3WgCJB=N95*wB@%O-<{6lojJ zDb@!~`TB_)Sx<3|F+>wTV(2Y>SEKIS*^LY&Pv~^*mObPPEE%Nzme!Hie#{p*qgZu>LW%z57twz30B zm#lXd+-6RWg$(~XI5yNiDw>YemzaMeDj9S9zuj+2*?v~PMA=>+p(Kc>meBL@?dCy! z@64l#y3xqd&~f!twN_=ELOMuiSX%|xB#75$X@r#Us+Bw!9A+yh!;VFhMV~zT^Hlu@ z;bi`_er|Aa$ef8usVVFi{ClEycb2Ehqh6frI>L>lyF(QFd6RyjTFaPSr}3Wc(Q+0~ zn@SN6kO!x;6V*JsD^HXwiWlAy6uVqzwo`g=1~OtQHx%m)x+a}O-@W*J`5Wt9)B*`< z6|8udb{@v>;UD9@=7z8);6PFeHgDsa>C5z`Aj1U%vXo=$vQ*o9aU-b-W-+g_h1?=8 zpIgk1XC9$h$VWjxT7lpewt3D}YErJK@0x3^iS`{>6p)bbQ|oCF41&R8CNq5KM_?tT z4?0e)#eyC8kP@4ZO=;_~Eg-25U(AC41CEgz$?cRZY8CY~b%FvY^Q6C^9FRcl!ZWb< zXg>NQT8}ERKI|I4jc6hKKpcn#p+E}UoVWuYuo`#+u{YoY4q!M3NCqS)(EoAX=8#9! zzF5`4Fz0c`Cd7OayX(M5Y^UF-*q{h@YGb%FSH&C@Ix|&f#yP1f^GrsvG$u1EHANa3 Hq5$AOfX}+wH+l1?k>gM-Q5Wm^l+}` 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 diff --git a/src/Makefile.am b/src/Makefile.am index dfaa6ba..1b04dfd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -42,8 +42,11 @@ libmmfcamcorder_la_CFLAGS = -I$(srcdir)/include \ $(MM_COMMON_CFLAGS) \ $(MMSESSION_CFLAGS) \ $(MMSOUND_CFLAGS) \ + $(AVSYSTEM_CFLAGS) \ $(SNDFILE_CFLAGS) \ $(CAMSRCJPEGENC_CFLAGS) \ + $(VCONF_CFLAGS) \ + $(MMUTIL_IMGP_CFLAGS) \ $(AUDIOSESSIONMGR_CFLAGS) libmmfcamcorder_la_LIBADD = \ @@ -56,8 +59,11 @@ libmmfcamcorder_la_LIBADD = \ $(EXIF_LIBS) \ $(MMSESSION_LIBS) \ $(MMSOUND_LIBS) \ + $(AVSYSTEM_LIBS) \ $(SNDFILE_LIBS) \ $(CAMSRCJPEGENC_LIBS) \ + $(VCONF_LIBS) \ + $(MMUTIL_IMGP_LIBS) \ $(AUDIOSESSIONMGR_LIBS) libmmfcamcorder_la_CFLAGS += $(MMLOGSVR_CFLAGS) -DMMF_LOG_OWNER=0x010 -DMMF_DEBUG_PREFIX=\"MMF-CAMCORDER\" -D_INTERNAL_SESSION_MANAGER_ diff --git a/src/include/mm_camcorder.h b/src/include/mm_camcorder.h index a3f2f73..e078aa2 100644 --- a/src/include/mm_camcorder.h +++ b/src/include/mm_camcorder.h @@ -226,8 +226,8 @@ Audio device ID for capturing audio stream - #MMCAM_CAMERA_DEVICE - Video device ID for capturing video stream + #MMCAM_CAMERA_DEVICE_COUNT + Video device count #MMCAM_AUDIO_ENCODER @@ -351,6 +351,10 @@ Target filename. Only used in Audio/Video recording. This is not used for capturing. + #MMCAM_TARGET_MAX_SIZE + Maximum size of recording file(Kbyte). If the size of file reaches this value. + + #MMCAM_TARGET_TIME_LIMIT Time limit of recording file. If the elapsed time of recording reaches this value. @@ -629,10 +633,15 @@ extern "C" { #define MMCAM_AUDIO_DEVICE "audio-device" /** - * Video device ID for capturing video stream. - * @see MMVideoDeviceType (in mm_types.h) + * Video device count. */ -#define MMCAM_CAMERA_DEVICE "camera-device" +#define MMCAM_CAMERA_DEVICE_COUNT "camera-device-count" + +/** + * Facing direction of camera device. + * @see MMCamcorderCameraFacingDirection + */ +#define MMCAM_CAMERA_FACING_DIRECTION "camera-facing-direction" /** * Audio codec for encoding audio stream. @@ -680,6 +689,11 @@ extern "C" { #define MMCAM_AUDIO_VOLUME "audio-volume" /** + * Disable Audio stream when record. + */ +#define MMCAM_AUDIO_DISABLE "audio-disable" + +/** * Set audio input route * @remarks Deprecated. This will be removed soon. * @see MMAudioRoutePolicy (in mm_types.h) @@ -693,6 +707,21 @@ extern "C" { #define MMCAM_CAMERA_FORMAT "camera-format" /** + * Slow motion rate when video recording + * @remarks Deprecated + */ +#define MMCAM_CAMERA_SLOW_MOTION_RATE "camera-slow-motion-rate" + +/** + * Motion rate when video recording + * @remarks This should be bigger than 0(zero). + * Default value is 1 and it's for normal video recording. + * If the value is smaller than 1, recorded file will be played slower, + * otherwise, recorded file will be played faster. + */ +#define MMCAM_CAMERA_RECORDING_MOTION_RATE "camera-recording-motion-rate" + +/** * Frames per second. This is an integer field * */ @@ -800,6 +829,12 @@ extern "C" { #define MMCAM_CAMERA_ANTI_HANDSHAKE "camera-anti-handshake" /** + * Video Stabilization + * @see MMCamcorderVideoStabilizationMode + */ +#define MMCAM_CAMERA_VIDEO_STABILIZATION "camera-video-stabilization" + +/** * FPS Auto. When you set true to this attribute, FPS will vary depending on the amount of the light. */ #define MMCAM_CAMERA_FPS_AUTO "camera-fps-auto" @@ -811,6 +846,12 @@ extern "C" { #define MMCAM_CAMERA_ROTATION "camera-rotation" /** + * HDR(High Dynamic Range) Capture mode + * @see MMCamcorderHDRMode + */ +#define MMCAM_CAMERA_HDR_CAPTURE "camera-hdr-capture" + +/** * Bitrate of Audio Encoder */ #define MMCAM_AUDIO_ENCODER_BITRATE "audio-encoder-bitrate" @@ -904,6 +945,18 @@ extern "C" { #define MMCAM_CAPTURE_BREAK_CONTINUOUS_SHOT "capture-break-cont-shot" /** + * Raw data of captured image which resolution is same as preview. + * This is READ-ONLY attribute and only available in capture callback. + * This should be used after casted as MMCamcorderCaptureDataType. + */ +#define MMCAM_CAPTURED_SCREENNAIL "captured-screennail" + +/** + * Raw data of EXIF. This is READ-ONLY attribute and only available in capture callback. + */ +#define MMCAM_CAPTURED_EXIF_RAW_DATA "captured-exif-raw-data" + +/** * Pointer of display buffer or ID of xwindow. */ #define MMCAM_DISPLAY_HANDLE "display-handle" @@ -921,6 +974,12 @@ extern "C" { #define MMCAM_DISPLAY_SURFACE "display-surface" /** + * Mode of display. + * @see MMDisplayModeType (in mm_types.h) + */ +#define MMCAM_DISPLAY_MODE "display-mode" + +/** * X position of display rectangle. * This is only available when #MMCAM_DISPLAY_GEOMETRY_METHOD is MM_CAMCORDER_CUSTOM_ROI. * @see MMCamcorderGeometryMethod @@ -975,6 +1034,12 @@ extern "C" { #define MMCAM_DISPLAY_ROTATION "display-rotation" /** + * Flip of display. + * @see MMFlipType (in mm_types.h) + */ +#define MMCAM_DISPLAY_FLIP "display-flip" + +/** * Visible of display. */ #define MMCAM_DISPLAY_VISIBLE "display-visible" @@ -992,11 +1057,28 @@ extern "C" { #define MMCAM_DISPLAY_GEOMETRY_METHOD "display-geometry-method" /** + * A videosink name of evas surface. + * This is READ-ONLY attribute. + */ +#define MMCAM_DISPLAY_EVAS_SURFACE_SINK "display-evas-surface-sink" + +/** + * This attribute is only available if value of MMCAM_DISPLAY_EVAS_SURFACE_SINK "evaspixmapsink" + */ +#define MMCAM_DISPLAY_EVAS_DO_SCALING "display-evas-do-scaling" + +/** * Target filename. Only used in Audio/Video recording. This is not used for capturing. */ #define MMCAM_TARGET_FILENAME "target-filename" /** + * Maximum size(Kbyte) of recording file. If the size of file reaches this value, + * camcorder will send 'MM_MESSAGE_CAMCORDER_MAX_SIZE' message. + */ +#define MMCAM_TARGET_MAX_SIZE "target-max-size" + +/** * Time limit(Second) of recording file. If the elapsed time of recording reaches this value, * camcorder will send 'MM_MESSAGE_CAMCORDER_TIME_LIMIT' message. */ @@ -1087,9 +1169,46 @@ extern "C" { #define MMCAM_RECOMMEND_DISPLAY_ROTATION "recommend-display-rotation" /** - * Rotation angle of video input stream and display for video recording. + * Recommend width of camera preview. + * This attribute can be used with #mm_camcorder_get_attribute_info and #MMCamcorderPreviewType. + * @see mm_camcorder_get_attribute_info, MMCamcorderPreviewType */ -#define MMCAM_CAMCORDER_ROTATION "camcorder-rotation" +#define MMCAM_RECOMMEND_CAMERA_WIDTH "recommend-camera-width" + +/** + * Recommend height of camera preview + * This attribute can be used with #mm_camcorder_get_attribute_info and #MMCamcorderPreviewType. + * @see mm_camcorder_get_attribute_info, MMCamcorderPreviewType + */ +#define MMCAM_RECOMMEND_CAMERA_HEIGHT "recommend-camera-height" + +/** + * Flip of video input stream. + * @see MMFlipType (in mm_types.h) + */ +#define MMCAM_CAMERA_FLIP "camera-flip" + +/** + * X coordinate of Face zoom. + */ +#define MMCAM_CAMERA_FACE_ZOOM_X "camera-face-zoom-x" + +/** + * Y coordinate of Face zoom. + */ +#define MMCAM_CAMERA_FACE_ZOOM_Y "camera-face-zoom-y" + +/** + * Zoom level of Face zoom. + */ +#define MMCAM_CAMERA_FACE_ZOOM_LEVEL "camera-face-zoom-level" + +/** + * Mode of Face zoom. + * @see MMCamcorderFaceZoomMode + */ +#define MMCAM_CAMERA_FACE_ZOOM_MODE "camera-face-zoom-mode" + /*======================================================================================= | ENUM DEFINITIONS | @@ -1112,11 +1231,18 @@ typedef enum { * An enumeration for camcorder mode. */ typedef enum { - MM_CAMCORDER_MODE_IMAGE = 0, /**< Still image capture mode */ - MM_CAMCORDER_MODE_AUDIO, /**< Audio recording mode */ - MM_CAMCORDER_MODE_VIDEO, /**< Video recording mode */ + MM_CAMCORDER_MODE_VIDEO_CAPTURE = 0, /**< Video recording and Image capture mode */ + MM_CAMCORDER_MODE_AUDIO, /**< Audio recording mode */ } MMCamcorderModeType; +/** + * An enumeration for facing direction. + */ +typedef enum { + MM_CAMCORDER_CAMERA_FACING_DIRECTION_REAR = 0, /**< Facing direction of camera is REAR */ + MM_CAMCORDER_CAMERA_FACING_DIRECTION_FRONT, /**< Facing direction of camera is FRONT */ +} MMCamcorderCameraFacingDirection; + /** * An enumeration of Audio Format. @@ -1133,34 +1259,36 @@ typedef enum * seeing through a tinted glass. */ enum MMCamcorderColorToneType { - MM_CAMCORDER_COLOR_TONE_NONE = 0, /**< None */ - MM_CAMCORDER_COLOR_TONE_MONO, /**< Mono */ - MM_CAMCORDER_COLOR_TONE_SEPIA, /**< Sepia */ - MM_CAMCORDER_COLOR_TONE_NEGATIVE, /**< Negative */ - MM_CAMCORDER_COLOR_TONE_BLUE, /**< Blue */ - MM_CAMCORDER_COLOR_TONE_GREEN, /**< Green */ - MM_CAMCORDER_COLOR_TONE_AQUA, /**< Aqua */ - MM_CAMCORDER_COLOR_TONE_VIOLET, /**< Violet */ - MM_CAMCORDER_COLOR_TONE_ORANGE, /**< Orange */ - MM_CAMCORDER_COLOR_TONE_GRAY, /**< Gray */ - MM_CAMCORDER_COLOR_TONE_RED, /**< Red */ - MM_CAMCORDER_COLOR_TONE_ANTIQUE, /**< Antique */ - MM_CAMCORDER_COLOR_TONE_WARM, /**< Warm */ - MM_CAMCORDER_COLOR_TONE_PINK, /**< Pink */ - MM_CAMCORDER_COLOR_TONE_YELLOW, /**< Yellow */ - MM_CAMCORDER_COLOR_TONE_PURPLE, /**< Purple */ - MM_CAMCORDER_COLOR_TONE_EMBOSS, /**< Emboss */ - MM_CAMCORDER_COLOR_TONE_OUTLINE, /**< Outline */ - - MM_CAMCORDER_COLOR_TONE_SOLARIZATION_1, /**< Solarization1 */ - MM_CAMCORDER_COLOR_TONE_SOLARIZATION_2, /**< Solarization2 */ - MM_CAMCORDER_COLOR_TONE_SOLARIZATION_3, /**< Solarization3 */ - MM_CAMCORDER_COLOR_TONE_SOLARIZATION_4, /**< Solarization4 */ - - MM_CAMCORDER_COLOR_TONE_SKETCH_1, /**< Sketch1 */ - MM_CAMCORDER_COLOR_TONE_SKETCH_2, /**< Sketch2 */ - MM_CAMCORDER_COLOR_TONE_SKETCH_3, /**< Sketch3 */ - MM_CAMCORDER_COLOR_TONE_SKETCH_4, /**< Sketch4 */ + MM_CAMCORDER_COLOR_TONE_NONE = 0, /**< None */ + MM_CAMCORDER_COLOR_TONE_MONO, /**< Mono */ + MM_CAMCORDER_COLOR_TONE_SEPIA, /**< Sepia */ + MM_CAMCORDER_COLOR_TONE_NEGATIVE, /**< Negative */ + MM_CAMCORDER_COLOR_TONE_BLUE, /**< Blue */ + MM_CAMCORDER_COLOR_TONE_GREEN, /**< Green */ + MM_CAMCORDER_COLOR_TONE_AQUA, /**< Aqua */ + MM_CAMCORDER_COLOR_TONE_VIOLET, /**< Violet */ + MM_CAMCORDER_COLOR_TONE_ORANGE, /**< Orange */ + MM_CAMCORDER_COLOR_TONE_GRAY, /**< Gray */ + MM_CAMCORDER_COLOR_TONE_RED, /**< Red */ + MM_CAMCORDER_COLOR_TONE_ANTIQUE, /**< Antique */ + MM_CAMCORDER_COLOR_TONE_WARM, /**< Warm */ + MM_CAMCORDER_COLOR_TONE_PINK, /**< Pink */ + MM_CAMCORDER_COLOR_TONE_YELLOW, /**< Yellow */ + MM_CAMCORDER_COLOR_TONE_PURPLE, /**< Purple */ + MM_CAMCORDER_COLOR_TONE_EMBOSS, /**< Emboss */ + MM_CAMCORDER_COLOR_TONE_OUTLINE, /**< Outline */ + MM_CAMCORDER_COLOR_TONE_SOLARIZATION, /**< Solarization */ + MM_CAMCORDER_COLOR_TONE_SKETCH, /**< Sketch */ + MM_CAMCORDER_COLOR_TONE_WASHED, /**< Washed */ + MM_CAMCORDER_COLOR_TONE_VINTAGE_WARM, /**< Vintage warm */ + MM_CAMCORDER_COLOR_TONE_VINTAGE_COLD, /**< Vintage cold */ + MM_CAMCORDER_COLOR_TONE_POSTERIZATION, /**< Posterization */ + MM_CAMCORDER_COLOR_TONE_CARTOON, /**< Cartoon */ + MM_CAMCORDER_COLOR_TONE_SELECTIVE_RED, /**< Selective color - Red */ + MM_CAMCORDER_COLOR_TONE_SELECTIVE_GREEN, /**< Selective color - Green */ + MM_CAMCORDER_COLOR_TONE_SELECTIVE_BLUE, /**< Selective color - Blue */ + MM_CAMCORDER_COLOR_TONE_SELECTIVE_YELLOW, /**< Selective color - Yellow */ + MM_CAMCORDER_COLOR_TONE_SELECTIVE_RED_YELLOW, /**< Selective color - Red and Yellow */ }; @@ -1290,6 +1418,16 @@ enum MMCamcorderWDRMode { /** + * An enumeration for HDR capture mode + */ +enum MMCamcorderHDRMode { + MM_CAMCORDER_HDR_OFF = 0, /**< HDR OFF */ + MM_CAMCORDER_HDR_ON, /**< HDR ON and no original data - capture callback will be come once */ + MM_CAMCORDER_HDR_ON_AND_ORIGINAL, /**< HDR ON and original data - capture callback will be come twice(1st:Original, 2nd:HDR) */ +}; + + +/** * An enumeration for Anti-handshake mode . */ enum MMCamcorderAHSMode { @@ -1301,6 +1439,15 @@ enum MMCamcorderAHSMode { /** + * An enumeration for Video stabilization mode + */ +enum MMCamcorderVideoStabilizationMode { + MM_CAMCORDER_VIDEO_STABILIZATION_OFF = 0, /**< Video Stabilization OFF*/ + MM_CAMCORDER_VIDEO_STABILIZATION_ON, /**< Video Stabilization ON*/ +}; + + +/** * Geometry method for camcorder display. */ enum MMCamcorderGeometryMethod { @@ -1308,6 +1455,7 @@ enum MMCamcorderGeometryMethod { MM_CAMCORDER_ORIGIN_SIZE, /**< Origin size*/ MM_CAMCORDER_FULL, /**< full-screen*/ MM_CAMCORDER_CROPPED_FULL, /**< Cropped full-screen*/ + MM_CAMCORDER_ORIGIN_OR_LETTER, /**< Origin size or Letter box*/ MM_CAMCORDER_CUSTOM_ROI, /**< Explicitely described destination ROI*/ }; @@ -1362,6 +1510,23 @@ enum MMCamcorderDetectMode { }; +/** + * An enumeration for Face zoom mode. + */ +enum MMCamcorderFaceZoomMode { + MM_CAMCORDER_FACE_ZOOM_MODE_OFF = 0, /**< turn face zoom off */ + MM_CAMCORDER_FACE_ZOOM_MODE_ON, /**< turn face zoom on */ +}; + +/** + * An enumeration for recommended preview resolution. + */ +enum MMCamcorderPreviewType { + MM_CAMCORDER_PREVIEW_TYPE_NORMAL = 0, /**< normal ratio like 4:3 */ + MM_CAMCORDER_PREVIEW_TYPE_WIDE, /**< wide ratio like 16:9 */ +}; + + /********************************** * Attribute info * **********************************/ @@ -1374,8 +1539,6 @@ typedef enum{ MM_CAM_ATTRS_TYPE_DOUBLE, /**< Double type attribute */ MM_CAM_ATTRS_TYPE_STRING, /**< UTF-8 String type attribute */ MM_CAM_ATTRS_TYPE_DATA, /**< Pointer type attribute */ - MM_CAM_ATTRS_TYPE_ARRAY, /**< Array type attribute */ - MM_CAM_ATTRS_TYPE_RANGE, /**< Range type attribute */ }MMCamAttrsType; @@ -1404,6 +1567,21 @@ typedef enum { } MMCamAttrsFlag; +/********************************** +* Stream data * +**********************************/ +/** + * An enumeration for stream data type. + */ +typedef enum { + MM_CAM_STREAM_DATA_YUV420 = 0, /**< YUV420 Packed type - 1 plane */ + MM_CAM_STREAM_DATA_YUV422, /**< YUV422 Packed type - 1 plane */ + MM_CAM_STREAM_DATA_YUV420SP, /**< YUV420 SemiPlannar type - 2 planes */ + MM_CAM_STREAM_DATA_YUV420P, /**< YUV420 Plannar type - 3 planes */ + MM_CAM_STREAM_DATA_YUV422P, /**< YUV422 Plannar type - 3 planes */ +} MMCamStreamData; + + /*======================================================================================= | STRUCTURE DEFINITIONS | ========================================================================================*/ @@ -1478,12 +1656,33 @@ typedef struct { * Structure for video stream data. */ typedef struct { - void *data; /**< pointer of captured stream */ - unsigned int length; /**< length of stream buffer (in byte)*/ - MMPixelFormatType format; /**< image format */ - int width; /**< width of video buffer */ - int height; /**< height of video buffer */ - unsigned int timestamp; /**< timestamp of stream buffer (msec)*/ + union { + struct { + unsigned char *yuv; + unsigned int length_yuv; + } yuv420, yuv422; + struct { + unsigned char *y; + unsigned int length_y; + unsigned char *uv; + unsigned int length_uv; + } yuv420sp; + struct { + unsigned char *y; + unsigned int length_y; + unsigned char *u; + unsigned int length_u; + unsigned char *v; + unsigned int length_v; + } yuv420p, yuv422p; + } data; /**< pointer of captured stream */ + MMCamStreamData data_type; /**< data type */ + unsigned int length_total; /**< total length of stream buffer (in byte)*/ + unsigned int num_planes; /**< number of planes */ + MMPixelFormatType format; /**< image format */ + int width; /**< width of video buffer */ + int height; /**< height of video buffer */ + unsigned int timestamp; /**< timestamp of stream buffer (msec)*/ } MMCamcorderVideoStreamDataType; @@ -1514,9 +1713,27 @@ typedef struct { /** * Report structure of recording file */ -typedef struct MMCamRecordingReport { +typedef struct { char *recording_filename; /**< File name of stored recording file. Please free after using. */ -}MMCamRecordingReport; /**< report structure definition of recording file */ +} MMCamRecordingReport; /**< report structure definition of recording file */ + + +/** + * Face detect defailed information + */ +typedef struct _MMCamFaceInfo { + int id; /**< id of each face */ + int score; /**< score of each face */ + MMRectType rect; /**< area of face */ +} MMCamFaceInfo; + +/** + * Face detect information + */ +typedef struct _MMCamFaceDetectInfo { + int num_of_faces; /**< number of detected faces */ + MMCamFaceInfo *face_info; /**< face information, this should be freed after use it. */ +} MMCamFaceDetectInfo; /*======================================================================================= diff --git a/src/include/mm_camcorder_attribute.h b/src/include/mm_camcorder_attribute.h index 8a499e5..30b4cd8 100644 --- a/src/include/mm_camcorder_attribute.h +++ b/src/include/mm_camcorder_attribute.h @@ -57,7 +57,7 @@ typedef enum { MM_CAM_MODE, /* 0 */ MM_CAM_AUDIO_DEVICE, - MM_CAM_CAMERA_DEVICE, + MM_CAM_CAMERA_DEVICE_COUNT, MM_CAM_AUDIO_ENCODER, MM_CAM_VIDEO_ENCODER, MM_CAM_IMAGE_ENCODER, @@ -77,7 +77,7 @@ typedef enum MM_CAM_FILTER_HUE, MM_CAM_FILTER_SHARPNESS, /* 20 */ MM_CAM_CAMERA_FORMAT, - MM_CAM_CAMERA_SLOW_MOTION_FPS, + MM_CAM_CAMERA_RECORDING_MOTION_RATE, MM_CAM_CAMERA_FPS, MM_CAM_CAMERA_WIDTH, MM_CAM_CAMERA_HEIGHT, @@ -155,7 +155,22 @@ typedef enum MM_CAM_CAPTURED_SCREENNAIL, MM_CAM_CAPTURE_SOUND_ENABLE, MM_CAM_RECOMMEND_DISPLAY_ROTATION, - MM_CAM_CAMCORDER_ROTATION, /* 100 */ + MM_CAM_CAMERA_FLIP, /* 100 */ + MM_CAM_CAMERA_HDR_CAPTURE, + MM_CAM_DISPLAY_MODE, + MM_CAM_CAMERA_FACE_ZOOM_X, + MM_CAM_CAMERA_FACE_ZOOM_Y, + MM_CAM_CAMERA_FACE_ZOOM_LEVEL, + MM_CAM_CAMERA_FACE_ZOOM_MODE, + MM_CAM_AUDIO_DISABLE, + MM_CAM_RECOMMEND_CAMERA_WIDTH, + MM_CAM_RECOMMEND_CAMERA_HEIGHT, + MM_CAM_CAPTURED_EXIF_RAW_DATA, /* 110 */ + MM_CAM_DISPLAY_EVAS_SURFACE_SINK, + MM_CAM_DISPLAY_EVAS_DO_SCALING, + MM_CAM_CAMERA_FACING_DIRECTION, + MM_CAM_DISPLAY_FLIP, + MM_CAM_CAMERA_VIDEO_STABILIZATION, MM_CAM_NUM }MMCamcorderAttrsID; @@ -172,10 +187,15 @@ typedef struct { char *name; int value_type; int flags; - void* default_value; + union { + void *value_void; + char *value_string; + int value_int; + double value_double; + } default_value; /* default value */ MMCamAttrsValidType 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. */ + 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_cam_commit_func_t attr_commit; } mm_cam_attr_construct_info; @@ -296,9 +316,12 @@ bool _mmcamcorder_commit_capture_width(MMHandleType handle, int attr_idx, const bool _mmcamcorder_commit_capture_height(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_capture_break_cont_shot(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_capture_count(MMHandleType handle, int attr_idx, const mmf_value_t *value); +bool _mmcamcorder_commit_capture_sound_enable(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_audio_volume(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_audio_input_route(MMHandleType handle, int attr_idx, const mmf_value_t *value); +bool _mmcamcorder_commit_audio_disable(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_camera_fps(MMHandleType handle, int attr_idx, const mmf_value_t *value); +bool _mmcamcorder_commit_camera_recording_motion_rate(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_camera_width(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_camera_height(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_camera_zoom(MMHandleType handle, int attr_idx, const mmf_value_t *value); @@ -308,31 +331,34 @@ bool _mmcamcorder_commit_camera_af_touch_area(MMHandleType handle, int attr_idx, bool _mmcamcorder_commit_camera_capture_mode(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_camera_wdr(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_camera_anti_handshake(MMHandleType handle, int attr_idx, const mmf_value_t *value); +bool _mmcamcorder_commit_camera_video_stabilization(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_camera_hold_af_after_capturing(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_camera_rotate(MMHandleType handle, int attr_idx, const mmf_value_t *value); +bool _mmcamcorder_commit_camera_face_zoom(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_image_encoder_quality(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_target_filename(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_filter(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_filter_scene_mode(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_filter_flip(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_display_handle(MMHandleType handle, int attr_idx, const mmf_value_t *value); +bool _mmcamcorder_commit_display_mode(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_display_rotation(MMHandleType handle, int attr_idx, const mmf_value_t *value); +bool _mmcamcorder_commit_display_flip(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_display_visible(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_display_geometry_method(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_display_rect(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_display_scale(MMHandleType handle, int attr_idx, const mmf_value_t *value); +bool _mmcamcorder_commit_display_evas_do_scaling(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_strobe(MMHandleType handle, int attr_idx, const mmf_value_t *value); bool _mmcamcorder_commit_detect(MMHandleType handle, int attr_idx, const mmf_value_t *value); -bool _mmcamcorder_commit_camcorder_rotate(MMHandleType handle, int attr_idx, const mmf_value_t *value); +bool _mmcamcorder_commit_camera_flip(MMHandleType handle, int attr_idx, const mmf_value_t *value); +bool _mmcamcorder_commit_camera_hdr_capture(MMHandleType handle, int attr_idx, const mmf_value_t *value); /** * This function initialize effect setting. * * @param[in] handle Handle of camcorder. - * @return bool - * @remarks - * @see - * + * @return bool Success on TRUE or return FALSE */ bool _mmcamcorder_set_attribute_to_camsensor(MMHandleType handle); @@ -340,10 +366,7 @@ bool _mmcamcorder_set_attribute_to_camsensor(MMHandleType handle); * This function removes writable flag from pre-defined attributes. * * @param[in] handle Handle of camcorder. - * @return void - * @remarks - * @see - * + * @return int Success on MM_ERROR_NONE or return ERROR with error code */ int _mmcamcorder_lock_readonly_attributes(MMHandleType handle); @@ -351,13 +374,19 @@ int _mmcamcorder_lock_readonly_attributes(MMHandleType handle); * This function disable pre-defined attributes. * * @param[in] handle Handle of camcorder. - * @return void - * @remarks - * @see - * + * @return int Success on MM_ERROR_NONE or return ERROR with error code */ int _mmcamcorder_set_disabled_attributes(MMHandleType handle); +/** + * check whether supported or not + * + * @param[in] handle Handle of camcorder. + * @param[in] attr_index index of attribute to check. + * @return bool TRUE if supported or FALSE + */ +bool _mmcamcorder_check_supported_attribute(MMHandleType handle, int attr_index); + #ifdef __cplusplus } #endif diff --git a/src/include/mm_camcorder_audiorec.h b/src/include/mm_camcorder_audiorec.h index eb10677..6366fd2 100644 --- a/src/include/mm_camcorder_audiorec.h +++ b/src/include/mm_camcorder_audiorec.h @@ -45,6 +45,7 @@ typedef struct { gboolean b_commiting; /**< Is it commiting now? */ gboolean bMuxing; /**< whether muxing */ guint64 filesize; /**< current recorded file size */ + guint64 max_size; /**< max recording size */ guint64 max_time; /**< max recording time */ int fileformat; /**< recording file format */ } _MMCamcorderAudioInfo; diff --git a/src/include/mm_camcorder_gstcommon.h b/src/include/mm_camcorder_gstcommon.h index 7ba1605..eb33cab 100644 --- a/src/include/mm_camcorder_gstcommon.h +++ b/src/include/mm_camcorder_gstcommon.h @@ -46,7 +46,7 @@ extern "C" { /** * Enumerations for AMR bitrate */ -typedef enum MMCamcorderAMRBitRate { +typedef enum _MMCamcorderAMRBitRate { MM_CAMCORDER_MR475, /**< MR475 : 4.75 kbit/s */ MM_CAMCORDER_MR515, /**< MR515 : 5.15 kbit/s */ MM_CAMCORDER_MR59, /**< MR59 : 5.90 kbit/s */ @@ -58,6 +58,16 @@ typedef enum MMCamcorderAMRBitRate { MM_CAMCORDER_MRDTX /**< MRDTX */ } MMCamcorderAMRBitRate; +/** +* Encodebin profile +*/ +typedef enum _MMCamcorderEncodebinProfile { + MM_CAMCORDER_ENCBIN_PROFILE_VIDEO = 0, /**< Video recording profile */ + MM_CAMCORDER_ENCBIN_PROFILE_AUDIO, /**< Audio recording profile */ + MM_CAMCORDER_ENCBIN_PROFILE_IMAGE, /**< Image capture profile */ + MM_CAMCORDER_ENCBIN_PROFILE_NUM +} MMCamcorderEncodebinProfile; + /*======================================================================================= | STRUCTURE DEFINITIONS | ========================================================================================*/ @@ -130,11 +140,12 @@ int _mmcamcorder_create_videosink_bin(MMHandleType handle); * This function creates outputsink bin. * * @param[in] handle Handle of camcorder context. + * @param[in] profile profile of encodesinkbin. * @return This function returns MM_ERROR_NONE on success, or the other values on error. * @remarks * @see __mmcamcorder_create_preview_pipeline() */ -int _mmcamcorder_create_encodesink_bin(MMHandleType handle); +int _mmcamcorder_create_encodesink_bin(MMHandleType handle, MMCamcorderEncodebinProfile profile); /** * This function creates bin of still shot sink. @@ -165,8 +176,6 @@ int _mmcamcorder_create_preview_pipeline(MMHandleType handle); /* plug-in related */ void _mmcamcorder_negosig_handler(GstElement *videosrc, MMHandleType handle); -bool _mmcamcorder_set_display_rotation(MMHandleType handle, int display_rotate); -bool _mmcamcorder_set_videosrc_rotation(MMHandleType handle, int videosrc_rotate); /* etc */ int _mmcamcorder_videosink_window_set(MMHandleType handle, type_element *VideosinkElement); @@ -176,6 +185,12 @@ int _mmcamcorder_get_eos_message(MMHandleType handle); void _mmcamcorder_remove_element_handle(MMHandleType handle, int first_elem, int last_elem); int _mmcamcorder_check_audiocodec_fileformat_compatibility(MMHandleType handle); int _mmcamcorder_check_videocodec_fileformat_compatibility(MMHandleType handle); +bool _mmcamcorder_set_display_rotation(MMHandleType handle, int display_rotate); +bool _mmcamcorder_set_display_flip(MMHandleType handle, int display_flip); +bool _mmcamcorder_set_videosrc_rotation(MMHandleType handle, int videosrc_rotate); +bool _mmcamcorder_set_videosrc_flip(MMHandleType handle, int viderosrc_flip); +bool _mmcamcorder_set_videosrc_anti_shake(MMHandleType handle, int anti_shake); +bool _mmcamcorder_set_videosrc_stabilization(MMHandleType handle, int stabilization); #ifdef __cplusplus } diff --git a/src/include/mm_camcorder_internal.h b/src/include/mm_camcorder_internal.h index c887273..8819aac 100644 --- a/src/include/mm_camcorder_internal.h +++ b/src/include/mm_camcorder_internal.h @@ -22,7 +22,6 @@ #ifndef __MM_CAMCORDER_INTERNAL_H__ #define __MM_CAMCORDER_INTERNAL_H__ - /*======================================================================================= | INCLUDE FILES | ========================================================================================*/ @@ -38,6 +37,7 @@ #include #include #include +#include #include "mm_camcorder.h" #include "mm_debug.h" @@ -132,17 +132,34 @@ extern "C" { _mmcam_dbg_err("The element is existed. element_id=[%d], name=[%s]", eid, name); \ gst_object_unref(sub_context->element[eid].gst); \ } \ - sub_context->element[eid].id = eid; \ sub_context->element[eid].gst = gst_element_factory_make(name, nickname); \ if (sub_context->element[eid].gst == NULL) { \ _mmcam_dbg_err("Element creation fail. element_id=[%d], name=[%s]", eid, name); \ err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; \ goto pipeline_creation_error; \ } else { \ + _mmcam_dbg_log("Element creation done. element_id=[%d], name=[%s]", eid, name); \ + sub_context->element[eid].id = eid; \ g_object_weak_ref(G_OBJECT(sub_context->element[eid].gst), (GWeakNotify)_mmcamcorder_element_release_noti, sub_context); \ + err = MM_ERROR_NONE; \ } \ elist = g_list_append(elist, &(sub_context->element[eid])); +#define _MMCAMCORDER_ELEMENT_MAKE_IGNORE_ERROR(sub_context, eid, name /*char* */, nickname /*char* */, elist) \ + if (sub_context->element[eid].gst != NULL) { \ + _mmcam_dbg_err("The element is existed. element_id=[%d], name=[%s]", eid, name); \ + gst_object_unref(sub_context->element[eid].gst); \ + } \ + sub_context->element[eid].gst = gst_element_factory_make(name, nickname); \ + if (sub_context->element[eid].gst == NULL) { \ + _mmcam_dbg_err("Element creation fail. element_id=[%d], name=[%s], but keep going...", eid, name); \ + } else { \ + _mmcam_dbg_log("Element creation done. element_id=[%d], name=[%s]", eid, name); \ + sub_context->element[eid].id = eid; \ + g_object_weak_ref(G_OBJECT(sub_context->element[eid].gst), (GWeakNotify)_mmcamcorder_element_release_noti, sub_context); \ + elist = g_list_append(elist, &(sub_context->element[eid])); \ + } + #define _MMCAMCORDER_ENCODEBIN_ELMGET(sub_context, eid, name /*char* */, err) \ if (sub_context->element[eid].gst != NULL) { \ _mmcam_dbg_err("The element is existed. element_id=[%d], name=[%s]", eid, name); \ @@ -181,15 +198,33 @@ extern "C" { } #define _MM_GST_PAD_UNLINK_UNREF( srcpad, sinkpad) \ - gst_pad_unlink( srcpad, sinkpad ); \ - gst_object_unref( srcpad ); srcpad = NULL; \ - gst_object_unref( sinkpad ); sinkpad = NULL; + if (srcpad && sinkpad) { \ + gst_pad_unlink(srcpad, sinkpad); \ + } else { \ + _mmcam_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; \ + } #define _MMCAMCORDER_STATE_SET_COUNT 3 /* checking interval */ #define _MMCAMCORDER_STATE_CHECK_TOTALTIME 5000000L /* total wating time for state change */ #define _MMCAMCORDER_STATE_CHECK_INTERVAL 5000 /* checking interval */ /** + * Default videosink type + */ +#define _MMCAMCORDER_DEFAULT_VIDEOSINK_TYPE "VideosinkElementX" + +/** + * Default recording motion rate + */ +#define _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE 1.0 + +/** * Total level count of manual focus */ #define _MMFCAMCORDER_FOCUS_TOTAL_LEVEL 8 @@ -201,12 +236,22 @@ extern "C" { /** * Minimum integer value */ -#define _MMCAMCORDER_MIN_INT (-2147483648) +#define _MMCAMCORDER_MIN_INT (INT_MIN) /** * Maximum integer value */ -#define _MMCAMCORDER_MAX_INT (2147483647) +#define _MMCAMCORDER_MAX_INT (INT_MAX) + +/** + * Minimum double value + */ +#define _MMCAMCORDER_MIN_DOUBLE (DBL_MIN) + +/** + * Maximum integer value + */ +#define _MMCAMCORDER_MAX_DOUBLE (DBL_MAX) /** * Audio timestamp margin (msec) @@ -285,7 +330,7 @@ extern "C" { * If you increase any enum of attribute values, you also have to increase this. */ #define MM_CAMCORDER_MODE_NUM 3 /**< Number of mode type */ -#define MM_CAMCORDER_COLOR_TONE_NUM 27 /**< Number of color-tone modes */ +#define MM_CAMCORDER_COLOR_TONE_NUM 30 /**< Number of color-tone modes */ #define MM_CAMCORDER_WHITE_BALANCE_NUM 10 /**< Number of WhiteBalance modes*/ #define MM_CAMCORDER_SCENE_MODE_NUM 15 /**< Number of program-modes */ #define MM_CAMCORDER_FOCUS_MODE_NUM 6 /**< Number of focus mode*/ @@ -295,7 +340,9 @@ extern "C" { #define MM_CAMCORDER_AUTO_EXPOSURE_NUM 9 /**< Number of Auto exposure type */ #define MM_CAMCORDER_WDR_NUM 3 /**< Number of wide dynamic range */ #define MM_CAMCORDER_AHS_NUM 4 /**< Number of anti-handshake */ -#define MM_CAMCORDER_GEOMETRY_METHOD_NUM 4 /**< Number of geometry method */ +#define MM_CAMCORDER_VIDEO_STABILIZATION_NUM 2 /**< Number of video stabilization */ +#define MM_CAMCORDER_HDR_CAPTURE_NUM 3 /**< Number of HDR capture mode */ +#define MM_CAMCORDER_GEOMETRY_METHOD_NUM 5 /**< Number of geometry method */ #define MM_CAMCORDER_TAG_ORT_NUM 8 /**< Number of tag orientation */ #define MM_CAMCORDER_STROBE_MODE_NUM 8 /**< Number of strobe mode type */ #define MM_CAMCORDER_STROBE_CONTROL_NUM 3 /**< Number of strobe control type */ @@ -317,7 +364,6 @@ enum { /* Command for Image capture */ _MMCamcorder_CMD_CAPTURE, - _MMCamcorder_CMD_CAPTURE_CANCEL, /* Command for Preview(Video/Image only effective) */ _MMCamcorder_CMD_PREVIEW_START, @@ -356,6 +402,7 @@ typedef enum { _MMCAMCORDER_VIDEOSRC_BIN, _MMCAMCORDER_VIDEOSRC_SRC, _MMCAMCORDER_VIDEOSRC_FILT, + _MMCAMCORDER_VIDEOSRC_QUE, _MMCAMCORDER_VIDEOSRC_CLS, _MMCAMCORDER_VIDEOSRC_SCALE, _MMCAMCORDER_VIDEOSRC_VSFLT, @@ -443,7 +490,6 @@ typedef enum { } _MMCamcorderStateChange; - /*======================================================================================= | STRUCTURE DEFINITIONS | ========================================================================================*/ @@ -503,37 +549,41 @@ typedef struct { * MMCamcorder Sub Context */ typedef struct { - bool isMaxsizePausing; /**< Because of size limit, pipeline is paused. */ - bool isMaxtimePausing; /**< Because of time limit, pipeline is paused. */ - int element_num; /**< count of element */ - int cam_stability_count; /**< camsensor stability count. the count of frame will drop */ - GstClockTime pipeline_time; /**< current time of Gstreamer Pipeline */ - GstClockTime pause_time; /** amount of time while pipeline is in PAUSE state.*/ - GstClockTime stillshot_time; /** pipeline time of capturing moment*/ - gboolean is_slow; - gboolean error_occurs; - gboolean ferror_send; /** file write/seek error **/ - guint ferror_count; /** file write/seek error count **/ + bool isMaxsizePausing; /**< Because of size limit, pipeline is paused. */ + bool isMaxtimePausing; /**< Because of time limit, pipeline is paused. */ + int element_num; /**< count of element */ + int cam_stability_count; /**< camsensor stability count. the count of frame will drop */ + GstClockTime pipeline_time; /**< current time of Gstreamer Pipeline */ + GstClockTime pause_time; /**< amount of time while pipeline is in PAUSE state.*/ + GstClockTime stillshot_time; /**< pipeline time of capturing moment*/ + gboolean is_modified_rate; /**< whether recording motion rate is modified or not */ + 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 **/ GstClockTime previous_slot_time; - int display_interval; /** This value is set as 'GST_SECOND / display FPS' */ - gboolean bget_eos; /** Whether getting EOS */ - gboolean bencbin_capture; /** Use Encodebin for capturing */ - gboolean now_continuous_af; /** whether continuous af starts */ + int display_interval; /**< This value is set as 'GST_SECOND / display FPS' */ + gboolean bget_eos; /**< Whether getting EOS */ + gboolean bencbin_capture; /**< Use Encodebin for capturing */ + gboolean audio_disable; /**< whether audio is disabled or not when record */ + int videosrc_rotate; /**< rotate of videosrc */ /* For dropping video frame when start recording */ - int drop_vframe; /**< When this value is bigger than zero and pass_first_vframe is zero, MSL will drop video frame though cam_stability count is bigger then zero. */ - int pass_first_vframe; /**< When this value is bigger than zero, MSL won't drop video frame though "drop_vframe" is bigger then zero. */ + int drop_vframe; /**< When this value is bigger than zero and pass_first_vframe is zero, MSL will drop video frame though cam_stability count is bigger then zero. */ + int pass_first_vframe; /**< When this value is bigger than zero, MSL won't drop video frame though "drop_vframe" is bigger then zero. */ /* INI information */ - unsigned int fourcc; /**< Get fourcc value of camera INI file */ - void *info; /**< extra information for camcorder */ + unsigned int fourcc; /**< Get fourcc value of camera INI file */ + _MMCamcorderImageInfo *info_image; /**< extra information for image capture */ + _MMCamcorderVideoInfo *info_video; /**< extra information for video recording */ + _MMCamcorderAudioInfo *info_audio; /**< extra information for audio recording */ - _MMCamcorderGstElement *element; /**< array of Gstreamer element */ - _MMCamcorderKPIMeasure kpi; /**< information related with performance measurement */ + _MMCamcorderGstElement *element; /**< array of Gstreamer element */ + _MMCamcorderKPIMeasure kpi; /**< information related with performance measurement */ - type_element *VideosinkElement; /**< configure data of videosink element */ - gboolean SensorEncodedCapture; /**< whether camera sensor support encoded image capture */ - gboolean internal_encode; /**< whether use internal encoding function */ + type_element *VideosinkElement; /**< configure data of videosink element */ + gboolean SensorEncodedCapture; /**< whether camera sensor support encoded image capture */ + gboolean internal_encode; /**< whether use internal encoding function */ } _MMCamcorderSubContext; /** @@ -541,49 +591,54 @@ typedef struct { */ typedef struct mmf_camcorder { /* information */ - int type; /**< mmcamcorder_mode_type */ - int state; /**< state of camcorder */ - 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. */ + int type; /**< mmcamcorder_mode_type */ + int state; /**< state of camcorder */ + 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 */ + MMHandleType attributes; /**< Attribute handle */ _MMCamcorderSubContext *sub_context; /**< sub context */ - mm_exif_info_t *exif_info; /**< EXIF */ - 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 */ - camera_conf *conf_main; /**< Camera configure Main structure */ - camera_conf *conf_ctrl; /**< Camera configure Control structure */ - int asm_handle; /**< Audio session manager handle */ - guint pipeline_cb_event_id; /**< Event source ID of pipeline message callback */ - guint setting_event_id; /**< Event source ID of attributes setting to sensor */ - SOUND_INFO snd_info; /**< Sound handle for multishot capture */ + mm_exif_info_t *exif_info; /**< EXIF */ + 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 */ + camera_conf *conf_main; /**< Camera configure Main structure */ + camera_conf *conf_ctrl; /**< Camera configure Control structure */ + int asm_handle_sh; /**< Audio session manager handle of share session */ + int asm_handle_ex; /**< Audio session manager handle of exclusive session */ + guint pipeline_cb_event_id; /**< Event source ID of pipeline message callback */ + guint setting_event_id; /**< Event source ID of attributes setting to sensor */ + SOUND_INFO snd_info; /**< Sound handle for multishot capture */ /* callback handlers */ - MMMessageCallback msg_cb; /**< message callback */ - void *msg_cb_param; /**< message callback parameter */ - mm_camcorder_video_stream_callback vstream_cb; /**< Video stream callback */ - void *vstream_cb_param; /**< Video stream callback parameter */ - mm_camcorder_audio_stream_callback astream_cb; /**< Audio stream callback */ - void *astream_cb_param; /**< Audio stream callback parameter */ - mm_camcorder_video_capture_callback vcapture_cb; /**< Video capture callback */ - void *vcapture_cb_param; /**< Video capture callback parameter */ - int (*command)(MMHandleType, int); /**< camcorder's command */ + MMMessageCallback msg_cb; /**< message callback */ + void *msg_cb_param; /**< message callback parameter */ + mm_camcorder_video_stream_callback vstream_cb; /**< Video stream callback */ + void *vstream_cb_param; /**< Video stream callback parameter */ + mm_camcorder_audio_stream_callback astream_cb; /**< Audio stream callback */ + void *astream_cb_param; /**< Audio stream callback parameter */ + mm_camcorder_video_capture_callback vcapture_cb; /**< Video capture callback */ + void *vcapture_cb_param; /**< Video capture callback parameter */ + int (*command)(MMHandleType, int); /**< camcorder's command */ /* etc */ - _MMCamcorderMTSafe mtsafe; /**< Thread safe */ - _MMCamcorderCommand cmd; /**< information for command loop */ - int sync_state_change; /**< Change framework state synchronously */ + _MMCamcorderMTSafe mtsafe; /**< Thread safe */ + _MMCamcorderCommand cmd; /**< information for command loop */ + int sync_state_change; /**< Change framework state synchronously */ int quick_device_close; - int state_change_by_system; /**< MSL changes its state by itself because of system(ASM,MDM..) **/ - int asm_event_code; /**< event code of audio session manager */ - pthread_mutex_t sound_lock; /**< Capture sound mutex */ - pthread_cond_t sound_cond; /**< Capture sound cond */ - int use_zero_copy_format; /**< Whether use zero copy format for camera input */ + int state_change_by_system; /**< MSL changes its state by itself because of system(ASM,MDM..) **/ + int asm_event_code; /**< event code of audio session manager */ + pthread_mutex_t sound_lock; /**< Capture sound mutex */ + pthread_cond_t sound_cond; /**< Capture sound cond */ + int use_zero_copy_format; /**< Whether use zero copy format for camera input */ + int shutter_sound_policy; /**< shutter sound policy */ + + _MMCamcorderInfoConverting caminfo_convert[CAMINFO_CONVERT_NUM]; /**< converting structure of camera info */ + _MMCamcorderEnumConvert enum_conv[ENUM_CONVERT_NUM]; /**< enum converting list that is modified by ini info */ int reserved[4]; /**< reserved */ } mmf_camcorder_t; @@ -996,6 +1051,22 @@ int _mmcamcorder_set_functions(MMHandleType handle, int type); gboolean _mmcamcorder_pipeline_cb_message(GstBus *bus, GstMessage *message, gpointer data); /** + * This function is callback function of main pipeline. + * Once this function is registered with certain pipeline using gst_bus_set_sync_handler(), + * this callback will be called every time when there is upcomming message from pipeline. + * Basically, this function is used as sync 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 __mmcamcorder_create_preview_pipeline() + * + */ +GstBusSyncReply _mmcamcorder_pipeline_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data); + +/** * This function create main pipeline according to type. * * @param[in] handle Handle of camcorder context. diff --git a/src/include/mm_camcorder_platform.h b/src/include/mm_camcorder_platform.h index 171a9f4..a9c747b 100644 --- a/src/include/mm_camcorder_platform.h +++ b/src/include/mm_camcorder_platform.h @@ -142,6 +142,9 @@ extern "C" { */ #define _MMCAMCORDER_SENSOR_ENUM_NONE -255 +/* camera information related */ +#define CAMINFO_CONVERT_NUM 40 + /*======================================================================================= | ENUM DEFINITIONS | @@ -162,6 +165,21 @@ typedef enum { MM_CAMCONVERT_TYPE_USER, /* user define */ } MMCamConvertingType; +typedef enum { + ENUM_CONVERT_WHITE_BALANCE = 0, + ENUM_CONVERT_COLOR_TONE, + ENUM_CONVERT_ISO, + ENUM_CONVERT_PROGRAM_MODE, + ENUM_CONVERT_FOCUS_MODE, + ENUM_CONVERT_AF_RANGE, + ENUM_CONVERT_EXPOSURE_MODE, + ENUM_CONVERT_STROBE_MODE, + ENUM_CONVERT_WDR, + ENUM_CONVERT_ANTI_HAND_SHAKE, + ENUM_CONVERT_VIDEO_STABILIZATION, + ENUM_CONVERT_NUM +} MMCamConvertingEnum; + /*======================================================================================= | STRUCTURE DEFINITIONS | ========================================================================================*/ @@ -204,8 +222,8 @@ typedef struct { /*======================================================================================= | GLOBAL FUNCTION PROTOTYPES | ========================================================================================*/ -int _mmcamcorder_convert_msl_to_sensor(int attr_idx, int mslval); -int _mmcamcorder_convert_sensor_to_msl(int attr_idx, int sensval); +int _mmcamcorder_convert_msl_to_sensor(MMHandleType handle, int attr_idx, int mslval); +int _mmcamcorder_convert_sensor_to_msl(MMHandleType handle, int attr_idx, int sensval); int _mmcamcorder_set_converted_value(MMHandleType handle, _MMCamcorderEnumConvert *convert); int _mmcamcorder_init_convert_table(MMHandleType handle); diff --git a/src/include/mm_camcorder_sound.h b/src/include/mm_camcorder_sound.h index 199f27c..f193e5b 100644 --- a/src/include/mm_camcorder_sound.h +++ b/src/include/mm_camcorder_sound.h @@ -25,6 +25,7 @@ /*======================================================================================= | INCLUDE FILES | ========================================================================================*/ +#include #ifdef __cplusplus extern "C" { @@ -51,7 +52,6 @@ extern "C" { typedef enum { _MMCAMCORDER_SOUND_STATE_NONE, _MMCAMCORDER_SOUND_STATE_INIT, - _MMCAMCORDER_SOUND_STATE_PREPARE, _MMCAMCORDER_SOUND_STATE_PLAYING, } _MMCamcorderSoundState; @@ -62,21 +62,30 @@ typedef enum { * Structure of sound info */ typedef struct __SOUND_INFO { - SF_INFO sfinfo; - SNDFILE *infile; - short *pcm_buf; - int pcm_size; - char *filename; - + /* PCM */ MMSoundPcmHandle_t handle; + mm_sound_device_out active_out_backup; - int thread_run; - pthread_t thread; + /* mutex and cond */ pthread_mutex_t play_mutex; pthread_cond_t play_cond; pthread_mutex_t open_mutex; pthread_cond_t open_cond; - system_audio_route_t route_policy_backup; + + /* pulse audio */ + pa_threaded_mainloop *pulse_mainloop; + pa_context *pulse_context; + +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE + /* sound file */ + SF_INFO sfinfo; + SNDFILE *infile; + char *filename; + pa_stream *sample_stream; + pa_sample_spec sample_spec; + size_t sample_length; + pa_channel_map channel_map; +#endif _MMCamcorderSoundState state; } SOUND_INFO; @@ -89,11 +98,15 @@ typedef struct __SOUND_INFO { /*======================================================================================= | GLOBAL FUNCTION PROTOTYPES | ========================================================================================*/ +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE gboolean _mmcamcorder_sound_init(MMHandleType handle, char *filename); -gboolean _mmcamcorder_sound_prepare(MMHandleType handle); +#else /* _MMCAMCORDER_UPLOAD_SAMPLE */ +gboolean _mmcamcorder_sound_init(MMHandleType handle); +#endif /* _MMCAMCORDER_UPLOAD_SAMPLE */ gboolean _mmcamcorder_sound_play(MMHandleType handle); gboolean _mmcamcorder_sound_finalize(MMHandleType handle); +gboolean _mmcamcorder_sound_capture_play_cb(gpointer data); void _mmcamcorder_sound_solo_play(MMHandleType handle, const char *filepath, gboolean sync); #ifdef __cplusplus diff --git a/src/include/mm_camcorder_stillshot.h b/src/include/mm_camcorder_stillshot.h index 525237a..58525a8 100644 --- a/src/include/mm_camcorder_stillshot.h +++ b/src/include/mm_camcorder_stillshot.h @@ -43,10 +43,19 @@ extern "C" { #define _MMCAMCORDER_CAPTURE_STOP_CHECK_INTERVAL 5000 #define _MMCAMCORDER_CAPTURE_STOP_CHECK_COUNT 600 #define _MNOTE_VALUE_NONE 0 +#define _SOUND_STATUS_INIT -1 /*======================================================================================= | ENUM DEFINITIONS | ========================================================================================*/ +/** + * Enumeration for flip of fimcconvert + */ +enum { + FIMCCONVERT_FLIP_NONE = 0, + FIMCCONVERT_FLIP_VERTICAL, + FIMCCONVERT_FLIP_HORIZONTAL +}; /*======================================================================================= | STRUCTURE DEFINITIONS | @@ -66,6 +75,11 @@ typedef struct { int width; /**< Width of capture image */ int height; /**< Height of capture image */ int interval; /**< Capture interval */ + int preview_format; /**< Preview format */ + int hdr_capture_mode; /**< HDR Capture mode */ + gboolean sound_status; /**< sound status of system */ + unsigned int volume_level; /**< media volume level of system */ + gboolean played_capture_sound; /**< whether play capture sound when capture starts */ } _MMCamcorderImageInfo; /*======================================================================================= @@ -106,6 +120,15 @@ int _mmcamcorder_add_stillshot_pipeline(MMHandleType handle); int _mmcamcorder_remove_stillshot_pipeline(MMHandleType handle); /** + * This function connects capture signal. + * + * @param[in] handle Handle of camcorder context. + * @return This function returns MM_ERROR_NONE on success, or the other values on error. + * @remarks + */ +int _mmcamcorder_connect_capture_signal(MMHandleType handle); + +/** * This function destroy image pipeline. * * @param[in] handle Handle of camcorder context. @@ -114,18 +137,17 @@ int _mmcamcorder_remove_stillshot_pipeline(MMHandleType handle); * @see _mmcamcorder_destroy_pipeline() * */ -void _mmcamcorder_destroy_image_pipeline(MMHandleType handle); -int _mmcamcorder_image_command(MMHandleType handle, int command); +void _mmcamcorder_destroy_video_capture_pipeline(MMHandleType handle); +int _mmcamcorder_video_capture_command(MMHandleType handle, int command); int _mmcamcorder_set_resize_property(MMHandleType handle, int capture_width, int capture_height); /* Function for capture */ -int __mmcamcorder_set_exif_basic_info(MMHandleType handle); +int __mmcamcorder_set_exif_basic_info(MMHandleType handle, int image_width, int image_height); void __mmcamcorder_init_stillshot_info(MMHandleType handle); void __mmcamcorder_get_capture_data_from_buffer(MMCamcorderCaptureDataType *capture_data, int pixtype, GstBuffer *buffer); void __mmcamcorder_release_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType *dest); -gboolean __mmcamcorder_capture_save_exifinfo(MMHandleType handle, MMCamcorderCaptureDataType *original, MMCamcorderCaptureDataType *thumbnail); -gboolean __mmcamcorder_capture_send_msg(MMHandleType handle, int type, int count); -gboolean __mmcamcorder_set_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType *dest, MMCamcorderCaptureDataType *thumbnail); +int __mmcamcorder_capture_save_exifinfo(MMHandleType handle, MMCamcorderCaptureDataType *original, MMCamcorderCaptureDataType *thumbnail); +int __mmcamcorder_set_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType *dest, MMCamcorderCaptureDataType *thumbnail); #ifdef __cplusplus } diff --git a/src/include/mm_camcorder_util.h b/src/include/mm_camcorder_util.h index c9df689..284be2b 100644 --- a/src/include/mm_camcorder_util.h +++ b/src/include/mm_camcorder_util.h @@ -144,6 +144,16 @@ do { \ ((gchar)(((fourcc)>>16)&0xff)), \ ((gchar)(((fourcc)>>24)&0xff)) +#define MMCAM_SEND_MESSAGE(handle, msg_id, msg_code) \ +{\ + _MMCamcorderMsgItem msg;\ + msg.id = msg_id;\ + msg.param.code = msg_code;\ + _mmcam_dbg_log("msg id : %x, code : %x", msg_id, msg_code);\ + _mmcamcroder_send_message((MMHandleType)handle, &msg);\ +} + + /*======================================================================================= | ENUM DEFINITIONS | ========================================================================================*/ @@ -188,6 +198,59 @@ typedef struct { MMMessageParamType param; /**< message parameter */ } _MMCamcorderMsgItem; +/** + * Structure of zero copy image buffer + */ +#define SCMN_IMGB_MAX_PLANE (4) + +/* image buffer definition *************************************************** + + +------------------------------------------+ --- + | | ^ + | a[], p[] | | + | +---------------------------+ --- | | + | | | ^ | | + | |<---------- w[] ---------->| | | | + | | | | | | + | | | | + | | | h[] | e[] + | | | | + | | | | | | + | | | | | | + | | | v | | + | +---------------------------+ --- | | + | | v + +------------------------------------------+ --- + + |<----------------- s[] ------------------>| +*/ + +typedef struct +{ + /* width of each image plane */ + int w[SCMN_IMGB_MAX_PLANE]; + /* height of each image plane */ + int h[SCMN_IMGB_MAX_PLANE]; + /* stride of each image plane */ + int s[SCMN_IMGB_MAX_PLANE]; + /* elevation of each image plane */ + int e[SCMN_IMGB_MAX_PLANE]; + /* user space address of each image plane */ + void *a[SCMN_IMGB_MAX_PLANE]; + /* physical address of each image plane, if needs */ + void *p[SCMN_IMGB_MAX_PLANE]; + /* color space type of image */ + int cs; + /* left postion, if needs */ + int x; + /* top position, if needs */ + int y; + /* to align memory */ + int __dummy2; + /* arbitrary data */ + int data[16]; +} SCMN_IMGB; + /*======================================================================================= | CONSTANT DEFINITIONS | ========================================================================================*/ @@ -221,16 +284,20 @@ unsigned int _mmcamcorder_get_fourcc(int pixtype, int codectype, int use_zero_co gboolean _mmcamcorder_encode_jpeg(void *src_data, unsigned int src_width, unsigned int src_height, int src_format, unsigned int src_length, unsigned int jpeg_quality, void **result_data, unsigned int *result_length); +/* resize */ +gboolean _mmcamcorder_resize_frame(unsigned char *src_data, int src_width, int src_height, int src_length, int src_format, + unsigned char **dst_data, int *dst_width, int *dst_height, int *dst_length); /* Recording */ /* find top level tag only, do not use this function for finding sub level tags. tag_fourcc is Four-character-code (FOURCC) */ -gint _mmcamcorder_find_tag(FILE *f, guint32 tag_fourcc); +gint _mmcamcorder_find_tag(FILE *f, guint32 tag_fourcc, gboolean do_rewind); gint32 _mmcamcorder_double_to_fix(gdouble d_number); gboolean _mmcamcorder_update_size(FILE *f, gint64 prev_pos, gint64 curr_pos); gboolean _mmcamcorder_write_loci(FILE *f, _MMCamcorderLocationInfo info); gboolean _mmcamcorder_write_udta(FILE *f, _MMCamcorderLocationInfo info); -gulong _mmcamcorder_get_container_size(const guchar *size); +guint64 _mmcamcorder_get_container_size(const guchar *size); +gboolean _mmcamcorder_update_composition_matrix(FILE *f, int orientation); /* File system */ int _mmcamcorder_get_freespace(const gchar *path, guint64 *free_space); diff --git a/src/include/mm_camcorder_videorec.h b/src/include/mm_camcorder_videorec.h index e5018d5..dd78abe 100644 --- a/src/include/mm_camcorder_videorec.h +++ b/src/include/mm_camcorder_videorec.h @@ -52,10 +52,11 @@ extern "C" { typedef struct { gboolean b_commiting; /**< Is it commiting now? */ char *filename; /**< recorded filename */ - gint multiple_fps; /**< fps for high speed recording(slow motion recording) */ + double record_timestamp_ratio; /**< timestamp ratio of video recording for slow motion recording */ guint64 video_frame_count; /**< current video frame */ guint64 audio_frame_count; /**< current audio frame */ guint64 filesize; /**< current file size */ + guint64 max_size; /**< max recording size */ guint64 max_time; /**< max recording time */ int fileformat; /**< recording file format */ /* @@ -132,6 +133,7 @@ int _mmcamcorder_video_command(MMHandleType handle, int command); */ int _mmcamcorder_video_handle_eos(MMHandleType handle); + #ifdef __cplusplus } #endif diff --git a/src/mm_camcorder_attribute.c b/src/mm_camcorder_attribute.c index f9df6d7..15b9489 100644 --- a/src/mm_camcorder_attribute.c +++ b/src/mm_camcorder_attribute.c @@ -29,27 +29,18 @@ #include #include +/*----------------------------------------------------------------------- +| MACRO DEFINITIONS: | +-----------------------------------------------------------------------*/ +#define MMCAMCORDER_DEFAULT_CAMERA_WIDTH 640 +#define MMCAMCORDER_DEFAULT_CAMERA_HEIGHT 480 /*--------------------------------------------------------------------------------------- | GLOBAL VARIABLE DEFINITIONS for internal | ---------------------------------------------------------------------------------------*/ -int video_input_rotation[] = {MM_VIDEO_INPUT_ROTATION_NONE, - MM_VIDEO_INPUT_ROTATION_90, - MM_VIDEO_INPUT_ROTATION_180, - MM_VIDEO_INPUT_ROTATION_270, - MM_VIDEO_INPUT_ROTATION_FLIP_HORZ, - MM_VIDEO_INPUT_ROTATION_FLIP_VERT}; - int depth[] = {MM_CAMCORDER_AUDIO_FORMAT_PCM_U8, MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE}; -int rotation[] = {MM_DISPLAY_ROTATION_NONE, - MM_DISPLAY_ROTATION_90, - MM_DISPLAY_ROTATION_180, - MM_DISPLAY_ROTATION_270, - MM_DISPLAY_ROTATION_FLIP_HORZ, - MM_DISPLAY_ROTATION_FLIP_VERT}; - int visible_values[] = { 0, 1 }; /*0: off, 1:on*/ int strobe_mode[] = {MM_CAMCORDER_STROBE_MODE_OFF, @@ -75,6 +66,7 @@ int tag_orientation_values[] = 8, /*the 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.*/ }; + /* basic attributes' info */ mm_cam_attr_construct_info cam_attrs_const_info[] ={ //0 @@ -83,10 +75,10 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "mode", /* Name */ MMF_VALUE_TYPE_INT, /* Type */ MM_ATTRS_FLAG_RW, /* Flag */ - (void*)MM_CAMCORDER_MODE_IMAGE, /* Default value */ + {(void*)MM_CAMCORDER_MODE_VIDEO_CAPTURE}, /* Default value */ MM_ATTRS_VALID_TYPE_INT_RANGE, /* Validity type */ - MM_CAMCORDER_MODE_IMAGE, /* Validity val1 (min, *array,...) */ - MM_CAMCORDER_MODE_VIDEO, /* Validity val2 (max, count, ...) */ + MM_CAMCORDER_MODE_VIDEO_CAPTURE, /* Validity val1 (min, *array,...) */ + MM_CAMCORDER_MODE_AUDIO, /* Validity val2 (max, count, ...) */ NULL, /* Runtime setting function of the attribute */ }, // 1 @@ -95,7 +87,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "audio-device", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_AUDIO_DEVICE_MIC, + {(void*)MM_AUDIO_DEVICE_MIC}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, MM_AUDIO_DEVICE_NUM-1, @@ -103,14 +95,14 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ }, // 2 { - MM_CAM_CAMERA_DEVICE, - "camera-device", + MM_CAM_CAMERA_DEVICE_COUNT, + "camera-device-count", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_VIDEO_DEVICE_NONE, + {(void*)MM_VIDEO_DEVICE_NUM}, MM_ATTRS_VALID_TYPE_INT_RANGE, MM_VIDEO_DEVICE_NONE, - MM_VIDEO_DEVICE_NUM-1, + MM_VIDEO_DEVICE_NUM, NULL, }, // 3 @@ -119,7 +111,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "audio-encoder", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_AUDIO_CODEC_AMR, + {(void*)MM_AUDIO_CODEC_AMR}, MM_ATTRS_VALID_TYPE_INT_ARRAY, (int)NULL, 0, @@ -131,7 +123,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "video-encoder", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_VIDEO_CODEC_MPEG4, + {(void*)MM_VIDEO_CODEC_MPEG4}, MM_ATTRS_VALID_TYPE_INT_ARRAY, (int)NULL, 0, @@ -143,7 +135,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "image-encoder", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_IMAGE_CODEC_JPEG, + {(void*)MM_IMAGE_CODEC_JPEG}, MM_ATTRS_VALID_TYPE_INT_ARRAY, (int)NULL, 0, @@ -155,7 +147,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "file-format", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_FILE_FORMAT_MP4, + {(void*)MM_FILE_FORMAT_MP4}, MM_ATTRS_VALID_TYPE_INT_ARRAY, (int)NULL, 0, @@ -167,7 +159,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-device-name", MMF_VALUE_TYPE_STRING, MM_ATTRS_FLAG_RW, - (void*)NULL, + {(void*)NULL}, MM_ATTRS_VALID_TYPE_NONE, 0, 0, @@ -179,7 +171,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "audio-samplerate", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)8000, + {(void*)8000}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -191,7 +183,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "audio-format", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE, + {(void*)MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE}, MM_ATTRS_VALID_TYPE_INT_ARRAY, (int)depth, ARRAY_SIZE(depth), @@ -203,7 +195,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "audio-channel", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)2, + {(void*)2}, MM_ATTRS_VALID_TYPE_INT_RANGE, 1, 2, @@ -215,7 +207,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "audio-volume", MMF_VALUE_TYPE_DOUBLE, MM_ATTRS_FLAG_RW, - (void*)1, + {(void*)1}, MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, 0, 10.0, @@ -227,7 +219,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "audio-input-route", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_AUDIOROUTE_USE_EXTERNAL_SETTING, + {(void*)MM_AUDIOROUTE_USE_EXTERNAL_SETTING}, MM_ATTRS_VALID_TYPE_INT_RANGE, MM_AUDIOROUTE_USE_EXTERNAL_SETTING, MM_AUDIOROUTE_CAPTURE_STEREOMIC_ONLY, @@ -239,7 +231,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "filter-scene-mode", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -251,7 +243,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "filter-brightness", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)1, + {(void*)1}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -263,7 +255,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "filter-contrast", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -275,7 +267,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "filter-wb", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -287,7 +279,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "filter-color-tone", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -299,7 +291,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "filter-saturation", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -311,7 +303,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "filter-hue", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -323,7 +315,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "filter-sharpness", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -335,7 +327,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-format", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_PIXEL_FORMAT_YUYV, + {(void*)MM_PIXEL_FORMAT_YUYV}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -343,15 +335,15 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ }, //22 { - MM_CAM_CAMERA_SLOW_MOTION_FPS, - "camera-slow-motion-fps", - MMF_VALUE_TYPE_INT, + MM_CAM_CAMERA_RECORDING_MOTION_RATE, + "camera-recording-motion-rate", + MMF_VALUE_TYPE_DOUBLE, MM_ATTRS_FLAG_RW, - (void*)0, - MM_ATTRS_VALID_TYPE_INT_RANGE, + {(void*)1}, + MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, 0, _MMCAMCORDER_MAX_INT, - NULL, + _mmcamcorder_commit_camera_recording_motion_rate, }, //23 { @@ -359,7 +351,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-fps", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)30, + {(void*)30}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -371,7 +363,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-width", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)320, + {(void*)MMCAMCORDER_DEFAULT_CAMERA_WIDTH}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -383,7 +375,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-height", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)240, + {(void*)MMCAMCORDER_DEFAULT_CAMERA_HEIGHT}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -395,7 +387,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-digital-zoom", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)10, + {(void*)10}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -407,7 +399,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-optical-zoom", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -419,7 +411,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-focus-mode", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_CAMCORDER_FOCUS_MODE_NONE, + {(void*)MM_CAMCORDER_FOCUS_MODE_NONE}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -431,7 +423,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-af-scan-range", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -443,7 +435,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-exposure-mode", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -455,7 +447,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-exposure-value", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -467,7 +459,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-f-number", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -479,7 +471,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-shutter-speed", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -491,7 +483,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-iso", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -503,7 +495,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-wdr", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -515,7 +507,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-anti-handshake", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -527,7 +519,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-fps-auto", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)FALSE, + {(void*)FALSE}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, 1, @@ -539,7 +531,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-hold-af-after-capturing", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, 1, @@ -551,7 +543,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-delay-attr-setting", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)FALSE, + {(void*)FALSE}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, 1, @@ -563,7 +555,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "audio-encoder-bitrate", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -575,7 +567,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "video-encoder-bitrate", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -587,7 +579,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "image-encoder-quality", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)95, + {(void*)95}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -599,7 +591,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "capture-format", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_PIXEL_FORMAT_ENCODED, + {(void*)MM_PIXEL_FORMAT_ENCODED}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -611,7 +603,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "capture-width", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)1600, + {(void*)1600}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -623,7 +615,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "capture-height", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)1200, + {(void*)1200}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -635,7 +627,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "capture-count", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)1, + {(void*)1}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -647,7 +639,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "capture-interval", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -659,7 +651,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "capture-break-cont-shot", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)FALSE, + {(void*)FALSE}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, 1, @@ -671,7 +663,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-handle", MMF_VALUE_TYPE_DATA, MM_ATTRS_FLAG_RW, - (void*)NULL, + {(void*)NULL}, MM_ATTRS_VALID_TYPE_NONE, 0, 0, @@ -683,7 +675,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-device", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_DISPLAY_DEVICE_MAINLCD, + {(void*)MM_DISPLAY_DEVICE_MAINLCD}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -695,7 +687,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-surface", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_DISPLAY_SURFACE_X, + {(void*)MM_DISPLAY_SURFACE_X}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -707,7 +699,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-rect-x", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -719,7 +711,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-rect-y", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -731,7 +723,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-rect-width", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -743,7 +735,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-rect-height", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -755,7 +747,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-src-x", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -767,7 +759,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-src-y", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -779,7 +771,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-src-width", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -791,7 +783,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-src-height", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -803,10 +795,10 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-rotation", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_DISPLAY_ROTATION_NONE, - MM_ATTRS_VALID_TYPE_INT_ARRAY, - (int)rotation, - ARRAY_SIZE(rotation), + {(void*)MM_DISPLAY_ROTATION_NONE}, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_DISPLAY_ROTATION_NONE, + MM_DISPLAY_ROTATION_270, _mmcamcorder_commit_display_rotation, }, //61 @@ -815,7 +807,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-visible", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)1, + {(void*)1}, MM_ATTRS_VALID_TYPE_INT_ARRAY, (int)visible_values, ARRAY_SIZE(visible_values), @@ -827,7 +819,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-scale", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, MM_DISPLAY_SCALE_DEFAULT, MM_DISPLAY_SCALE_TRIPLE_LENGTH, @@ -839,7 +831,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "display-geometry-method", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, MM_DISPLAY_METHOD_LETTER_BOX, MM_DISPLAY_METHOD_CUSTOM_ROI, @@ -851,7 +843,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "target-filename", MMF_VALUE_TYPE_STRING, MM_ATTRS_FLAG_RW, - (void*)"/tmp/CAM-NONAME", + {(void*)"/tmp/CAM-NONAME"}, MM_ATTRS_VALID_TYPE_NONE, 0, 0, @@ -863,7 +855,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "target-max-size", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -875,7 +867,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "target-time-limit", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -887,8 +879,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "tag-enable", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, -// (void*)tag_enable_values[0], - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, 1, @@ -900,7 +891,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "tag-image-description", MMF_VALUE_TYPE_STRING, MM_ATTRS_FLAG_RW, - (void*)NULL, + {(void*)NULL}, MM_ATTRS_VALID_TYPE_NONE, 0, 0, @@ -912,8 +903,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "tag-orientation", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, -// (void*)tag_orientation_values[0], - (void*)1, + {(void*)1}, MM_ATTRS_VALID_TYPE_INT_ARRAY, (int)tag_orientation_values, ARRAY_SIZE(tag_orientation_values), @@ -925,7 +915,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "tag-software", MMF_VALUE_TYPE_STRING, MM_ATTRS_FLAG_RW, - (void*)NULL, + {(void*)NULL}, MM_ATTRS_VALID_TYPE_NONE, 0, 0, @@ -937,7 +927,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "tag-latitude", MMF_VALUE_TYPE_DOUBLE, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, -360, 360, @@ -949,7 +939,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "tag-longitude", MMF_VALUE_TYPE_DOUBLE, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, -360, 360, @@ -961,7 +951,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "tag-altitude", MMF_VALUE_TYPE_DOUBLE, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, -999999, 999999, @@ -973,7 +963,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "strobe-control", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -985,7 +975,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "strobe-capabilities", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -997,10 +987,10 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "strobe-mode", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, - (int)strobe_mode, - ARRAY_SIZE(strobe_mode), + 0, + 0, _mmcamcorder_commit_strobe, }, //77 @@ -1009,7 +999,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "detect-mode", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -1021,7 +1011,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "detect-number", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -1033,7 +1023,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "detect-focus-select", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -1045,7 +1035,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "detect-select-number", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, -1, @@ -1057,7 +1047,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "detect-status", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_ARRAY, 0, 0, @@ -1069,7 +1059,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "capture-zero-systemlag", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)FALSE, + {(void*)FALSE}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, 1, @@ -1081,7 +1071,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-af-touch-x", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -1093,7 +1083,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-af-touch-y", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -1105,7 +1095,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-af-touch-width", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -1117,7 +1107,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-af-touch-height", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, _MMCAMCORDER_MAX_INT, @@ -1129,7 +1119,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-focal-length", MMF_VALUE_TYPE_DOUBLE, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, 0, 1000, @@ -1141,10 +1131,10 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "recommend-preview-format-for-capture", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_PIXEL_FORMAT_YUYV, + {(void*)MM_PIXEL_FORMAT_YUYV}, MM_ATTRS_VALID_TYPE_INT_RANGE, MM_PIXEL_FORMAT_NV12, - MM_PIXEL_FORMAT_ENCODED, + MM_PIXEL_FORMAT_ITLV_JPEG_UYVY, NULL, }, //89 @@ -1153,10 +1143,10 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "recommend-preview-format-for-recording", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_PIXEL_FORMAT_NV12, + {(void*)MM_PIXEL_FORMAT_NV12}, MM_ATTRS_VALID_TYPE_INT_RANGE, MM_PIXEL_FORMAT_NV12, - MM_PIXEL_FORMAT_ENCODED, + MM_PIXEL_FORMAT_ITLV_JPEG_UYVY, NULL, }, //90 @@ -1165,7 +1155,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "capture-thumbnail", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)TRUE, + {(void*)TRUE}, MM_ATTRS_VALID_TYPE_NONE, 0, 0, @@ -1177,7 +1167,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "tag-gps-enable", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)TRUE, + {(void*)TRUE}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, 1, @@ -1189,7 +1179,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "tag-gps-time-stamp", MMF_VALUE_TYPE_DOUBLE, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_NONE, 0, 0, @@ -1201,7 +1191,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "tag-gps-date-stamp", MMF_VALUE_TYPE_STRING, MM_ATTRS_FLAG_RW, - NULL, + {(void*)NULL}, MM_ATTRS_VALID_TYPE_NONE, 0, 0, @@ -1213,7 +1203,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "tag-gps-processing-method", MMF_VALUE_TYPE_STRING, MM_ATTRS_FLAG_RW, - NULL, + {(void*)NULL}, MM_ATTRS_VALID_TYPE_NONE, 0, 0, @@ -1225,10 +1215,10 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "camera-rotation", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_VIDEO_INPUT_ROTATION_NONE, - MM_ATTRS_VALID_TYPE_INT_ARRAY, - (int)video_input_rotation, - ARRAY_SIZE(video_input_rotation), + {(void*)MM_VIDEO_INPUT_ROTATION_NONE}, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_VIDEO_INPUT_ROTATION_NONE, + MM_VIDEO_INPUT_ROTATION_270, _mmcamcorder_commit_camera_rotate, }, //96 @@ -1237,7 +1227,7 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "enable-converted-stream-callback", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)0, + {(void*)0}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, 1, @@ -1248,8 +1238,8 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ MM_CAM_CAPTURED_SCREENNAIL, "captured-screennail", MMF_VALUE_TYPE_DATA, - MM_ATTRS_FLAG_RW, - (void*)NULL, + MM_ATTRS_FLAG_READABLE, + {(void*)NULL}, MM_ATTRS_VALID_TYPE_NONE, 0, 0, @@ -1261,11 +1251,11 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "capture-sound-enable", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)FALSE, + {(void*)TRUE}, MM_ATTRS_VALID_TYPE_INT_RANGE, 0, 1, - NULL, + _mmcamcorder_commit_capture_sound_enable, }, //99 { @@ -1273,38 +1263,219 @@ mm_cam_attr_construct_info cam_attrs_const_info[] ={ "recommend-display-rotation", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_DISPLAY_ROTATION_270, + {(void*)MM_DISPLAY_ROTATION_270}, MM_ATTRS_VALID_TYPE_INT_RANGE, MM_DISPLAY_ROTATION_NONE, - MM_DISPLAY_ROTATION_FLIP_VERT, + MM_DISPLAY_ROTATION_270, NULL, }, //100 { - MM_CAM_CAMCORDER_ROTATION, - "camcorder-rotation", + MM_CAM_CAMERA_FLIP, + "camera-flip", MMF_VALUE_TYPE_INT, MM_ATTRS_FLAG_RW, - (void*)MM_VIDEO_INPUT_ROTATION_NONE, + {(void*)MM_FLIP_NONE}, MM_ATTRS_VALID_TYPE_INT_RANGE, - MM_VIDEO_INPUT_ROTATION_NONE, - MM_VIDEO_INPUT_ROTATION_270, - _mmcamcorder_commit_camcorder_rotate, + MM_FLIP_NONE, + MM_FLIP_BOTH, + _mmcamcorder_commit_camera_flip, + }, + //101 + { + MM_CAM_CAMERA_HDR_CAPTURE, + "camera-hdr-capture", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)FALSE}, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_hdr_capture, + }, + //102 + { + MM_CAM_DISPLAY_MODE, + "display-mode", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)MM_DISPLAY_MODE_DEFAULT}, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_display_mode, + }, + //103 + { + MM_CAM_CAMERA_FACE_ZOOM_X, + "camera-face-zoom-x", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)0}, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + _mmcamcorder_commit_camera_face_zoom, + }, + //104 + { + MM_CAM_CAMERA_FACE_ZOOM_Y, + "camera-face-zoom-y", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)0}, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + _mmcamcorder_commit_camera_face_zoom, + }, + //105 + { + MM_CAM_CAMERA_FACE_ZOOM_LEVEL, + "camera-face-zoom-level", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)0}, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + NULL, + }, + //106 + { + MM_CAM_CAMERA_FACE_ZOOM_MODE, + "camera-face-zoom-mode", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)FALSE}, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_face_zoom, + }, + //107 + { + MM_CAM_AUDIO_DISABLE, + "audio-disable", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)FALSE}, + MM_ATTRS_VALID_TYPE_INT_RANGE, + FALSE, + TRUE, + _mmcamcorder_commit_audio_disable, + }, + //108 + { + MM_CAM_RECOMMEND_CAMERA_WIDTH, + "recommend-camera-width", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)MMCAMCORDER_DEFAULT_CAMERA_WIDTH}, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + NULL, + }, + //109 + { + MM_CAM_RECOMMEND_CAMERA_HEIGHT, + "recommend-camera-height", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)MMCAMCORDER_DEFAULT_CAMERA_HEIGHT}, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + NULL, + }, + //110 + { + MM_CAM_CAPTURED_EXIF_RAW_DATA, + "captured-exif-raw-data", + MMF_VALUE_TYPE_DATA, + MM_ATTRS_FLAG_READABLE, + {(void*)NULL}, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0, + NULL, + }, + //111 + { + MM_CAM_DISPLAY_EVAS_SURFACE_SINK, + "display-evas-surface-sink", + MMF_VALUE_TYPE_STRING, + MM_ATTRS_FLAG_READABLE, + {(void*)NULL}, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0, + NULL, + }, + //112 + { + MM_CAM_DISPLAY_EVAS_DO_SCALING, + "display-evas-do-scaling", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)TRUE}, + MM_ATTRS_VALID_TYPE_INT_RANGE, + FALSE, + TRUE, + _mmcamcorder_commit_display_evas_do_scaling, + }, + //113 + { + MM_CAM_CAMERA_FACING_DIRECTION, + "camera-facing-direction", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)MM_CAMCORDER_CAMERA_FACING_DIRECTION_REAR}, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_CAMCORDER_CAMERA_FACING_DIRECTION_REAR, + MM_CAMCORDER_CAMERA_FACING_DIRECTION_FRONT, + NULL, }, + //114 + { + MM_CAM_DISPLAY_FLIP, + "display-flip", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)MM_FLIP_NONE}, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_FLIP_NONE, + MM_FLIP_BOTH, + _mmcamcorder_commit_display_flip, + }, + //115 + { + MM_CAM_CAMERA_VIDEO_STABILIZATION, + "camera-video-stabilization", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + {(void*)MM_CAMCORDER_VIDEO_STABILIZATION_OFF}, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_video_stabilization, + } }; -/*--------------------------------------------------------------------------- -| LOCAL VARIABLE DEFINITIONS for internal | ----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS for internal | +-----------------------------------------------------------------------*/ /* Readonly attributes list. * If you want to make some attributes read only, write down here. * It will make them read only after composing whole attributes. */ -static int readonly_attributes[] = { - MM_CAM_CAMERA_DEVICE, +static int readonly_attributes[] = { + MM_CAM_CAMERA_DEVICE_COUNT, MM_CAM_CAMERA_DEVICE_NAME, + MM_CAM_CAMERA_FACING_DIRECTION, MM_CAM_CAMERA_SHUTTER_SPEED, MM_CAM_RECOMMEND_PREVIEW_FORMAT_FOR_CAPTURE, MM_CAM_RECOMMEND_PREVIEW_FORMAT_FOR_RECORDING, @@ -1312,81 +1483,72 @@ static int readonly_attributes[] = { MM_CAM_RECOMMEND_DISPLAY_ROTATION, }; -/*--------------------------------------------------------------------------- -| LOCAL FUNCTION PROTOTYPES: | ----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +-----------------------------------------------------------------------*/ /* STATIC INTERNAL FUNCTION */ static bool __mmcamcorder_set_capture_resolution(MMHandleType handle, int width, int height); static bool __mmcamcorder_set_camera_resolution(MMHandleType handle, int width, int height); static int __mmcamcorder_set_conf_to_valid_info(MMHandleType handle); +static int __mmcamcorder_release_conf_valid_info(MMHandleType handle); static bool __mmcamcorder_attrs_is_supported(MMHandleType handle, int idx); static int __mmcamcorder_check_valid_pair(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list var_args); -/*=========================================================================================== -| | -| FUNCTION DEFINITIONS | -| | -========================================================================================== */ -/*--------------------------------------------------------------------------- -| GLOBAL FUNCTION DEFINITIONS: | ----------------------------------------------------------------------------*/ +/*======================================================================= +| FUNCTION DEFINITIONS | +=======================================================================*/ +/*----------------------------------------------------------------------- +| GLOBAL FUNCTION DEFINITIONS: | +-----------------------------------------------------------------------*/ MMHandleType _mmcamcorder_alloc_attribute( MMHandleType handle, MMCamPreset *info ) { _mmcam_dbg_log( "" ); MMHandleType attrs = 0; - mmf_attrs_construct_info_t * attrs_const_info = NULL; + mmf_attrs_construct_info_t *attrs_const_info = NULL; int attr_count = 0; int idx; - + /* Create attribute constructor */ - _mmcam_dbg_log( "start" ); - //set runtime values to 'cam_attrs_const_info' - { - cam_attrs_const_info[MM_CAM_CAMERA_DEVICE].default_value = (void*)info->videodev_type; - } + _mmcam_dbg_log("start"); - //alloc 'mmf_attrs_construct_info_t' - attr_count = ARRAY_SIZE( cam_attrs_const_info ); + /* alloc 'mmf_attrs_construct_info_t' */ + attr_count = ARRAY_SIZE(cam_attrs_const_info); attrs_const_info = malloc(attr_count * sizeof(mmf_attrs_construct_info_t)); - if (!attrs_const_info) - { - _mmcam_dbg_err( "Fail to alloc constructor." ); + if (!attrs_const_info) { + _mmcam_dbg_err("Fail to alloc constructor."); return 0; } - for (idx = 0; idx < attr_count; idx++) - { - //attribute order check. - if (idx != cam_attrs_const_info[idx].attrid) //This should be same. - { - _mmcam_dbg_err( "Please check attributes order. Is the idx same with enum val?" ); + for (idx = 0 ; idx < attr_count ; idx++) { + /* attribute order check. This should be same. */ + if (idx != cam_attrs_const_info[idx].attrid) { + _mmcam_dbg_err("Please check attributes order. Is the idx same with enum val?"); return 0; } attrs_const_info[idx].name = cam_attrs_const_info[idx].name; attrs_const_info[idx].value_type = cam_attrs_const_info[idx].value_type; attrs_const_info[idx].flags = cam_attrs_const_info[idx].flags; - attrs_const_info[idx].default_value = cam_attrs_const_info[idx].default_value; + attrs_const_info[idx].default_value = cam_attrs_const_info[idx].default_value.value_void; } /* Camcorder Attributes */ - _mmcam_dbg_log( "Create Camcorder Attributes[%p, %d]", attrs_const_info, attr_count); + _mmcam_dbg_log("Create Camcorder Attributes[%p, %d]", attrs_const_info, attr_count); - attrs = mmf_attrs_new_from_data( "Camcorder_Attributes", - attrs_const_info, - attr_count, - _mmcamcorder_commit_camcorder_attrs, - (void*)handle ); + attrs = mmf_attrs_new_from_data("Camcorder_Attributes", + attrs_const_info, + attr_count, + _mmcamcorder_commit_camcorder_attrs, + (void *)handle); free(attrs_const_info); attrs_const_info = NULL; - if( attrs == 0 ) - { - _mmcam_dbg_err( "Fail to alloc attribute handle" ); + if (attrs == 0) { + _mmcam_dbg_err("Fail to alloc attribute handle"); return 0; } @@ -1402,18 +1564,34 @@ _mmcamcorder_alloc_attribute( MMHandleType handle, MMCamPreset *info ) switch (cam_attrs_const_info[idx].validity_type) { case MM_ATTRS_VALID_TYPE_INT_ARRAY: - if ((cam_attrs_const_info[idx].validity_value1) &&(cam_attrs_const_info[idx].validity_value2 > 0)) - mmf_attrs_set_valid_array (attrs, idx, (const int*)(cam_attrs_const_info[idx].validity_value1), cam_attrs_const_info[idx].validity_value2); + if (cam_attrs_const_info[idx].validity_value1 && + cam_attrs_const_info[idx].validity_value2 > 0) { + mmf_attrs_set_valid_array(attrs, idx, + (const int *)(cam_attrs_const_info[idx].validity_value1), + cam_attrs_const_info[idx].validity_value2, + (int)(cam_attrs_const_info[idx].default_value.value_int)); + } break; case MM_ATTRS_VALID_TYPE_INT_RANGE: - mmf_attrs_set_valid_range (attrs, idx, cam_attrs_const_info[idx].validity_value1, cam_attrs_const_info[idx].validity_value2); + mmf_attrs_set_valid_range(attrs, idx, + cam_attrs_const_info[idx].validity_value1, + cam_attrs_const_info[idx].validity_value2, + (int)(cam_attrs_const_info[idx].default_value.value_int)); break; case MM_ATTRS_VALID_TYPE_DOUBLE_ARRAY: - if ((cam_attrs_const_info[idx].validity_value1) &&(cam_attrs_const_info[idx].validity_value2 > 0)) - mmf_attrs_set_valid_double_array (attrs, idx, (const double*)(cam_attrs_const_info[idx].validity_value1), cam_attrs_const_info[idx].validity_value2); + if (cam_attrs_const_info[idx].validity_value1 && + cam_attrs_const_info[idx].validity_value2 > 0) { + mmf_attrs_set_valid_double_array(attrs, idx, + (const double *)(cam_attrs_const_info[idx].validity_value1), + cam_attrs_const_info[idx].validity_value2, + (double)(cam_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)cam_attrs_const_info[idx].validity_value1, (double)cam_attrs_const_info[idx].validity_value2); + mmf_attrs_set_valid_double_range(attrs, idx, + (double)(cam_attrs_const_info[idx].validity_value1), + (double)(cam_attrs_const_info[idx].validity_value2), + (double)(cam_attrs_const_info[idx].default_value.value_double)); break; case MM_ATTRS_VALID_TYPE_NONE: break; @@ -1424,6 +1602,8 @@ _mmcamcorder_alloc_attribute( MMHandleType handle, MMCamPreset *info ) } } + __mmcamcorder_release_conf_valid_info(handle); + return attrs; } @@ -1454,7 +1634,7 @@ _mmcamcorder_get_attributes(MMHandleType handle, char **err_attr_name, const ch attrs = MMF_CAMCORDER_ATTRS(handle); mmf_return_val_if_fail( attrs, MM_ERROR_CAMCORDER_NOT_INITIALIZED ); - ret = mm_attrs_get_valist (attrs, err_attr_name, attribute_name, var_args); + ret = mm_attrs_get_valist(attrs, err_attr_name, attribute_name, var_args); return ret; } @@ -1476,9 +1656,8 @@ _mmcamcorder_set_attributes(MMHandleType handle, char **err_attr_name, const cha ret = __mmcamcorder_check_valid_pair( handle, err_attr_name, attribute_name, var_args ); ); - if( ret == MM_ERROR_NONE ) - { - ret = mm_attrs_set_valist (attrs, err_attr_name, attribute_name, var_args); + if (ret == MM_ERROR_NONE) { + ret = mm_attrs_set_valist(attrs, err_attr_name, attribute_name, var_args); } return ret; @@ -1496,7 +1675,7 @@ _mmcamcorder_get_attribute_info(MMHandleType handle, const char *attr_name, MMCa mmf_return_val_if_fail( attr_name, MM_ERROR_CAMCORDER_INVALID_ARGUMENT ); mmf_return_val_if_fail( info, MM_ERROR_CAMCORDER_INVALID_ARGUMENT ); - attrs = MMF_CAMCORDER_ATTRS(handle); + attrs = MMF_CAMCORDER_ATTRS(handle); mmf_return_val_if_fail( attrs, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); ret = mm_attrs_get_info_by_name(attrs, attr_name, (MMAttrsInfo*)&attrinfo); @@ -1513,22 +1692,22 @@ _mmcamcorder_get_attribute_info(MMHandleType handle, const char *attr_name, MMCa 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 = 0; + 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 = 0; + 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 = 0; + 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 = 0; + info->double_range.def = attrinfo.double_range.dval; break; case MM_ATTRS_VALID_TYPE_NONE: break; @@ -1592,10 +1771,8 @@ _mmcamcorder_commit_camcorder_attrs (int attr_idx, const char *attr_name, const } -int -__mmcamcorder_set_conf_to_valid_info(MMHandleType handle) +int __mmcamcorder_set_conf_to_valid_info(MMHandleType handle) { - //mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); int *format = NULL; int total_count = 0; @@ -1623,6 +1800,50 @@ __mmcamcorder_set_conf_to_valid_info(MMHandleType handle) } +int __mmcamcorder_release_conf_valid_info(MMHandleType handle) +{ + int *allocated_memory = NULL; + + _mmcam_dbg_log("START"); + + /* Audio encoder info */ + allocated_memory = (int*)(cam_attrs_const_info[MM_CAM_AUDIO_ENCODER].validity_value1); + if (allocated_memory) { + free(allocated_memory); + cam_attrs_const_info[MM_CAM_AUDIO_ENCODER].validity_value1 = (int)NULL; + cam_attrs_const_info[MM_CAM_AUDIO_ENCODER].validity_value2 = (int)0; + } + + /* Video encoder info */ + allocated_memory = (int*)(cam_attrs_const_info[MM_CAM_VIDEO_ENCODER].validity_value1); + if (allocated_memory) { + free(allocated_memory); + cam_attrs_const_info[MM_CAM_VIDEO_ENCODER].validity_value1 = (int)NULL; + cam_attrs_const_info[MM_CAM_VIDEO_ENCODER].validity_value2 = (int)0; + } + + /* Image encoder info */ + allocated_memory = (int*)(cam_attrs_const_info[MM_CAM_IMAGE_ENCODER].validity_value1); + if (allocated_memory) { + free(allocated_memory); + cam_attrs_const_info[MM_CAM_IMAGE_ENCODER].validity_value1 = (int)NULL; + cam_attrs_const_info[MM_CAM_IMAGE_ENCODER].validity_value2 = (int)0; + } + + /* File format info */ + allocated_memory = (int*)(cam_attrs_const_info[MM_CAM_FILE_FORMAT].validity_value1); + if (allocated_memory) { + free(allocated_memory); + cam_attrs_const_info[MM_CAM_FILE_FORMAT].validity_value1 = (int)NULL; + cam_attrs_const_info[MM_CAM_FILE_FORMAT].validity_value2 = (int)0; + } + + _mmcam_dbg_log("DONE"); + + return MM_ERROR_NONE; +} + + bool _mmcamcorder_commit_capture_width (MMHandleType handle, int attr_idx, const mmf_value_t *value) { MMHandleType attr = 0; @@ -1633,13 +1854,8 @@ bool _mmcamcorder_commit_capture_width (MMHandleType handle, int attr_idx, const _mmcam_dbg_log("(%d)", attr_idx); - current_state = _mmcamcorder_get_state( handle); - - if( !_mmcamcorder_is_state_changing(handle) - && ( current_state == MM_CAMCORDER_STATE_NULL - || current_state == MM_CAMCORDER_STATE_READY - || current_state == MM_CAMCORDER_STATE_PREPARE ) ) - { + current_state = _mmcamcorder_get_state(handle); + if (current_state <= MM_CAMCORDER_STATE_PREPARE) { int flags = MM_ATTRS_FLAG_NONE; int capture_width, capture_height; MMCamAttrsInfo info; @@ -1647,8 +1863,7 @@ bool _mmcamcorder_commit_capture_width (MMHandleType handle, int attr_idx, const mm_camcorder_get_attribute_info(handle, MMCAM_CAPTURE_HEIGHT, &info); flags = info.flag; - if (!(flags & MM_ATTRS_FLAG_MODIFIED)) - { + if (!(flags & MM_ATTRS_FLAG_MODIFIED)) { mm_camcorder_get_attributes(handle, NULL, MMCAM_CAPTURE_HEIGHT, &capture_height, NULL); capture_width = value->value.i_val; @@ -1657,9 +1872,7 @@ bool _mmcamcorder_commit_capture_width (MMHandleType handle, int attr_idx, const } return TRUE; - } - else - { + } else { _mmcam_dbg_log("Capture resolution can't be set.(state=%d)", current_state); return FALSE; } @@ -1670,22 +1883,18 @@ bool _mmcamcorder_commit_capture_height (MMHandleType handle, int attr_idx, cons { int current_state = MM_CAMCORDER_STATE_NONE; - current_state = _mmcamcorder_get_state( handle); + current_state = _mmcamcorder_get_state(handle); - if( current_state == MM_CAMCORDER_STATE_NULL - || current_state == MM_CAMCORDER_STATE_READY - || current_state == MM_CAMCORDER_STATE_PREPARE ) - { + if (current_state <= MM_CAMCORDER_STATE_PREPARE) { int capture_width, capture_height; mm_camcorder_get_attributes(handle, NULL, MMCAM_CAPTURE_WIDTH, &capture_width, NULL); capture_height = value->value.i_val; return __mmcamcorder_set_capture_resolution(handle, capture_width, capture_height); - } - else - { + } else { _mmcam_dbg_log("Capture resolution can't be set.(state=%d)", current_state); + return FALSE; } } @@ -1703,11 +1912,11 @@ bool _mmcamcorder_commit_capture_break_cont_shot (MMHandleType handle, int attr_ char* videosrc_name = NULL; - _mmcamcorder_conf_get_element( hcamcorder->conf_main, - CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, - "VideosrcElement", - &VideosrcElement ); - _mmcamcorder_conf_get_value_element_name( VideosrcElement, &videosrc_name ); + _mmcamcorder_conf_get_element(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, + "VideosrcElement", + &VideosrcElement ); + _mmcamcorder_conf_get_value_element_name(VideosrcElement, &videosrc_name); sc = MMF_CAMCORDER_SUBCONTEXT(handle); if (!sc) @@ -1743,41 +1952,48 @@ bool _mmcamcorder_commit_capture_break_cont_shot (MMHandleType handle, int attr_ } -bool _mmcamcorder_commit_capture_count (MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_capture_count(MMHandleType handle, int attr_idx, const mmf_value_t *value) { - int ret = FALSE; - int cap_count = 0; - int mode = MM_CAMCORDER_MODE_IMAGE; + int mode = MM_CAMCORDER_MODE_VIDEO_CAPTURE; + int current_state = MM_CAMCORDER_STATE_NONE; mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); mmf_return_val_if_fail(hcamcorder, FALSE); - cap_count = value->value.i_val; - + current_state = _mmcamcorder_get_state(handle); mm_camcorder_get_attributes(handle, NULL, MMCAM_MODE, &mode, NULL); - if (mode == MM_CAMCORDER_MODE_IMAGE) { - if (cap_count > 1) { - __ta__("_mmcamcorder_sound_init", - ret = _mmcamcorder_sound_init(handle, _MMCAMCORDER_FILEPATH_CAPTURE2_SND); - ); - if (ret == TRUE) { - __ta__("_mmcamcorder_sound_prepare", - ret = _mmcamcorder_sound_prepare(handle); - ); - _mmcam_dbg_log("sound prepare [%d]", ret); - } - } else if (cap_count == 1) { - __ta__("_mmcamcorder_sound_finalize", - ret = _mmcamcorder_sound_finalize(handle); - ); - _mmcam_dbg_log("sound finalize [%d]", ret); - } + + _mmcam_dbg_log("current state %d, mode %d, set count %d", + current_state, mode, value->value.i_val); + + if (mode != MM_CAMCORDER_MODE_AUDIO && + current_state != MM_CAMCORDER_STATE_CAPTURING) { + return TRUE; + } else { + _mmcam_dbg_err("Invalid mode[%d] or state[%d]", mode, current_state); + return FALSE; } +} - _mmcam_dbg_log("Capture Count(%d)", cap_count); - return TRUE; +bool _mmcamcorder_commit_capture_sound_enable(MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + mmf_return_val_if_fail(hcamcorder, FALSE); + + _mmcam_dbg_log("shutter sound policy: %d", hcamcorder->shutter_sound_policy); + + /* return error when disable shutter sound if policy is TRUE */ + if (!value->value.i_val && + hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON) { + _mmcam_dbg_err("not permitted DISABLE SHUTTER SOUND"); + return FALSE; + } else { + _mmcam_dbg_log("set value [%d] success", value->value.i_val); + return TRUE; + } } @@ -1812,7 +2028,7 @@ bool _mmcamcorder_commit_audio_volume (MMHandleType handle, int attr_idx, const MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_AUDIOSRC_VOL].gst, "volume", mslNewVal); } } - + _mmcam_dbg_log("Commit : volume(%f)", mslNewVal); bret = TRUE; } @@ -1821,8 +2037,8 @@ bool _mmcamcorder_commit_audio_volume (MMHandleType handle, int attr_idx, const _mmcam_dbg_log("Commit : nothing to commit. status(%d)", current_state); bret = TRUE; } - return bret; + return bret; } @@ -1833,6 +2049,41 @@ bool _mmcamcorder_commit_camera_fps (MMHandleType handle, int attr_idx, const mm } +bool _mmcamcorder_commit_camera_recording_motion_rate(MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + int current_state = MM_CAMCORDER_STATE_NONE; + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(handle, TRUE); + + current_state = _mmcamcorder_get_state(handle); + + if (current_state > MM_CAMCORDER_STATE_PREPARE) { + _mmcam_dbg_warn("invalid state %d", current_state); + return FALSE; + } + + /* Verify recording motion rate */ + if (value->value.d_val > 0.0) { + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, TRUE); + + /* set is_slow flag */ + if (value->value.d_val != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) { + sc->is_modified_rate = TRUE; + } else { + sc->is_modified_rate = FALSE; + } + + _mmcam_dbg_log("Set slow motion rate %lf", value->value.d_val); + return TRUE; + } else { + _mmcam_dbg_warn("Failed to set recording motion rate %lf", value->value.d_val); + return FALSE; + } +} + + bool _mmcamcorder_commit_camera_width (MMHandleType handle, int attr_idx, const mmf_value_t *value) { MMHandleType attr = 0; @@ -1844,9 +2095,9 @@ bool _mmcamcorder_commit_camera_width (MMHandleType handle, int attr_idx, const _mmcam_dbg_log("Width(%d)", value->value.i_val); - current_state = _mmcamcorder_get_state( handle); + current_state = _mmcamcorder_get_state(handle); - if ((current_state > MM_CAMCORDER_STATE_READY) || _mmcamcorder_is_state_changing( handle ) ) { + if (current_state > MM_CAMCORDER_STATE_READY) { _mmcam_dbg_log("Resolution can't be changed.(state=%d)", current_state); return FALSE; } else { @@ -1879,7 +2130,7 @@ bool _mmcamcorder_commit_camera_height (MMHandleType handle, int attr_idx, const _mmcam_dbg_log("Height(%d)", value->value.i_val); current_state = _mmcamcorder_get_state( handle); - if ( (current_state > MM_CAMCORDER_STATE_READY) || _mmcamcorder_is_state_changing( handle )) { + if (current_state > MM_CAMCORDER_STATE_READY) { _mmcam_dbg_log("Resolution can't be changed.(state=%d)", current_state); return FALSE; } else { @@ -1961,9 +2212,14 @@ bool _mmcamcorder_commit_camera_focus_mode (MMHandleType handle, int attr_idx, c _mmcam_dbg_log("Focus mode(%d)", value->value.i_val); - current_state = _mmcamcorder_get_state( handle); + /* check whether set or not */ + if (!_mmcamcorder_check_supported_attribute(handle, attr_idx)) { + _mmcam_dbg_log("skip set value %d", value->value.i_val); + return TRUE; + } - if (current_state < MM_CAMCORDER_STATE_READY) { + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_NULL) { _mmcam_dbg_log("Focus mode will be changed later.(state=%d)", current_state); return TRUE; } @@ -1976,13 +2232,13 @@ bool _mmcamcorder_commit_camera_focus_mode (MMHandleType handle, int attr_idx, c if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { _mmcam_dbg_log("Can't cast Video source into camera control."); - return TRUE; + return TRUE; } - + control = GST_CAMERA_CONTROL (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); mslVal = value->value.i_val; - mode = _mmcamcorder_convert_msl_to_sensor( attr_idx, mslVal ); + mode = _mmcamcorder_convert_msl_to_sensor( handle, attr_idx, mslVal ); mm_camcorder_get_attribute_info(handle, MMCAM_CAMERA_AF_SCAN_RANGE, &info); flags = info.flag; @@ -1997,7 +2253,7 @@ bool _mmcamcorder_commit_camera_focus_mode (MMHandleType handle, int attr_idx, c if( gst_camera_control_set_focus( control, mode, cur_focus_range ) ) { MMTA_ACUM_ITEM_END(" gst_camera_control_set_focus", 0); - //_mmcam_dbg_log( "Succeed in setting AF mode[%d]", mslVal ); + _mmcam_dbg_log( "Succeed in setting AF mode[%d]", mslVal ); return TRUE; } else @@ -2008,7 +2264,7 @@ bool _mmcamcorder_commit_camera_focus_mode (MMHandleType handle, int attr_idx, c } else { - //_mmcam_dbg_log( "No need to set AF mode. Current[%d]", mslVal ); + _mmcam_dbg_log( "No need to set AF mode. Current[%d]", mslVal ); return TRUE; } } @@ -2043,13 +2299,17 @@ bool _mmcamcorder_commit_camera_af_scan_range (MMHandleType handle, int attr_idx _mmcam_dbg_log("(%d)", attr_idx); - current_state = _mmcamcorder_get_state( handle); + /* check whether set or not */ + if (!_mmcamcorder_check_supported_attribute(handle, attr_idx)) { + _mmcam_dbg_log("skip set value %d", value->value.i_val); + return TRUE; + } mslVal = value->value.i_val; - newVal = _mmcamcorder_convert_msl_to_sensor( attr_idx, mslVal ); + newVal = _mmcamcorder_convert_msl_to_sensor(handle, attr_idx, mslVal); - if( current_state < MM_CAMCORDER_STATE_PREPARE ) - { + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_PREPARE) { _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); return TRUE; } @@ -2059,13 +2319,13 @@ bool _mmcamcorder_commit_camera_af_scan_range (MMHandleType handle, int attr_idx if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { _mmcam_dbg_log("Can't cast Video source into camera control."); - return TRUE; + return TRUE; } - + control = GST_CAMERA_CONTROL (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); mm_camcorder_get_attributes(handle, NULL, MMCAM_CAMERA_FOCUS_MODE, &msl_mode, NULL); - converted_mode = _mmcamcorder_convert_msl_to_sensor( MM_CAM_CAMERA_FOCUS_MODE, msl_mode ); + converted_mode = _mmcamcorder_convert_msl_to_sensor( handle, MM_CAM_CAMERA_FOCUS_MODE, msl_mode ); if( gst_camera_control_get_focus( control, &cur_focus_mode, &cur_focus_range ) ) { @@ -2276,7 +2536,6 @@ bool _mmcamcorder_commit_camera_capture_mode (MMHandleType handle, int attr_idx, int ivalue = value->value.i_val; int mslVal1 = 0, mslVal2 = 0; int newVal1 = 0, newVal2 = 0; - int cur_value1 = 0, cur_value2 = 0; int exposure_type = 0; int current_state = MM_CAMCORDER_STATE_NONE; _MMCamcorderSubContext *sc = NULL; @@ -2288,8 +2547,13 @@ bool _mmcamcorder_commit_camera_capture_mode (MMHandleType handle, int attr_idx, if (!sc) return TRUE; - current_state = _mmcamcorder_get_state( handle); + /* check whether set or not */ + if (!_mmcamcorder_check_supported_attribute(handle, attr_idx)) { + _mmcam_dbg_log("skip set value %d", value->value.i_val); + return TRUE; + } + current_state = _mmcamcorder_get_state( handle); if (current_state < MM_CAMCORDER_STATE_READY) { return TRUE; } @@ -2305,16 +2569,17 @@ bool _mmcamcorder_commit_camera_capture_mode (MMHandleType handle, int attr_idx, } else if (attr_idx == MM_CAM_CAMERA_ISO) { exposure_type = GST_CAMERA_CONTROL_ISO; mslVal1 = ivalue; - newVal1 = _mmcamcorder_convert_msl_to_sensor(attr_idx, mslVal1); + newVal1 = _mmcamcorder_convert_msl_to_sensor(handle, attr_idx, mslVal1); check_scene_mode = TRUE; } else if (attr_idx == MM_CAM_CAMERA_EXPOSURE_MODE) { exposure_type = GST_CAMERA_CONTROL_EXPOSURE_MODE; mslVal1 = ivalue; - newVal1 = _mmcamcorder_convert_msl_to_sensor(attr_idx, mslVal1); + newVal1 = _mmcamcorder_convert_msl_to_sensor(handle, attr_idx, mslVal1); + check_scene_mode = TRUE; } else if (attr_idx == MM_CAM_CAMERA_EXPOSURE_VALUE) { exposure_type = GST_CAMERA_CONTROL_EXPOSURE_VALUE; mslVal1 = newVal1 = MM_CAMCORDER_GET_NUMERATOR( ivalue ); - mslVal2 = newVal2 = MM_CAMCORDER_GET_DENOMINATOR( ivalue ); + mslVal2 = newVal2 = MM_CAMCORDER_GET_DENOMINATOR( ivalue ); } if (check_scene_mode) { @@ -2326,31 +2591,23 @@ bool _mmcamcorder_commit_camera_capture_mode (MMHandleType handle, int attr_idx, } if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) { + int ret = 0; + if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { _mmcam_dbg_log("Can't cast Video source into camera control."); - return TRUE; + return TRUE; } control = GST_CAMERA_CONTROL (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); - if (gst_camera_control_get_exposure(control, exposure_type, &cur_value1, &cur_value2)) { - if (newVal1 != cur_value1 || newVal2 != cur_value2) { - int ret = 0; - __ta__(" gst_camera_control_set_exposure", - ret = gst_camera_control_set_exposure(control, exposure_type, newVal1, newVal2); - ); - if (ret) { - //_mmcam_dbg_log( "Succeed in setting exposure. Type[%d],value1[%d],value2[%d]", exposure_type, mslVal1, mslVal2 ); - return TRUE; - } else { - _mmcam_dbg_warn( "Failed to set exposure. Type[%d],value1[%d],value2[%d]", exposure_type, mslVal1, mslVal2 ); - } - } else { - //_mmcam_dbg_log( "No need to set exposure. Type[%d],value1[%d],value2[%d]", exposure_type, mslVal1, mslVal2 ); - return TRUE; - } + __ta__(" gst_camera_control_set_exposure", + ret = gst_camera_control_set_exposure(control, exposure_type, newVal1, newVal2); + ); + if (ret) { + _mmcam_dbg_log("Succeed in setting exposure. Type[%d],value1[%d],value2[%d]", exposure_type, mslVal1, mslVal2 ); + return TRUE; } else { - _mmcam_dbg_warn( "Failed to get exposure. Type[%d]", exposure_type ); + _mmcam_dbg_warn("Failed to set exposure. Type[%d],value1[%d],value2[%d]", exposure_type, mslVal1, mslVal2 ); } } else { _mmcam_dbg_log("pointer of video src is null"); @@ -2363,60 +2620,61 @@ bool _mmcamcorder_commit_camera_capture_mode (MMHandleType handle, int attr_idx, bool _mmcamcorder_commit_camera_wdr (MMHandleType handle, int attr_idx, const mmf_value_t *value) { GstCameraControl *control = NULL; - int mslVal = value->value.i_val; - int newVal = _mmcamcorder_convert_msl_to_sensor( MM_CAM_CAMERA_WDR, mslVal); + int mslVal = 0; + int newVal = 0; int cur_value = 0; _MMCamcorderSubContext *sc = NULL; int current_state = MM_CAMCORDER_STATE_NONE; - sc = MMF_CAMCORDER_SUBCONTEXT(handle); - if (!sc) + mmf_return_val_if_fail(handle && value, FALSE); + + /* check whether set or not */ + if (!_mmcamcorder_check_supported_attribute(handle, attr_idx)) { + _mmcam_dbg_log("skip set value %d", value->value.i_val); return TRUE; + } + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, TRUE); + /* check current state */ current_state = _mmcamcorder_get_state( handle); - if (current_state < MM_CAMCORDER_STATE_PREPARE) { _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); return TRUE; - } + } - if( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst ) - { - if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) - { + if (current_state == MM_CAMCORDER_STATE_CAPTURING) { + _mmcam_dbg_warn("Can not set WDR while CAPTURING"); + return FALSE; + } + + mslVal = value->value.i_val; + newVal = _mmcamcorder_convert_msl_to_sensor(handle, MM_CAM_CAMERA_WDR, mslVal); + + if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) { + if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { _mmcam_dbg_log("Can't cast Video source into camera control."); return TRUE; } - - control = GST_CAMERA_CONTROL( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst ); - if( gst_camera_control_get_wdr( control, &cur_value ) ) - { - if( newVal != cur_value ) - { - if( gst_camera_control_set_wdr( control, newVal ) ) - { - //_mmcam_dbg_log( "Success - set wdr[%d]", mslVal ); + control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); + if (gst_camera_control_get_wdr(control, &cur_value)) { + if (newVal != cur_value) { + if (gst_camera_control_set_wdr(control, newVal)) { + _mmcam_dbg_log( "Success - set wdr[%d]", mslVal ); return TRUE; + } else { + _mmcam_dbg_warn("Failed to set WDR. NewVal[%d],CurVal[%d]", newVal, cur_value); } - else - { - _mmcam_dbg_warn( "Failed to set WDR. NewVal[%d],CurVal[%d]", newVal, cur_value ); - } - } - else - { - //_mmcam_dbg_log( "No need to set new WDR. Current[%d]", mslVal ); + } else { + _mmcam_dbg_log( "No need to set new WDR. Current[%d]", mslVal ); return TRUE; } - } - else - { + } else { _mmcam_dbg_warn( "Failed to get WDR." ); } - } - else - { + } else { _mmcam_dbg_log("pointer of video src is null"); } @@ -2424,67 +2682,43 @@ bool _mmcamcorder_commit_camera_wdr (MMHandleType handle, int attr_idx, const mm } -bool _mmcamcorder_commit_camera_anti_handshake (MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_camera_anti_handshake(MMHandleType handle, int attr_idx, const mmf_value_t *value) { - GstCameraControl *control = NULL; - int mslVal = value->value.i_val; - int newVal = _mmcamcorder_convert_msl_to_sensor(MM_CAM_CAMERA_ANTI_HANDSHAKE, mslVal); - int cur_value = 0; - _MMCamcorderSubContext *sc = NULL; int current_state = MM_CAMCORDER_STATE_NONE; - sc = MMF_CAMCORDER_SUBCONTEXT(handle); - if (!sc) + /* check whether set or not */ + if (!_mmcamcorder_check_supported_attribute(handle, attr_idx)) { + _mmcam_dbg_log("skip set value %d", value->value.i_val); return TRUE; + } - current_state = _mmcamcorder_get_state( handle); - + current_state = _mmcamcorder_get_state(handle); if (current_state < MM_CAMCORDER_STATE_READY) { _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); return TRUE; - } + } else if (current_state > MM_CAMCORDER_STATE_PREPARE) { + _mmcam_dbg_err("Invaild state (state %d)", current_state); + return FALSE; + } - if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) - { - if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) - { - _mmcam_dbg_log("Can't cast Video source into camera control."); - return TRUE; - } - - control = GST_CAMERA_CONTROL (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); + return _mmcamcorder_set_videosrc_anti_shake(handle, value->value.i_val); +} - if( gst_camera_control_get_ahs( control, &cur_value ) ) - { - if( newVal != cur_value ) - { - if (gst_camera_control_set_ahs(control, newVal)) - { - //_mmcam_dbg_log("Succeed in operating anti-handshake."); - return TRUE; - } - else - { - _mmcam_dbg_warn("Failed to operate anti-handshake. value[%d]", newVal); - } - } - else - { - //_mmcam_dbg_log( "No need to set new Anti-Handshake. Current[%d]", mslVal ); - return TRUE; - } - } - else - { - _mmcam_dbg_warn( "Failed to get Anti-Handshake." ); - } - } - else - { - _mmcam_dbg_warn("pointer of video src is null"); + +bool _mmcamcorder_commit_camera_video_stabilization(MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + int current_state = MM_CAMCORDER_STATE_NONE; + + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); + return TRUE; + } else if (current_state > MM_CAMCORDER_STATE_PREPARE) { + _mmcam_dbg_err("Invaild state (state %d)", current_state); + return FALSE; } - return FALSE; + return _mmcamcorder_set_videosrc_stabilization(handle, value->value.i_val); } @@ -2497,7 +2731,7 @@ bool _mmcamcorder_commit_camera_hold_af_after_capturing (MMHandleType handle, in if (!sc) return TRUE; - current_state = _mmcamcorder_get_state( handle); + current_state = _mmcamcorder_get_state(handle); if( current_state < MM_CAMCORDER_STATE_READY ) { @@ -2517,35 +2751,61 @@ bool _mmcamcorder_commit_camera_hold_af_after_capturing (MMHandleType handle, in } -bool _mmcamcorder_commit_camera_rotate (MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_camera_rotate(MMHandleType handle, int attr_idx, const mmf_value_t *value) { int current_state = MM_CAMCORDER_STATE_NONE; - gboolean bstate_changing = FALSE; _mmcam_dbg_log("rotate(%d)", value->value.i_val); - current_state = _mmcamcorder_get_state( handle); - bstate_changing = _mmcamcorder_is_state_changing( handle); + current_state = _mmcamcorder_get_state(handle); - if ((current_state > MM_CAMCORDER_STATE_READY) || bstate_changing ) { - _mmcam_dbg_err("camera rotation setting failed.(state=%d, is_state_changing(%d))", current_state, bstate_changing); + if (current_state > MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_err("camera rotation setting failed.(state=%d)", current_state); return FALSE; } else { - return _mmcamcorder_set_videosrc_rotation( handle, value->value.i_val ); + return _mmcamcorder_set_videosrc_rotation(handle, value->value.i_val); } } -bool _mmcamcorder_commit_image_encoder_quality (MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_image_encoder_quality(MMHandleType handle, int attr_idx, const mmf_value_t *value) { + int current_state = MM_CAMCORDER_STATE_NONE; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(handle, FALSE); + + /* check type */ + if (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO) { + _mmcam_dbg_err("invalid mode %d", hcamcorder->type); + return FALSE; + } + + /* check current state */ + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("NOT initialized. this will be applied later"); + return TRUE; + } + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + _mmcam_dbg_log("Image encoder quality(%d)", value->value.i_val); - return TRUE; + + if (current_state == MM_CAMCORDER_STATE_PREPARE) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-jpg-quality", value->value.i_val); + return TRUE; + } else { + _mmcam_dbg_err("invalid state %d", current_state); + return FALSE; + } } -bool _mmcamcorder_commit_target_filename (MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_target_filename(MMHandleType handle, int attr_idx, const mmf_value_t *value) { - mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _MMCamcorderSubContext *sc = NULL; char * filename = NULL; int size = 0; @@ -2554,48 +2814,17 @@ bool _mmcamcorder_commit_target_filename (MMHandleType handle, int attr_idx, con if (!sc) return TRUE; - //Set basic infomation - if (value->type != MM_ATTRS_TYPE_STRING) - { - _mmcam_dbg_log("Mismatched value type (%d)", value->type); - return FALSE; - } - else - { - filename = (char*)mmf_value_get_string(value, &size); - } + /* get string */ + filename = (char *)mmf_value_get_string(value, &size); - if (sc->element != NULL) - { - if ((hcamcorder->type == MM_CAMCORDER_MODE_VIDEO) || (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO)) - { - if (sc->element[_MMCAMCORDER_ENCSINK_BIN].gst != NULL) - { - if (sc->element[_MMCAMCORDER_ENCSINK_SINK].gst != NULL) - { - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", filename); - _mmcam_dbg_log("new file location set.(%s)", filename); - } - else - { - _mmcam_dbg_warn("filesink is not created."); - } - } - else - { - _mmcam_dbg_warn("filesink is not created."); - } - } - else - { - _mmcam_dbg_log("new file location set.(%s)", filename); - } - } - else - { - _mmcam_dbg_warn("gstreamer pipeline is not created."); + if (sc->element && sc->element[_MMCAMCORDER_ENCSINK_SINK].gst) { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", filename); + _mmcam_dbg_log("new file location set.(%s)", filename); + } else { + _mmcam_dbg_log("element is not created yet. [%s] will be set later...", filename); } - return TRUE; + + return TRUE; } @@ -2609,7 +2838,6 @@ bool _mmcamcorder_commit_filter (MMHandleType handle, int attr_idx, const mmf_va const GList *item = NULL; int newVal = 0; int mslNewVal = 0; - int cur_value = 0; int current_state = MM_CAMCORDER_STATE_NONE; gchar * control_label = NULL; _MMCamcorderSubContext *sc = NULL; @@ -2621,11 +2849,15 @@ bool _mmcamcorder_commit_filter (MMHandleType handle, int attr_idx, const mmf_va if (!sc) return TRUE; - current_state = _mmcamcorder_get_state(handle); + /* check whether set or not */ + if (!_mmcamcorder_check_supported_attribute(handle, attr_idx)) { + _mmcam_dbg_log("skip set value %d", value->value.i_val); + return TRUE; + } - //status check + current_state = _mmcamcorder_get_state(handle); if (current_state < MM_CAMCORDER_STATE_PREPARE) { - //_mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); + _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); return TRUE; } @@ -2636,39 +2868,38 @@ bool _mmcamcorder_commit_filter (MMHandleType handle, int attr_idx, const mmf_va mslNewVal = value->value.i_val; } - switch (attr_idx) - { - case MM_CAM_FILTER_BRIGHTNESS: - control_label = "brightness"; - check_scene_mode = TRUE; - break; + switch (attr_idx) { + case MM_CAM_FILTER_BRIGHTNESS: + control_label = "brightness"; + check_scene_mode = TRUE; + break; - case MM_CAM_FILTER_CONTRAST: - control_label = "contrast"; - break; + case MM_CAM_FILTER_CONTRAST: + control_label = "contrast"; + break; - case MM_CAM_FILTER_WB: - control_label = "white balance"; - check_scene_mode = TRUE; - break; + case MM_CAM_FILTER_WB: + control_label = "white balance"; + check_scene_mode = TRUE; + break; - case MM_CAM_FILTER_COLOR_TONE: - control_label = "color tone"; - break; + case MM_CAM_FILTER_COLOR_TONE: + control_label = "color tone"; + break; - case MM_CAM_FILTER_SATURATION: - control_label = "saturation"; - check_scene_mode = TRUE; - break; + case MM_CAM_FILTER_SATURATION: + control_label = "saturation"; + check_scene_mode = TRUE; + break; - case MM_CAM_FILTER_HUE: - control_label = "hue"; - break; + case MM_CAM_FILTER_HUE: + control_label = "hue"; + break; - case MM_CAM_FILTER_SHARPNESS: - control_label = "sharpness"; - check_scene_mode = TRUE; - break; + case MM_CAM_FILTER_SHARPNESS: + control_label = "sharpness"; + check_scene_mode = TRUE; + break; } if (check_scene_mode) { @@ -2679,14 +2910,13 @@ bool _mmcamcorder_commit_filter (MMHandleType handle, int attr_idx, const mmf_va } } - newVal = _mmcamcorder_convert_msl_to_sensor(attr_idx, mslNewVal); + newVal = _mmcamcorder_convert_msl_to_sensor(handle, attr_idx, mslNewVal); if (newVal == _MMCAMCORDER_SENSOR_ENUM_NONE) return FALSE; _mmcam_dbg_log("label(%s): MSL(%d)->Sensor(%d)", control_label, mslNewVal, newVal); - if (!GST_IS_COLOR_BALANCE(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) - { + if (!GST_IS_COLOR_BALANCE(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { _mmcam_dbg_log("Can't cast Video source into color balance."); return TRUE; } @@ -2694,27 +2924,22 @@ bool _mmcamcorder_commit_filter (MMHandleType handle, int attr_idx, const mmf_va balance = GST_COLOR_BALANCE (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); controls = gst_color_balance_list_channels (balance); - //_mmcam_dbg_log("controls(%x)", controls); if (controls == NULL) { _mmcam_dbg_log("There is no list of colorbalance controls"); return FALSE; } - for (item = controls;item != NULL;item = item->next) - { - if (item) - { - if (item->data) - { + for (item = controls ; item != NULL ; item = item->next) { + if (item) { + if (item->data) { Colorchannel = item->data; - //_mmcam_dbg_log("Getting name of CID=(%s), input CID=(%s)", Colorchannel->label, control_label); + /*_mmcam_dbg_log("Getting name of CID=(%s), input CID=(%s)", Colorchannel->label, control_label);*/ - if (strcmp(Colorchannel->label, control_label) == 0) - { + if (!strcmp(Colorchannel->label, control_label)) { break; - } - else + } else { Colorchannel = NULL; + } } } } @@ -2724,22 +2949,11 @@ bool _mmcamcorder_commit_filter (MMHandleType handle, int attr_idx, const mmf_va return FALSE; } - //_mmcam_dbg_log("Colorchannel(%x, %s)", Colorchannel, Colorchannel->label); - - cur_value = gst_color_balance_get_value( balance, Colorchannel ); - _mmcam_dbg_log( "device[cur:%d,new%d]", cur_value, newVal ); + __ta__(" gst_color_balance_set_value", + gst_color_balance_set_value (balance, Colorchannel, newVal); + ); - if( newVal != cur_value ) - { - __ta__(" gst_color_balance_set_value", - gst_color_balance_set_value (balance, Colorchannel, newVal); - ); - //_mmcam_dbg_log( "Set complete - %s[%d]", Colorchannel->label, mslNewVal ); - } - else - { - _mmcam_dbg_log( "No need to set %s. Current[%d]", Colorchannel->label, mslNewVal); - } + _mmcam_dbg_log( "Set complete - %s[msl:%d,real:%d]", Colorchannel->label, mslNewVal, newVal); return TRUE; } @@ -2749,8 +2963,7 @@ bool _mmcamcorder_commit_filter_scene_mode (MMHandleType handle, int attr_idx, c { GstCameraControl *control = NULL; int mslVal = value->value.i_val; - int newVal = _mmcamcorder_convert_msl_to_sensor( MM_CAM_FILTER_SCENE_MODE, mslVal ); - int cur_program_mode = MM_CAMCORDER_SCENE_MODE_NORMAL; + int newVal = _mmcamcorder_convert_msl_to_sensor( handle, MM_CAM_FILTER_SCENE_MODE, mslVal ); _MMCamcorderSubContext *sc = NULL; int current_state = MM_CAMCORDER_STATE_NONE; @@ -2758,59 +2971,56 @@ bool _mmcamcorder_commit_filter_scene_mode (MMHandleType handle, int attr_idx, c if (!sc) return TRUE; - current_state = _mmcamcorder_get_state( handle); - + /* check whether set or not */ + if (!_mmcamcorder_check_supported_attribute(handle, attr_idx)) { + _mmcam_dbg_log("skip set value %d", value->value.i_val); + return TRUE; + } + + current_state = _mmcamcorder_get_state(handle); if (current_state < MM_CAMCORDER_STATE_PREPARE) { _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); return TRUE; } if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) { + int ret = 0; + if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { _mmcam_dbg_log("Can't cast Video source into camera control."); return TRUE; } control = GST_CAMERA_CONTROL (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); - if( gst_camera_control_get_exposure( control, GST_CAMERA_CONTROL_PROGRAM_MODE, &cur_program_mode, NULL ) ) - { - if( newVal != cur_program_mode ) - { - int ret = 0; - __ta__(" gst_camera_control_set_exposure:GST_CAMERA_CONTROL_PROGRAM_MODE", - ret = gst_camera_control_set_exposure(control, GST_CAMERA_CONTROL_PROGRAM_MODE, newVal, 0); - ); - if (ret) { - _mmcam_dbg_log("Succeed in setting program mode[%d].", mslVal); - - if (mslVal == MM_CAMCORDER_SCENE_MODE_NORMAL) { - int i = 0; - int attr_idxs[] = { - MM_CAM_CAMERA_ISO - , MM_CAM_FILTER_BRIGHTNESS - , MM_CAM_FILTER_WB - , MM_CAM_FILTER_SATURATION - , MM_CAM_FILTER_SHARPNESS - }; - mmf_attrs_t *attr = (mmf_attrs_t *)MMF_CAMCORDER_ATTRS(handle); - - for (i = 0 ; i < ARRAY_SIZE(attr_idxs) ; i++) { - if (__mmcamcorder_attrs_is_supported((MMHandleType)attr, attr_idxs[i])) { - mmf_attribute_set_modified(&(attr->items[attr_idxs[i]])); - } - } + __ta__(" gst_camera_control_set_exposure:GST_CAMERA_CONTROL_PROGRAM_MODE", + ret = gst_camera_control_set_exposure(control, GST_CAMERA_CONTROL_PROGRAM_MODE, newVal, 0); + ); + if (ret) { + _mmcam_dbg_log("Succeed in setting program mode[%d].", mslVal); + + if (mslVal == MM_CAMCORDER_SCENE_MODE_NORMAL) { + int i = 0; + int attr_idxs[] = { + MM_CAM_CAMERA_ISO + , MM_CAM_FILTER_BRIGHTNESS + , MM_CAM_FILTER_WB + , MM_CAM_FILTER_SATURATION + , MM_CAM_FILTER_SHARPNESS + , MM_CAM_FILTER_COLOR_TONE + , MM_CAM_CAMERA_EXPOSURE_MODE + }; + mmf_attrs_t *attr = (mmf_attrs_t *)MMF_CAMCORDER_ATTRS(handle); + + for (i = 0 ; i < ARRAY_SIZE(attr_idxs) ; i++) { + if (__mmcamcorder_attrs_is_supported((MMHandleType)attr, attr_idxs[i])) { + mmf_attribute_set_modified(&(attr->items[attr_idxs[i]])); } - - return TRUE; - } else { - _mmcam_dbg_log( "Failed to set program mode[%d].", mslVal ); } - } else { - _mmcam_dbg_log( "No need to set program mode. Current[%d]", mslVal ); - return TRUE; } + + return TRUE; } else { - _mmcam_dbg_warn( "Failed to get program mode, so do not set new program mode[%d]", mslVal ); + _mmcam_dbg_log( "Failed to set program mode[%d].", mslVal ); } } else { _mmcam_dbg_warn("pointer of video src is null"); @@ -2827,21 +3037,111 @@ bool _mmcamcorder_commit_filter_flip (MMHandleType handle, int attr_idx, const m } -bool _mmcamcorder_commit_camcorder_rotate(MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_camera_face_zoom(MMHandleType handle, int attr_idx, const mmf_value_t *value) { + int ret = 0; int current_state = MM_CAMCORDER_STATE_NONE; - gboolean bstate_changing = FALSE; - _mmcam_dbg_log("camcorder-rotation(%d)", value->value.i_val); - current_state = _mmcamcorder_get_state( handle); - bstate_changing = _mmcamcorder_is_state_changing( handle); + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + GstCameraControl *control = NULL; + _MMCamcorderSubContext *sc = NULL; - if ((current_state > MM_CAMCORDER_STATE_PREPARE) || bstate_changing ) { - _mmcam_dbg_err("camcorder-rotation setting failed.(state=%d, is_state_changing(%d))", current_state, bstate_changing); - return FALSE; + mmf_return_val_if_fail(hcamcorder, FALSE); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, TRUE); + + /* these are only available after camera preview is started */ + current_state = _mmcamcorder_get_state(handle); + if (current_state >= MM_CAMCORDER_STATE_PREPARE && + hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + int x = 0; + int y = 0; + int zoom_level = 0; + int preview_width = 0; + int preview_height = 0; + + switch (attr_idx) { + case MM_CAM_CAMERA_FACE_ZOOM_X: + /* check x coordinate of face zoom */ + mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAMERA_WIDTH, &preview_width, + NULL); + /* x coordinate should be smaller than width of preview */ + if (value->value.i_val < preview_width) { + _mmcam_dbg_log("set face zoom x %d done", value->value.i_val); + ret = TRUE; + } else { + _mmcam_dbg_err("invalid face zoom x %d", value->value.i_val); + ret = FALSE; + } + break; + case MM_CAM_CAMERA_FACE_ZOOM_Y: + /* check y coordinate of face zoom */ + mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAMERA_WIDTH, &preview_height, + NULL); + /* y coordinate should be smaller than height of preview */ + if (value->value.i_val < preview_height) { + _mmcam_dbg_log("set face zoom y %d done", value->value.i_val); + ret = TRUE; + } else { + _mmcam_dbg_err("invalid face zoom y %d", value->value.i_val); + ret = FALSE; + } + break; + case MM_CAM_CAMERA_FACE_ZOOM_MODE: + if (value->value.i_val == MM_CAMCORDER_FACE_ZOOM_MODE_ON) { + int face_detect_mode = MM_CAMCORDER_DETECT_MODE_OFF; + + /* start face zoom */ + /* get x,y coordinate and zoom level */ + mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAMERA_FACE_ZOOM_X, &x, + MMCAM_CAMERA_FACE_ZOOM_Y, &y, + MMCAM_CAMERA_FACE_ZOOM_LEVEL, &zoom_level, + MMCAM_DETECT_MODE, &face_detect_mode, + NULL); + + if (face_detect_mode == MM_CAMCORDER_DETECT_MODE_ON) { + control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst ); + __ta__(" gst_camera_control_start_face_zoom", + ret = gst_camera_control_start_face_zoom(control, x, y, zoom_level); + ); + } else { + _mmcam_dbg_err("face detect is OFF... could not start face zoom"); + ret = FALSE; + } + } else if (value->value.i_val == MM_CAMCORDER_FACE_ZOOM_MODE_OFF) { + /* stop face zoom */ + control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst ); + __ta__(" gst_camera_control_stop_face_zoom", + ret = gst_camera_control_stop_face_zoom(control); + ); + } else { + /* should not be reached here */ + _mmcam_dbg_err("unknown command [%d]", value->value.i_val); + ret = FALSE; + } + + if (!ret) { + _mmcam_dbg_err("face zoom[%d] failed", value->value.i_val); + ret = FALSE; + } else { + _mmcam_dbg_log(""); + ret = TRUE; + } + break; + default: + _mmcam_dbg_warn("should not be reached here. attr_idx %d", attr_idx); + break; + } } else { - return TRUE; + _mmcam_dbg_err("invalid state[%d] or mode[%d]", current_state, hcamcorder->type); + ret = FALSE; } + + return ret; } @@ -2853,411 +3153,441 @@ bool _mmcamcorder_commit_audio_input_route (MMHandleType handle, int attr_idx, c } -bool _mmcamcorder_commit_display_handle (MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_audio_disable(MMHandleType handle, int attr_idx, const mmf_value_t *value) { - _MMCamcorderSubContext *sc = NULL; - - char* videosink_name = NULL; + int current_state = MM_CAMCORDER_STATE_NONE; - sc = MMF_CAMCORDER_SUBCONTEXT(handle); - if (!sc) + current_state = _mmcamcorder_get_state(handle); + if (current_state > MM_CAMCORDER_STATE_PREPARE) { + _mmcam_dbg_warn("Can NOT Disable AUDIO. invalid state %d", current_state); + return FALSE; + } else { + _mmcam_dbg_log("Disable AUDIO when Recording"); return TRUE; - - if( sc ) - { - _mmcamcorder_conf_get_value_element_name( sc->VideosinkElement, &videosink_name ); - _mmcam_dbg_log( "Commit : videosinkname[%s]", videosink_name ); - - if( !strcmp( videosink_name, "xvimagesink" ) || !strcmp( videosink_name, "xvimagesink" ) ) - { - if( sc->element ) - { - if( sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst ) - { - _mmcam_dbg_log( "Commit : Set XID[%x]", *(int*)(value->value.p_val) ); - gst_x_overlay_set_xwindow_id( GST_X_OVERLAY(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst), *(int*)(value->value.p_val) ); - } - } - } - else - { - _mmcam_dbg_log( "Commit : Nothing to commit with this element[%s]", videosink_name ); - } } - else - { - _mmcam_dbg_log( "Commit : Nothing to commit with this attribute(MM_CAMCORDER_DISPLAY_HANDLE)" ); - } - - return TRUE; - } -bool _mmcamcorder_commit_display_rotation (MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_display_handle(MMHandleType handle, int attr_idx, const mmf_value_t *value) { - mmf_camcorder_t *hcamcorder = NULL; - _MMCamcorderSubContext *sc = NULL; int current_state = MM_CAMCORDER_STATE_NONE; + char *videosink_name = NULL; + void *p_handle = NULL; - hcamcorder = MMF_CAMCORDER(handle); - if(!hcamcorder) - return TRUE; - sc = MMF_CAMCORDER_SUBCONTEXT(handle); - if (!sc) + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(handle, FALSE); + + /* check type */ + if (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO) { + _mmcam_dbg_err("invalid mode %d", hcamcorder->type); + return FALSE; + } + + /* check current state */ + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("NOT initialized. this will be applied later"); return TRUE; + } - current_state = _mmcamcorder_get_state( handle); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); - if( current_state > MM_CAMCORDER_STATE_NULL ) { - if( hcamcorder->type != MM_CAMCORDER_MODE_AUDIO ) { - return _mmcamcorder_set_display_rotation( handle, value->value.i_val ); + p_handle = value->value.p_val; + if (p_handle) { + /* get videosink name */ + _mmcamcorder_conf_get_value_element_name(sc->VideosinkElement, &videosink_name); + _mmcam_dbg_log("Commit : videosinkname[%s]", videosink_name); + + if (!strcmp(videosink_name, "xvimagesink") || !strcmp(videosink_name, "ximagesink")) { + _mmcam_dbg_log("Commit : Set XID[%x]", *(int*)(p_handle)); + gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst), *(int*)(p_handle)); + } else if (!strcmp(videosink_name, "evasimagesink") || + !strcmp(videosink_name, "evaspixmapsink")) { + _mmcam_dbg_log("Commit : Set evas object [%p]", p_handle); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "evas-object", p_handle); } else { - _mmcam_dbg_warn( "Current Mode is AUDIO only mode." ); + _mmcam_dbg_warn("Commit : Nothing to commit with this element[%s]", videosink_name); return FALSE; } } else { - _mmcam_dbg_err("display rotation change failed.(state=%d)", current_state); + _mmcam_dbg_warn("Display handle is NULL"); return FALSE; } + + return TRUE; } -bool _mmcamcorder_commit_display_visible (MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_display_mode(MMHandleType handle, int attr_idx, const mmf_value_t *value) { - mmf_camcorder_t *hcamcorder= MMF_CAMCORDER( handle); + int current_state = MM_CAMCORDER_STATE_NONE; + char *videosink_name = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _MMCamcorderSubContext *sc = NULL; - int is_visible = 0; - int current_state = MM_CAMCORDER_STATE_NONE; - int bret = 0; + mmf_return_val_if_fail(handle, FALSE); + + /* check type */ + if (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO) { + _mmcam_dbg_err("invalid mode %d", hcamcorder->type); + return FALSE; + } + + /* check current state */ + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("NOT initialized. this will be applied later"); + return TRUE; + } - char *videosink_name = NULL; - sc = MMF_CAMCORDER_SUBCONTEXT(handle); - if (!sc) + + _mmcamcorder_conf_get_value_element_name(sc->VideosinkElement, &videosink_name); + _mmcam_dbg_log("Commit : videosinkname[%s]", videosink_name); + + if (!strcmp(videosink_name, "xvimagesink")) { + _mmcam_dbg_log("Commit : display mode [%d]", value->value.i_val); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "display-mode", value->value.i_val); return TRUE; - current_state = _mmcamcorder_get_state( handle); + } else { + _mmcam_dbg_warn("Commit : This element [%s] does not support display mode", videosink_name); + return FALSE; + } +} - if( current_state > MM_CAMCORDER_STATE_NULL ) - { - if( hcamcorder->type != MM_CAMCORDER_MODE_AUDIO ) - { - if( sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst ) - { - // Get videosink name - _mmcamcorder_conf_get_value_element_name( sc->VideosinkElement, &videosink_name ); - is_visible = value->value.i_val; +bool _mmcamcorder_commit_display_rotation(MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + int current_state = MM_CAMCORDER_STATE_NONE; - if( !strcmp( videosink_name, "xvimagesink" ) - || !strcmp( videosink_name, "avsysvideosink" ) ) - { - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, - "visible", is_visible); + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); - _mmcam_dbg_log( "Set visible [%d] done.", is_visible ); - bret = TRUE; - } - else - { - _mmcam_dbg_warn( "videosink[%s] does not support VISIBLE.", videosink_name ); - bret = FALSE; - } - } - else - { - _mmcam_dbg_warn( "Videosink element is null, but current state is [%d]", current_state ); - bret = FALSE; - } - } - else - { - _mmcam_dbg_warn( "Current Mode is AUDIO only mode." ); - bret = FALSE; - } + mmf_return_val_if_fail(handle, FALSE); + + /* check type */ + if (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO) { + _mmcam_dbg_err("invalid mode %d", hcamcorder->type); + return FALSE; } - else - { - _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); - bret = TRUE; + + /* check current state */ + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("NOT initialized. this will be applied later"); + return TRUE; } - return bret; + + return _mmcamcorder_set_display_rotation(handle, value->value.i_val); } -bool _mmcamcorder_commit_display_geometry_method (MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_display_flip(MMHandleType handle, int attr_idx, const mmf_value_t *value) { - mmf_camcorder_t *hcamcorder= MMF_CAMCORDER( handle); - _MMCamcorderSubContext *sc = NULL; + int current_state = MM_CAMCORDER_STATE_NONE; - int newattrs = 0; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + mmf_return_val_if_fail(handle, FALSE); + + /* check type */ + if (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO) { + _mmcam_dbg_err("invalid mode %d", hcamcorder->type); + return FALSE; + } + + /* check current state */ + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("NOT initialized. this will be applied later"); + return TRUE; + } + + return _mmcamcorder_set_display_flip(handle, value->value.i_val); +} + + +bool _mmcamcorder_commit_display_visible(MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ int current_state = MM_CAMCORDER_STATE_NONE; - int bret = 0; - char *videosink_name = NULL; - - sc = MMF_CAMCORDER_SUBCONTEXT(handle); - if (!sc) - return TRUE; - current_state = _mmcamcorder_get_state( handle); - if (current_state > MM_CAMCORDER_STATE_NULL) - { - if (sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst) - { - // Get videosink name - _mmcamcorder_conf_get_value_element_name( sc->VideosinkElement, &videosink_name ); + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; - if(strcmp(videosink_name, "xvimagesink") == 0) //only for xvimagesink - { - if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) - { - newattrs = value->value.i_val; - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "display-geometry-method", newattrs); - } - } - bret = TRUE; - } - else - { - _mmcam_dbg_log("Videosink element is null"); - bret = FALSE; - } + mmf_return_val_if_fail(handle, FALSE); + + /* check type */ + if (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO) { + _mmcam_dbg_err("invalid mode %d", hcamcorder->type); + return FALSE; } - else - { - _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); - bret = TRUE; + + /* check current state */ + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("NOT initialized. this will be applied later"); + return TRUE; + } + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + + /* Get videosink name */ + _mmcamcorder_conf_get_value_element_name(sc->VideosinkElement, &videosink_name); + if (!strcmp(videosink_name, "xvimagesink") || + !strcmp(videosink_name, "evaspixmapsink")) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "visible", value->value.i_val); + _mmcam_dbg_log("Set visible [%d] done.", value->value.i_val); + return TRUE; + } else { + _mmcam_dbg_warn("videosink[%s] does not support VISIBLE.", videosink_name); + return FALSE; } - - return bret; } -bool _mmcamcorder_commit_display_rect (MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_display_geometry_method (MMHandleType handle, int attr_idx, const mmf_value_t *value) { - mmf_camcorder_t *hcamcorder= MMF_CAMCORDER( handle); + int method = 0; + int current_state = MM_CAMCORDER_STATE_NONE; + char *videosink_name = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _MMCamcorderSubContext *sc = NULL; + mmf_return_val_if_fail(handle, FALSE); + + /* check type */ + if (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO) { + _mmcam_dbg_err("invalid mode %d", hcamcorder->type); + return FALSE; + } + + /* check current state */ + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("NOT initialized. this will be applied later"); + return TRUE; + } + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + + /* Get videosink name */ + _mmcamcorder_conf_get_value_element_name(sc->VideosinkElement, &videosink_name); + if (!strcmp(videosink_name, "xvimagesink") || + !strcmp(videosink_name, "evaspixmapsink")) { + method = value->value.i_val; + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "display-geometry-method", method); + return TRUE; + } else { + _mmcam_dbg_warn("videosink[%s] does not support geometry method.", videosink_name); + return FALSE; + } +} + + +bool _mmcamcorder_commit_display_rect(MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ int current_state = MM_CAMCORDER_STATE_NONE; - int bret = 0; - + int method = 0; char *videosink_name = NULL; - - sc = MMF_CAMCORDER_SUBCONTEXT(handle); - if (!sc) + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(handle, FALSE); + + /* check type */ + if (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO) { + _mmcam_dbg_err("invalid mode %d", hcamcorder->type); + return FALSE; + } + + /* check current state */ + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("NOT initialized. this will be applied later"); return TRUE; - current_state = _mmcamcorder_get_state( handle); + } - if (current_state > MM_CAMCORDER_STATE_NULL) - { - if (sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst) - { - // Get videosink name - _mmcamcorder_conf_get_value_element_name( sc->VideosinkElement, &videosink_name ); - - if(strcmp(videosink_name, "xvimagesink") == 0) //only for xvimagesink - { - if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) - { - int err = 0; - int rectx, recty, rectw, recth; - int display_geometry_method = 0; - - err = mm_camcorder_get_attributes(handle, NULL, - MMCAM_DISPLAY_RECT_X, &rectx, - MMCAM_DISPLAY_RECT_Y, &recty, - MMCAM_DISPLAY_RECT_WIDTH, &rectw, - MMCAM_DISPLAY_RECT_HEIGHT, &recth, - MMCAM_DISPLAY_GEOMETRY_METHOD, &display_geometry_method, - NULL); - if (err < 0) - { - _mmcam_dbg_warn("Get display-geometry-method attrs fail. (%x)", err); - return FALSE; - } + sc = MMF_CAMCORDER_SUBCONTEXT(handle); - if (display_geometry_method == MM_DISPLAY_METHOD_CUSTOM_ROI) - { - int flags = MM_ATTRS_FLAG_NONE; - MMCamAttrsInfo info; - _mmcam_dbg_log("FRECT(x,y,w,h) = (%d,%d,%d,%d)", rectx, recty, rectw, recth); - switch(attr_idx) - { - case MM_CAM_DISPLAY_RECT_X: - mm_camcorder_get_attribute_info(handle, MMCAM_DISPLAY_RECT_Y, &info); - flags |= info.flag; - memset(&info, 0x00, sizeof(info)); - mm_camcorder_get_attribute_info(handle, MMCAM_DISPLAY_RECT_WIDTH, &info); - flags |= info.flag; - memset(&info, 0x00, sizeof(info)); - mm_camcorder_get_attribute_info(handle, MMCAM_DISPLAY_RECT_HEIGHT, &info); - flags |= info.flag; - - rectx = value->value.i_val; - break; - case MM_CAM_DISPLAY_RECT_Y: - mm_camcorder_get_attribute_info(handle, MMCAM_DISPLAY_RECT_WIDTH, &info); - flags |= info.flag; - memset(&info, 0x00, sizeof(info)); - mm_camcorder_get_attribute_info(handle, MMCAM_DISPLAY_RECT_HEIGHT, &info); - flags |= info.flag; - - recty = value->value.i_val; - break; - case MM_CAM_DISPLAY_RECT_WIDTH: - mm_camcorder_get_attribute_info(handle, MMCAM_DISPLAY_RECT_HEIGHT, &info); - flags |= info.flag; + /* check current method */ + mm_camcorder_get_attributes(handle, NULL, + MMCAM_DISPLAY_GEOMETRY_METHOD, &method, + NULL); + if (method != MM_DISPLAY_METHOD_CUSTOM_ROI) { + _mmcam_dbg_log("current method[%d] is not supported rect", method); + return FALSE; + } - rectw = value->value.i_val; - break; - case MM_CAM_DISPLAY_RECT_HEIGHT: - recth = value->value.i_val; - break; - default: - _mmcam_dbg_err("Wrong attr_idx!"); - return FALSE; - } + /* Get videosink name */ + _mmcamcorder_conf_get_value_element_name(sc->VideosinkElement, &videosink_name); + if (!strcmp(videosink_name, "xvimagesink") || + !strcmp(videosink_name, "evaspixmapsink")) { + int rect_x = 0; + int rect_y = 0; + int rect_width = 0; + int rect_height = 0; + int flags = MM_ATTRS_FLAG_NONE; + MMCamAttrsInfo info; - if (!(flags & MM_ATTRS_FLAG_MODIFIED)) - { - _mmcam_dbg_log("RECT(x,y,w,h) = (%d,%d,%d,%d)", rectx, recty, rectw, recth); - - //Do we need to check all? - if(g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst)), "dst-roi-x")) - { - g_object_set (sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, - "dst-roi-x", rectx, - "dst-roi-y", recty, - "dst-roi-w", rectw, - "dst-roi-h", recth, - NULL); - } - } - } - } - } - bret = TRUE; + mm_camcorder_get_attributes(handle, NULL, + MMCAM_DISPLAY_RECT_X, &rect_x, + MMCAM_DISPLAY_RECT_Y, &rect_y, + MMCAM_DISPLAY_RECT_WIDTH, &rect_width, + MMCAM_DISPLAY_RECT_HEIGHT, &rect_height, + NULL); + switch (attr_idx) { + case MM_CAM_DISPLAY_RECT_X: + mm_camcorder_get_attribute_info(handle, MMCAM_DISPLAY_RECT_Y, &info); + flags |= info.flag; + memset(&info, 0x00, sizeof(info)); + mm_camcorder_get_attribute_info(handle, MMCAM_DISPLAY_RECT_WIDTH, &info); + flags |= info.flag; + memset(&info, 0x00, sizeof(info)); + mm_camcorder_get_attribute_info(handle, MMCAM_DISPLAY_RECT_HEIGHT, &info); + flags |= info.flag; + + rect_x = value->value.i_val; + break; + case MM_CAM_DISPLAY_RECT_Y: + mm_camcorder_get_attribute_info(handle, MMCAM_DISPLAY_RECT_WIDTH, &info); + flags |= info.flag; + memset(&info, 0x00, sizeof(info)); + mm_camcorder_get_attribute_info(handle, MMCAM_DISPLAY_RECT_HEIGHT, &info); + flags |= info.flag; + + rect_y = value->value.i_val; + break; + case MM_CAM_DISPLAY_RECT_WIDTH: + mm_camcorder_get_attribute_info(handle, MMCAM_DISPLAY_RECT_HEIGHT, &info); + flags |= info.flag; + + rect_width = value->value.i_val; + break; + case MM_CAM_DISPLAY_RECT_HEIGHT: + rect_height = value->value.i_val; + break; + default: + _mmcam_dbg_err("Wrong attr_idx!"); + return FALSE; } - else - { - _mmcam_dbg_log("Videosink element is null"); - bret = FALSE; + + if (!(flags & MM_ATTRS_FLAG_MODIFIED)) { + _mmcam_dbg_log("RECT(x,y,w,h) = (%d,%d,%d,%d)", + rect_x, rect_y, rect_width, rect_height); + g_object_set(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, + "dst-roi-x", rect_x, + "dst-roi-y", rect_y, + "dst-roi-w", rect_width, + "dst-roi-h", rect_height, + NULL); } + + return TRUE; + } else { + _mmcam_dbg_warn("videosink[%s] does not support display rect.", videosink_name); + return FALSE; } - else - { - _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); - bret = TRUE; - } - - return bret; } -bool _mmcamcorder_commit_display_scale (MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_display_scale(MMHandleType handle, int attr_idx, const mmf_value_t *value) { - mmf_camcorder_t *hcamcorder= MMF_CAMCORDER( handle); - _MMCamcorderSubContext *sc = NULL; - int zoom = 0; int current_state = MM_CAMCORDER_STATE_NONE; - int bret = 0; - char *videosink_name = NULL; + GstElement *vs_element = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(handle, FALSE); + + /* check type */ + if (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO) { + _mmcam_dbg_err("invalid mode %d", hcamcorder->type); + return FALSE; + } + + /* check current state */ + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("NOT initialized. this will be applied later"); + return TRUE; + } sc = MMF_CAMCORDER_SUBCONTEXT(handle); - if (!sc) + + /* Get videosink name */ + _mmcamcorder_conf_get_value_element_name(sc->VideosinkElement, &videosink_name); + zoom = value->value.i_val; + if (!strcmp(videosink_name, "xvimagesink")) { + vs_element = sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst; + + MMCAMCORDER_G_OBJECT_SET(vs_element, "zoom", zoom + 1); + _mmcam_dbg_log("Set display zoom to %d", zoom + 1); + return TRUE; - current_state = _mmcamcorder_get_state( handle); + } else { + _mmcam_dbg_warn("videosink[%s] does not support scale", videosink_name); + return FALSE; + } +} - if( current_state > MM_CAMCORDER_STATE_NULL ) - { - if( hcamcorder->type != MM_CAMCORDER_MODE_AUDIO ) - { - if( sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst ) - { - // Get videosink name - _mmcamcorder_conf_get_value_element_name( sc->VideosinkElement, &videosink_name ); - - zoom = value->value.i_val; - if( !strcmp( videosink_name, "xvimagesink" )) - { - //xvimagesink - switch (zoom) - { - case MM_DISPLAY_SCALE_DEFAULT: - { - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "zoom", 1); +bool _mmcamcorder_commit_display_evas_do_scaling(MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + int current_state = MM_CAMCORDER_STATE_NONE; + int do_scaling = 0; + char *videosink_name = NULL; - _mmcam_dbg_log( "Set display zoom to default."); - break; - } - case MM_DISPLAY_SCALE_DOUBLE_LENGTH: - { - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "zoom", 2); + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER( handle); + _MMCamcorderSubContext *sc = NULL; - _mmcam_dbg_log( "Set display zoom to double."); - break; - } - case MM_DISPLAY_SCALE_TRIPLE_LENGTH: - { - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "zoom", 3); + mmf_return_val_if_fail(handle, FALSE); - _mmcam_dbg_log( "Set display zoom to triple."); - break; - } - default: - { - _mmcam_dbg_warn( "Unsupported value."); - } - } - - bret = TRUE; - } - else if (!strcmp( videosink_name, "avsysvideosink" ) ) - { - //avsysvideosink - bret = TRUE; - } - else - { - _mmcam_dbg_warn( "videosink[%s] does not support 'zoom'.", videosink_name ); - bret = FALSE; - } - } - else - { - _mmcam_dbg_warn( "Videosink element is null, but current state is [%d]", current_state ); - bret = FALSE; - } - } - else - { - _mmcam_dbg_warn( "Current Mode is AUDIO only mode." ); - bret = FALSE; - } + /* check type */ + if (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO) { + _mmcam_dbg_err("invalid mode %d", hcamcorder->type); + return FALSE; } - else - { - _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); - bret = TRUE; + + /* check current state */ + current_state = _mmcamcorder_get_state(handle); + if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("NOT initialized. this will be applied later"); + return TRUE; } - return bret; + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + + do_scaling = value->value.i_val; + + /* Get videosink name */ + _mmcamcorder_conf_get_value_element_name(sc->VideosinkElement, &videosink_name); + if (!strcmp(videosink_name, "evaspixmapsink")) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "origin-size", !do_scaling); + _mmcam_dbg_log("Set origin-size to %d", !(value->value.i_val)); + return TRUE; + } else { + _mmcam_dbg_warn("videosink[%s] does not support scale", videosink_name); + return FALSE; + } } bool _mmcamcorder_commit_strobe (MMHandleType handle, int attr_idx, const mmf_value_t *value) { - bool bret = FALSE; - _MMCamcorderSubContext* sc = NULL; - int strobe_type, mslVal, newVal, cur_value; - int current_state = MM_CAMCORDER_STATE_NONE; + bool bret = FALSE; + _MMCamcorderSubContext *sc = NULL; + int strobe_type, mslVal, newVal, cur_value; + int current_state = MM_CAMCORDER_STATE_NONE; - sc = MMF_CAMCORDER_SUBCONTEXT( handle ); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); if (!sc) return TRUE; @@ -3274,61 +3604,52 @@ bool _mmcamcorder_commit_strobe (MMHandleType handle, int attr_idx, const mmf_va mslVal = value->value.i_val; - switch( attr_idx ) - { - case MM_CAM_STROBE_CONTROL: - strobe_type = GST_CAMERA_CONTROL_STROBE_CONTROL; - newVal = _mmcamcorder_convert_msl_to_sensor( MM_CAM_STROBE_CONTROL, mslVal); - break; - case MM_CAM_STROBE_CAPABILITIES: - strobe_type = GST_CAMERA_CONTROL_STROBE_CAPABILITIES; - newVal = mslVal; - break; - case MM_CAM_STROBE_MODE: - strobe_type = GST_CAMERA_CONTROL_STROBE_MODE; - newVal = _mmcamcorder_convert_msl_to_sensor( MM_CAM_STROBE_MODE, mslVal); - break; - default: - { - _mmcam_dbg_err("Commit : strobe attribute(attr_idx(%d) is out of range)", attr_idx); - return FALSE; + switch (attr_idx) { + case MM_CAM_STROBE_CONTROL: + strobe_type = GST_CAMERA_CONTROL_STROBE_CONTROL; + newVal = _mmcamcorder_convert_msl_to_sensor(handle, MM_CAM_STROBE_CONTROL, mslVal); + break; + case MM_CAM_STROBE_CAPABILITIES: + strobe_type = GST_CAMERA_CONTROL_STROBE_CAPABILITIES; + newVal = mslVal; + break; + case MM_CAM_STROBE_MODE: + /* check whether set or not */ + if (!_mmcamcorder_check_supported_attribute(handle, attr_idx)) { + _mmcam_dbg_log("skip set value %d", mslVal); + return TRUE; } + + strobe_type = GST_CAMERA_CONTROL_STROBE_MODE; + newVal = _mmcamcorder_convert_msl_to_sensor(handle, MM_CAM_STROBE_MODE, mslVal); + break; + default: + _mmcam_dbg_err("Commit : strobe attribute(attr_idx(%d) is out of range)", attr_idx); + return FALSE; } GstCameraControl *control = NULL; - if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) - { + if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { _mmcam_dbg_err("Can't cast Video source into camera control."); - bret = FALSE; - } - else - { - control = GST_CAMERA_CONTROL( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst ); + bret = FALSE; + } else { + control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); - if( gst_camera_control_get_strobe( control, strobe_type, &cur_value ) ) - { - if( newVal != cur_value ) - { - if( gst_camera_control_set_strobe( control, strobe_type, newVal ) ) - { - _mmcam_dbg_log( "Succeed in setting strobe. Type[%d],value[%d]", strobe_type, mslVal ); + if (gst_camera_control_get_strobe(control, strobe_type, &cur_value)) { + if (newVal != cur_value) { + if (gst_camera_control_set_strobe(control, strobe_type, newVal)) { + _mmcam_dbg_log("Succeed in setting strobe. Type[%d],value[%d]", strobe_type, mslVal); bret = TRUE; - } - else - { - _mmcam_dbg_warn( "Set strobe failed. Type[%d],value[%d]", strobe_type, mslVal ); + } else { + _mmcam_dbg_warn("Set strobe failed. Type[%d],value[%d]", strobe_type, mslVal); bret = FALSE; } - } - else - { - _mmcam_dbg_log( "No need to set strobe. Type[%d],value[%d]", strobe_type, mslVal ); + } else { + _mmcam_dbg_log("No need to set strobe. Type[%d],value[%d]", strobe_type, mslVal); bret = TRUE; } - } - else - { - _mmcam_dbg_warn( "Failed to get strobe. Type[%d]", strobe_type ); + } else { + _mmcam_dbg_warn("Failed to get strobe. Type[%d]", strobe_type); bret = FALSE; } } @@ -3337,90 +3658,145 @@ bool _mmcamcorder_commit_strobe (MMHandleType handle, int attr_idx, const mmf_va } -bool _mmcamcorder_commit_detect (MMHandleType handle, int attr_idx, const mmf_value_t *value) +bool _mmcamcorder_commit_camera_flip(MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + int ret = 0; + int current_state = MM_CAMCORDER_STATE_NONE; + + if ((void *)handle == NULL) { + _mmcam_dbg_warn("handle is NULL"); + return FALSE; + } + + _mmcam_dbg_log("Commit : flip %d", value->value.i_val); + + /* state check */ + current_state = _mmcamcorder_get_state(handle); + if (current_state > MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_err("Can not set camera FLIP horizontal at state %d", current_state); + return FALSE; + } else if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("Pipeline is not created yet. This will be set when create pipeline."); + return TRUE; + } + + ret = _mmcamcorder_set_videosrc_flip(handle, value->value.i_val); + + _mmcam_dbg_log("ret %d", ret); + + return ret; +} + + +bool _mmcamcorder_commit_camera_hdr_capture(MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + int current_state = MM_CAMCORDER_STATE_NONE; + + if ((void *)handle == NULL) { + _mmcam_dbg_warn("handle is NULL"); + return FALSE; + } + + _mmcam_dbg_log("Commit : HDR Capture %d", value->value.i_val); + + /* check whether set or not */ + if (!_mmcamcorder_check_supported_attribute(handle, attr_idx)) { + _mmcam_dbg_log("skip set value %d", value->value.i_val); + return TRUE; + } + + /* state check */ + current_state = _mmcamcorder_get_state(handle); + if (current_state > MM_CAMCORDER_STATE_PREPARE) { + _mmcam_dbg_err("can NOT set HDR capture at state %d", current_state); + return FALSE; + } + + return TRUE; +} + + +bool _mmcamcorder_commit_detect(MMHandleType handle, int attr_idx, const mmf_value_t *value) { - bool bret = FALSE; - _MMCamcorderSubContext* sc = NULL; - int detect_type, mslVal, newVal, curVal; + bool bret = FALSE; + _MMCamcorderSubContext *sc = NULL; + int detect_type = GST_CAMERA_CONTROL_FACE_DETECT_MODE; + int set_value = 0; + int current_value = 0; + int current_state = MM_CAMCORDER_STATE_NONE; GstCameraControl *control = NULL; - int current_state = MM_CAMCORDER_STATE_NONE; - sc = MMF_CAMCORDER_SUBCONTEXT( handle ); - if (!sc) + if ((void *)handle == NULL) { + _mmcam_dbg_warn("handle is NULL"); + return FALSE; + } + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) { return TRUE; + } - _mmcam_dbg_log( "Commit : detect attribute(%d)", attr_idx); + _mmcam_dbg_log("Commit : detect attribute(%d)", attr_idx); - //status check + /* state check */ current_state = _mmcamcorder_get_state( handle); - if (current_state < MM_CAMCORDER_STATE_READY) { //_mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); return TRUE; } - - switch( attr_idx ) - { - case MM_CAM_DETECT_MODE: - detect_type = GST_CAMERA_CONTROL_FACE_DETECT_MODE; - break; - case MM_CAM_DETECT_NUMBER: - detect_type = GST_CAMERA_CONTROL_FACE_DETECT_NUMBER; - break; - case MM_CAM_DETECT_FOCUS_SELECT: - detect_type = GST_CAMERA_CONTROL_FACE_FOCUS_SELECT; - break; - case MM_CAM_DETECT_SELECT_NUMBER: - detect_type = GST_CAMERA_CONTROL_FACE_SELECT_NUMBER; - break; - case MM_CAM_DETECT_STATUS: - detect_type = GST_CAMERA_CONTROL_FACE_DETECT_STATUS; - break; - default: - { - _mmcam_dbg_err("Commit : strobe attribute(attr_idx(%d) is out of range)", attr_idx); - bret = FALSE; - return bret; + + set_value = value->value.i_val; + + switch (attr_idx) { + case MM_CAM_DETECT_MODE: + /* check whether set or not */ + if (!_mmcamcorder_check_supported_attribute(handle, attr_idx)) { + _mmcam_dbg_log("skip set value %d", set_value); + return TRUE; } - } - mslVal = value->value.i_val; - newVal = _mmcamcorder_convert_msl_to_sensor( attr_idx, mslVal ); - + detect_type = GST_CAMERA_CONTROL_FACE_DETECT_MODE; + break; + case MM_CAM_DETECT_NUMBER: + detect_type = GST_CAMERA_CONTROL_FACE_DETECT_NUMBER; + break; + case MM_CAM_DETECT_FOCUS_SELECT: + detect_type = GST_CAMERA_CONTROL_FACE_FOCUS_SELECT; + break; + case MM_CAM_DETECT_SELECT_NUMBER: + detect_type = GST_CAMERA_CONTROL_FACE_SELECT_NUMBER; + break; + case MM_CAM_DETECT_STATUS: + detect_type = GST_CAMERA_CONTROL_FACE_DETECT_STATUS; + break; + default: + _mmcam_dbg_err("Commit : strobe attribute(attr_idx(%d) is out of range)", attr_idx); + return FALSE; + } - if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) - { + if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { _mmcam_dbg_err("Can't cast Video source into camera control."); bret = FALSE; - } - else - { - control = GST_CAMERA_CONTROL( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst ); + } else { + control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); - if( gst_camera_control_get_detect( control, detect_type, &curVal ) ) - { - if( curVal == newVal ) - { - _mmcam_dbg_log( "No need to set detect. Type[%d],value[%d]", detect_type, mslVal ); + if (gst_camera_control_get_detect(control, detect_type, ¤t_value)) { + if (current_value == set_value) { + _mmcam_dbg_log("No need to set detect(same). Type[%d],value[%d]", detect_type, set_value); bret = TRUE; - } - else - { - if( !gst_camera_control_set_detect( control, detect_type, newVal ) ) - { - _mmcam_dbg_warn( "Set detect failed. Type[%d],value[%d]", detect_type, mslVal ); + } else { + if (!gst_camera_control_set_detect(control, detect_type, set_value)) { + _mmcam_dbg_warn("Set detect failed. Type[%d],value[%d]", + detect_type, set_value); bret = FALSE; - } - else - { - _mmcam_dbg_log( "Set detect success. Type[%d],value[%d]", detect_type, mslVal ); + } else { + _mmcam_dbg_log("Set detect success. Type[%d],value[%d]", + detect_type, set_value); bret = TRUE; } } - } - else - { - _mmcam_dbg_warn( "Get detect failed. Type[%d]", detect_type ); + } else { + _mmcam_dbg_warn("Get detect failed. Type[%d]", detect_type); bret = FALSE; } } @@ -3475,29 +3851,12 @@ _mmcamcorder_set_attribute_to_camsensor(MMHandleType handle) int attr_idxs_default[] = { MM_CAM_CAMERA_DIGITAL_ZOOM , MM_CAM_CAMERA_OPTICAL_ZOOM - , MM_CAM_CAMERA_FOCUS_MODE - , MM_CAM_CAMERA_AF_SCAN_RANGE - , MM_CAM_CAMERA_EXPOSURE_MODE - , MM_CAM_CAMERA_EXPOSURE_VALUE - , MM_CAM_CAMERA_F_NUMBER - , MM_CAM_CAMERA_SHUTTER_SPEED , MM_CAM_CAMERA_WDR - , MM_CAM_CAMERA_ANTI_HANDSHAKE - , MM_CAM_CAMERA_FPS_AUTO , MM_CAM_CAMERA_HOLD_AF_AFTER_CAPTURING , MM_CAM_FILTER_CONTRAST - , MM_CAM_FILTER_COLOR_TONE , MM_CAM_FILTER_HUE - , MM_CAM_STROBE_CONTROL , MM_CAM_STROBE_MODE , MM_CAM_DETECT_MODE - , MM_CAM_DETECT_NUMBER - , MM_CAM_DETECT_FOCUS_SELECT - , MM_CAM_DETECT_SELECT_NUMBER - , MM_CAM_CAMERA_AF_TOUCH_X - , MM_CAM_CAMERA_AF_TOUCH_Y - , MM_CAM_CAMERA_AF_TOUCH_WIDTH - , MM_CAM_CAMERA_AF_TOUCH_HEIGHT }; int attr_idxs_extra[] = { @@ -3506,6 +3865,8 @@ _mmcamcorder_set_attribute_to_camsensor(MMHandleType handle) , MM_CAM_FILTER_WB , MM_CAM_FILTER_SATURATION , MM_CAM_FILTER_SHARPNESS + , MM_CAM_FILTER_COLOR_TONE + , MM_CAM_CAMERA_EXPOSURE_MODE }; mmf_return_val_if_fail(hcamcorder, FALSE); @@ -3605,10 +3966,10 @@ int _mmcamcorder_set_disabled_attributes(MMHandleType handle) _mmcam_dbg_log(""); /* add gst_param */ - _mmcamcorder_conf_get_value_string_array( hcamcorder->conf_main, - CONFIGURE_CATEGORY_MAIN_GENERAL, - "DisabledAttributes", - &disabled_attr ); + _mmcamcorder_conf_get_value_string_array(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_GENERAL, + "DisabledAttributes", + &disabled_attr); if (disabled_attr != NULL && disabled_attr->value) { cnt_str = disabled_attr->count; for (i = 0; i < cnt_str; i++) { @@ -3639,7 +4000,7 @@ static bool __mmcamcorder_set_capture_resolution(MMHandleType handle, int width, mmf_return_val_if_fail(hcamcorder, FALSE); sc = MMF_CAMCORDER_SUBCONTEXT(handle); - mmf_return_val_if_fail(sc && sc->info, TRUE); + mmf_return_val_if_fail(sc, TRUE); current_state = _mmcamcorder_get_state(handle); @@ -3662,44 +4023,38 @@ static bool __mmcamcorder_set_capture_resolution(MMHandleType handle, int width, static bool __mmcamcorder_set_camera_resolution(MMHandleType handle, int width, int height) { - mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); - int fps, slow_fps; + int fps = 0; + double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _MMCamcorderSubContext *sc = NULL; GstCaps *caps = NULL; - int set_width, set_height; - + + mmf_return_val_if_fail(hcamcorder, FALSE); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); - if (!sc) - return TRUE; + mmf_return_val_if_fail(sc, TRUE); - mm_camcorder_get_attributes(handle, NULL, - MMCAM_CAMERA_FPS, &fps, - "camera-slow-motion-fps", &slow_fps, - NULL); + mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAMERA_FPS, &fps, + MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate, + NULL); - if (hcamcorder->type == MM_CAMCORDER_MODE_VIDEO) { - if(slow_fps > 0) { - sc->is_slow = TRUE; + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + if(motion_rate != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) { MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "high-speed-fps", fps); } else { - sc->is_slow = FALSE; MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "high-speed-fps", 0); } - } else { - sc->is_slow = FALSE; } - set_width = width; - set_height = height; - - caps = gst_caps_new_simple( "video/x-raw-yuv", - "format", GST_TYPE_FOURCC, sc->fourcc, - "width", G_TYPE_INT, set_width, - "height", G_TYPE_INT, set_height, - "framerate", GST_TYPE_FRACTION, (sc->is_slow ? slow_fps : fps), 1, - NULL - ); - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSRC_FILT].gst, "caps", caps); + caps = gst_caps_new_simple("video/x-raw-yuv", + "format", GST_TYPE_FOURCC, sc->fourcc, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + "framerate", GST_TYPE_FRACTION, fps, 1, + NULL); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_FILT].gst, "caps", caps); gst_caps_unref(caps); return TRUE; @@ -3803,14 +4158,6 @@ __mmcamcorder_check_valid_pair( MMHandleType handle, char **err_attr_name, const va_arg ((var_args), void*); /* data */ va_arg ((var_args), int); /* size */ break; - case MM_ATTRS_TYPE_ARRAY: - va_arg ((var_args), void*); /* array */ - va_arg ((var_args), int); /* length */ - break; - case MM_ATTRS_TYPE_RANGE: - va_arg ((var_args), int); /* min */ - va_arg ((var_args), int); /* max */ - break; case MM_ATTRS_TYPE_INVALID: default: _mmcam_dbg_err( "Not supported attribute type(%d, name:%s)", attr_type, name); @@ -3873,6 +4220,11 @@ __mmcamcorder_check_valid_pair( MMHandleType handle, char **err_attr_name, const return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; } + + if (err_name) { + free(err_name); + err_name = NULL; + } } } @@ -3880,3 +4232,50 @@ __mmcamcorder_check_valid_pair( MMHandleType handle, char **err_attr_name, const return MM_ERROR_NONE; } + + +bool _mmcamcorder_check_supported_attribute(MMHandleType handle, int attr_index) +{ + MMAttrsInfo info; + + if ((void *)handle == NULL) { + _mmcam_dbg_warn("handle %p is NULL", handle); + return FALSE; + } + + memset(&info, 0x0, sizeof(MMAttrsInfo)); + + mm_attrs_get_info(MMF_CAMCORDER_ATTRS(handle), attr_index, &info); + + switch (info.validity_type) { + case MM_ATTRS_VALID_TYPE_INT_ARRAY: + _mmcam_dbg_log("int array count %d", info.int_array.count) + if (info.int_array.count <= 1) { + return FALSE; + } + break; + case MM_ATTRS_VALID_TYPE_INT_RANGE: + _mmcam_dbg_log("int range min %d, max %d",info.int_range.min, info.int_range.max); + if (info.int_range.min >= info.int_range.max) { + return FALSE; + } + break; + case MM_ATTRS_VALID_TYPE_DOUBLE_ARRAY: + _mmcam_dbg_log("double array count %d", info.double_array.count) + if (info.double_array.count <= 1) { + return FALSE; + } + break; + case MM_ATTRS_VALID_TYPE_DOUBLE_RANGE: + _mmcam_dbg_log("double range min %lf, max %lf",info.int_range.min, info.int_range.max); + if (info.double_range.min >= info.double_range.max) { + return FALSE; + } + break; + default: + _mmcam_dbg_warn("invalid type %d", info.validity_type); + return FALSE; + } + + return TRUE; +} diff --git a/src/mm_camcorder_audiorec.c b/src/mm_camcorder_audiorec.c index b810fe7..754a72e 100644 --- a/src/mm_camcorder_audiorec.c +++ b/src/mm_camcorder_audiorec.c @@ -57,7 +57,6 @@ static void __mmcamcorder_audiorec_pad_added_cb(GstElement *element, GstPad *pad | GLOBAL FUNCTION DEFINITIONS: | ---------------------------------------------------------------------------------------*/ - static int __mmcamcorder_create_audiop_with_encodebin(MMHandleType handle) { int err = MM_ERROR_NONE; @@ -80,9 +79,9 @@ static int __mmcamcorder_create_audiop_with_encodebin(MMHandleType handle) mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED); mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - mmf_return_val_if_fail(sc->info, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc->info_audio, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - info = (_MMCamcorderAudioInfo *)sc->info; + info = (_MMCamcorderAudioInfo *)sc->info_audio; _mmcam_dbg_log(""); @@ -117,7 +116,7 @@ static int __mmcamcorder_create_audiop_with_encodebin(MMHandleType handle) if (info->bMuxing) { /* Muxing. can use encodebin. */ __ta__(" _mmcamcorder_create_encodesink_bin", - err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder); + err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_AUDIO); ); if (err != MM_ERROR_NONE ) { return err; @@ -294,16 +293,16 @@ _mmcamcorder_create_audio_pipeline(MMHandleType handle) void _mmcamcorder_destroy_audio_pipeline(MMHandleType handle) { - mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _MMCamcorderSubContext *sc = NULL; - _MMCamcorderAudioInfo* info = NULL; + _MMCamcorderAudioInfo *info = NULL; mmf_return_if_fail(hcamcorder); sc = MMF_CAMCORDER_SUBCONTEXT(handle); - mmf_return_if_fail(sc); + mmf_return_if_fail(sc && sc->info_audio); mmf_return_if_fail(sc->element); - info = sc->info; + info = sc->info_audio; _mmcam_dbg_log(""); @@ -373,27 +372,29 @@ int _mmcamcorder_audio_command(MMHandleType handle, int command) { int cmd = command; - GstElement *pipeline = NULL; - GstElement *audioSrc = NULL; int ret = MM_ERROR_NONE; int err = 0; - char *dir_name = NULL; int size=0; guint64 free_space = 0; - mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); - _MMCamcorderSubContext *sc = NULL; - _MMCamcorderAudioInfo *info = NULL; + char *dir_name = NULL; char *err_attr_name = NULL; - + + GstElement *pipeline = NULL; + GstElement *audioSrc = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + _MMCamcorderAudioInfo *info = NULL; + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); sc = MMF_CAMCORDER_SUBCONTEXT(handle); mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED); mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - mmf_return_val_if_fail(sc->info, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc->info_audio, MM_ERROR_CAMCORDER_NOT_INITIALIZED); pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; - info = sc->info; - + info = sc->info_audio; + _mmcam_dbg_log(""); pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; @@ -404,6 +405,7 @@ _mmcamcorder_audio_command(MMHandleType handle, int command) //check status for resume case if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) { + guint imax_size = 0; guint imax_time = 0; char *temp_filename = NULL; @@ -413,6 +415,7 @@ _mmcamcorder_audio_command(MMHandleType handle, int command) sc->pipeline_time = RESET_PAUSE_TIME; ret = mm_camcorder_get_attributes(handle, &err_attr_name, + MMCAM_TARGET_MAX_SIZE, &imax_size, MMCAM_TARGET_TIME_LIMIT, &imax_time, MMCAM_FILE_FORMAT, &(info->fileformat), MMCAM_TARGET_FILENAME, &temp_filename, &size, @@ -439,6 +442,13 @@ _mmcamcorder_audio_command(MMHandleType handle, int command) 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 */ @@ -684,11 +694,11 @@ _mmcamcorder_audio_handle_eos(MMHandleType handle) sc = MMF_CAMCORDER_SUBCONTEXT(handle); mmf_return_val_if_fail(sc, FALSE); - mmf_return_val_if_fail(sc->info, FALSE); + mmf_return_val_if_fail(sc->info_audio, FALSE); _mmcam_dbg_err(""); - info = sc->info; + info = sc->info_audio; //changing pipeline for display pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; @@ -708,8 +718,8 @@ _mmcamcorder_audio_handle_eos(MMHandleType handle) // ) //Send message - //Send recording report to application - msg.id = MM_MESSAGE_CAMCORDER_CAPTURED; + //Send recording report to application + msg.id = MM_MESSAGE_CAMCORDER_AUDIO_CAPTURED; report = (MMCamRecordingReport*) malloc(sizeof(MMCamRecordingReport)); //who free this? if (!report) @@ -911,6 +921,7 @@ static gboolean __mmcamcorder_audio_dataprobe_record(GstPad *pad, GstBuffer *buf guint64 buffer_size = 0; guint64 trailer_size = 0; char *filename = NULL; + unsigned long long remained_time = 0; _MMCamcorderSubContext *sc = NULL; mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); @@ -921,8 +932,8 @@ static gboolean __mmcamcorder_audio_dataprobe_record(GstPad *pad, GstBuffer *buf mmf_return_val_if_fail(buffer, FALSE); sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); - mmf_return_val_if_fail(sc && sc->info, FALSE); - info = sc->info; + mmf_return_val_if_fail(sc && sc->info_audio, FALSE); + info = sc->info_audio; if (sc->isMaxtimePausing || sc->isMaxsizePausing) { _mmcam_dbg_warn("isMaxtimePausing[%d],isMaxsizePausing[%d]", @@ -949,7 +960,9 @@ static gboolean __mmcamcorder_audio_dataprobe_record(GstPad *pad, GstBuffer *buf } /* get trailer size */ - if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) { + if (info->fileformat == MM_FILE_FORMAT_3GP || + info->fileformat == MM_FILE_FORMAT_MP4 || + info->fileformat == MM_FILE_FORMAT_AAC) { MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size); /*_mmcam_dbg_log("trailer_size %d", trailer_size);*/ } else { @@ -1014,6 +1027,48 @@ static gboolean __mmcamcorder_audio_dataprobe_record(GstPad *pad, GstBuffer *buf rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer)); + /* calculate remained time can be recorded */ + if (info->max_time > 0 && info->max_time < (remained_time + rec_pipe_time)) { + remained_time = info->max_time - rec_pipe_time; + } else if (info->max_size > 0) { + long double max_size = (long double)info->max_size; + long double current_size = (long double)(info->filesize + buffer_size + trailer_size); + + remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time; + } + + /*_mmcam_dbg_log("remained time : %u", remained_time);*/ + + /* check max size of recorded file */ + if (info->max_size > 0 && + info->max_size < info->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) { + _mmcam_dbg_warn("Max size!!! Recording is paused."); + _mmcam_dbg_warn("Max [%" G_GUINT64_FORMAT "], file [%" G_GUINT64_FORMAT "], trailer : [%" G_GUINT64_FORMAT "]", \ + info->max_size, info->filesize, trailer_size); + + /* just same as pause status. After blocking two queue, this function will not call again. */ + if (info->bMuxing) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE); + } else { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", TRUE); + } + + msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS; + msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time; + msg.param.recording_status.filesize = (unsigned long long)((info->filesize + trailer_size) >> 10); + msg.param.recording_status.remained_time = 0; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + + _mmcam_dbg_log("Last filesize sent by message : %d", info->filesize + trailer_size); + + sc->isMaxsizePausing = TRUE; + msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + + /* skip this buffer */ + return FALSE; + } + /* check recording time limit and send recording status message */ if (info->max_time > 0 && rec_pipe_time > info->max_time) { _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \ @@ -1038,8 +1093,9 @@ static gboolean __mmcamcorder_audio_dataprobe_record(GstPad *pad, GstBuffer *buf info->filesize += buffer_size; msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS; - msg.param.recording_status.elapsed = (unsigned int)rec_pipe_time; - msg.param.recording_status.filesize = (unsigned int)((info->filesize + trailer_size) >> 10); + msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time; + msg.param.recording_status.filesize = (unsigned long long)((info->filesize + trailer_size) >> 10); + msg.param.recording_status.remained_time = remained_time; _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); return TRUE; diff --git a/src/mm_camcorder_configure.c b/src/mm_camcorder_configure.c index ae4e205..ac05b02 100644 --- a/src/mm_camcorder_configure.c +++ b/src/mm_camcorder_configure.c @@ -19,11 +19,9 @@ * */ -/*=========================================================================================== -| | -| INCLUDE FILES | -| | -========================================================================================== */ +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ #include #include #include @@ -32,19 +30,19 @@ #include "mm_camcorder_internal.h" #include "mm_camcorder_configure.h" -/*--------------------------------------------------------------------------- -| MACRO DEFINITIONS: | ----------------------------------------------------------------------------*/ -#define CONFIGURE_PATH "/opt/etc" -#define CONFIGURE_PATH_RETRY "/usr/etc" +/*----------------------------------------------------------------------- +| MACRO DEFINITIONS: | +-----------------------------------------------------------------------*/ +#define CONFIGURE_PATH "/usr/etc" +#define CONFIGURE_PATH_RETRY "/opt/etc" -/*--------------------------------------------------------------------------- -| GLOBAL VARIABLE DEFINITIONS | ----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS | +-----------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------- -| LOCAL VARIABLE DEFINITIONS | ----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS | +-----------------------------------------------------------------------*/ static int conf_main_category_size[CONFIGURE_CATEGORY_MAIN_NUM] = { 0, }; static int conf_ctrl_category_size[CONFIGURE_CATEGORY_CTRL_NUM] = { 0, }; @@ -668,9 +666,9 @@ static type_element _matroska_element_default = { */ static conf_info_table conf_main_general_table[] = { { "SyncStateChange", CONFIGURE_VALUE_INT, {1} }, - { "GSTInitOption", CONFIGURE_VALUE_STRING_ARRAY, {NULL} }, - { "ModelName", CONFIGURE_VALUE_STRING, {(char*)"Samsung Camera"} }, - { "DisabledAttributes", CONFIGURE_VALUE_STRING_ARRAY, {NULL} }, + { "GSTInitOption", CONFIGURE_VALUE_STRING_ARRAY, {(int)NULL} }, + { "ModelName", CONFIGURE_VALUE_STRING, {(int)"Samsung Camera"} }, + { "DisabledAttributes", CONFIGURE_VALUE_STRING_ARRAY, {(int)NULL} }, }; /* @@ -678,34 +676,36 @@ static conf_info_table conf_main_general_table[] = { */ static conf_info_table conf_main_video_input_table[] = { { "UseConfCtrl", CONFIGURE_VALUE_INT, {1} }, - { "ConfCtrlFile0", CONFIGURE_VALUE_STRING, {(char*)"mmfw_camcorder_dev_video_pri.ini"} }, - { "ConfCtrlFile1", CONFIGURE_VALUE_STRING, {(char*)"mmfw_camcorder_dev_video_sec.ini"} }, - { "VideosrcElement", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_videosrc_element_default} }, + { "ConfCtrlFile0", CONFIGURE_VALUE_STRING, {(int)"mmfw_camcorder_dev_video_pri.ini"} }, + { "ConfCtrlFile1", CONFIGURE_VALUE_STRING, {(int)"mmfw_camcorder_dev_video_sec.ini"} }, + { "VideosrcElement", CONFIGURE_VALUE_ELEMENT, {(int)&_videosrc_element_default} }, { "UseVideoscale", CONFIGURE_VALUE_INT, {0} }, - { "VideoscaleElement", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_videoscale_element_default} }, + { "VideoscaleElement", CONFIGURE_VALUE_ELEMENT, {(int)&_videoscale_element_default} }, { "UseZeroCopyFormat", CONFIGURE_VALUE_INT, {0} }, + { "DeviceCount", CONFIGURE_VALUE_INT, {MM_VIDEO_DEVICE_NUM} }, }; /* * [AudioInput] matching table */ static conf_info_table conf_main_audio_input_table[] = { - { "AudiosrcElement", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_audiosrc_element_default} }, - { "AudiomodemsrcElement", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_audiomodemsrc_element_default} }, + { "AudiosrcElement", CONFIGURE_VALUE_ELEMENT, {(int)&_audiosrc_element_default} }, + { "AudiomodemsrcElement", CONFIGURE_VALUE_ELEMENT, {(int)&_audiomodemsrc_element_default} }, }; /* * [VideoOutput] matching table */ static conf_info_table conf_main_video_output_table[] = { - { "DisplayDevice", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "Videosink", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "VideosinkElementX", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_videosink_element_x_default} }, - { "VideosinkElementEvas", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_videosink_element_evas_default} }, - { "VideosinkElementGL", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_videosink_element_gl_default} }, - { "VideosinkElementNull", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_videosink_element_null_default} }, + { "DisplayDevice", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "DisplayMode", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "Videosink", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "VideosinkElementX", CONFIGURE_VALUE_ELEMENT, {(int)&_videosink_element_x_default} }, + { "VideosinkElementEvas", CONFIGURE_VALUE_ELEMENT, {(int)&_videosink_element_evas_default} }, + { "VideosinkElementGL", CONFIGURE_VALUE_ELEMENT, {(int)&_videosink_element_gl_default} }, + { "VideosinkElementNull", CONFIGURE_VALUE_ELEMENT, {(int)&_videosink_element_null_default} }, { "UseVideoscale", CONFIGURE_VALUE_INT, {0} }, - { "VideoscaleElement", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_videoscale_element_default} }, + { "VideoscaleElement", CONFIGURE_VALUE_ELEMENT, {(int)&_videoscale_element_default} }, }; /* @@ -714,15 +714,16 @@ static conf_info_table conf_main_video_output_table[] = { static conf_info_table conf_main_capture_table[] = { { "UseEncodebin", CONFIGURE_VALUE_INT, {0} }, { "UseCaptureMode", CONFIGURE_VALUE_INT, {0} }, - { "VideoscaleElement", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_videoscale_element_default} }, + { "VideoscaleElement", CONFIGURE_VALUE_ELEMENT, {(int)&_videoscale_element_default} }, + { "PlayCaptureSound", CONFIGURE_VALUE_INT, {1} }, }; /* * [Record] matching table */ static conf_info_table conf_main_record_table[] = { - { "UseAudioEncoderQueue", CONFIGURE_VALUE_INT, {1} }, - { "UseVideoEncoderQueue", CONFIGURE_VALUE_INT, {1} }, + { "UseAudioEncoderQueue", CONFIGURE_VALUE_INT, {1} }, + { "UseVideoEncoderQueue", CONFIGURE_VALUE_INT, {1} }, { "VideoProfile", CONFIGURE_VALUE_INT, {0} }, { "VideoAutoAudioConvert", CONFIGURE_VALUE_INT, {0} }, { "VideoAutoAudioResample", CONFIGURE_VALUE_INT, {0} }, @@ -735,7 +736,7 @@ static conf_info_table conf_main_record_table[] = { { "ImageAutoAudioConvert", CONFIGURE_VALUE_INT, {0} }, { "ImageAutoAudioResample", CONFIGURE_VALUE_INT, {0} }, { "ImageAutoColorSpace", CONFIGURE_VALUE_INT, {0} }, - { "RecordsinkElement", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_recordsink_element_default} }, + { "RecordsinkElement", CONFIGURE_VALUE_ELEMENT, {(int)&_recordsink_element_default} }, { "UseNoiseSuppressor", CONFIGURE_VALUE_INT, {0} }, { "DropVideoFrame", CONFIGURE_VALUE_INT, {0} }, { "PassFirstVideoFrame", CONFIGURE_VALUE_INT, {0} }, @@ -745,65 +746,65 @@ static conf_info_table conf_main_record_table[] = { * [VideoEncoder] matching table */ static conf_info_table conf_main_video_encoder_table[] = { - { "H263", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_h263_element_default} }, - { "H264", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_h264_element_default} }, - { "H26L", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_h26l_element_default} }, - { "MPEG4", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_mpeg4_element_default} }, - { "MPEG1", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_mpeg1_element_default} }, - { "THEORA", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_theora_element_default} }, + { "H263", CONFIGURE_VALUE_ELEMENT, {(int)&_h263_element_default} }, + { "H264", CONFIGURE_VALUE_ELEMENT, {(int)&_h264_element_default} }, + { "H26L", CONFIGURE_VALUE_ELEMENT, {(int)&_h26l_element_default} }, + { "MPEG4", CONFIGURE_VALUE_ELEMENT, {(int)&_mpeg4_element_default} }, + { "MPEG1", CONFIGURE_VALUE_ELEMENT, {(int)&_mpeg1_element_default} }, + { "THEORA", CONFIGURE_VALUE_ELEMENT, {(int)&_theora_element_default} }, }; /* * [AudioEncoder] matching table */ static conf_info_table conf_main_audio_encoder_table[] = { - { "AMR", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_amr_element_default} }, - { "G723_1", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_g723_1_element_default} }, - { "MP3", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_mp3_element_default} }, - { "AAC", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_aac_element_default} }, - { "MMF", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_mmf_element_default} }, - { "ADPCM", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_adpcm_element_default} }, - { "WAVE", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_wave_element_default} }, - { "MIDI", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_midi_element_default} }, - { "IMELODY", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_imelody_element_default} }, - { "VORBIS", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_vorbis_element_default} }, + { "AMR", CONFIGURE_VALUE_ELEMENT, {(int)&_amr_element_default} }, + { "G723_1", CONFIGURE_VALUE_ELEMENT, {(int)&_g723_1_element_default} }, + { "MP3", CONFIGURE_VALUE_ELEMENT, {(int)&_mp3_element_default} }, + { "AAC", CONFIGURE_VALUE_ELEMENT, {(int)&_aac_element_default} }, + { "MMF", CONFIGURE_VALUE_ELEMENT, {(int)&_mmf_element_default} }, + { "ADPCM", CONFIGURE_VALUE_ELEMENT, {(int)&_adpcm_element_default} }, + { "WAVE", CONFIGURE_VALUE_ELEMENT, {(int)&_wave_element_default} }, + { "MIDI", CONFIGURE_VALUE_ELEMENT, {(int)&_midi_element_default} }, + { "IMELODY", CONFIGURE_VALUE_ELEMENT, {(int)&_imelody_element_default} }, + { "VORBIS", CONFIGURE_VALUE_ELEMENT, {(int)&_vorbis_element_default} }, }; /* * [ImageEncoder] matching table */ static conf_info_table conf_main_image_encoder_table[] = { - { "JPEG", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_jpeg_element_default} }, - { "PNG", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_png_element_default} }, - { "BMP", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_bmp_element_default} }, - { "WBMP", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_wbmp_element_default} }, - { "TIFF", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_tiff_element_default} }, - { "PCX", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_pcx_element_default} }, - { "GIF", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_gif_element_default} }, - { "ICO", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_ico_element_default} }, - { "RAS", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_ras_element_default} }, - { "TGA", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_tga_element_default} }, - { "XBM", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_xbm_element_default} }, - { "XPM", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_xpm_element_default} }, + { "JPEG", CONFIGURE_VALUE_ELEMENT, {(int)&_jpeg_element_default} }, + { "PNG", CONFIGURE_VALUE_ELEMENT, {(int)&_png_element_default} }, + { "BMP", CONFIGURE_VALUE_ELEMENT, {(int)&_bmp_element_default} }, + { "WBMP", CONFIGURE_VALUE_ELEMENT, {(int)&_wbmp_element_default} }, + { "TIFF", CONFIGURE_VALUE_ELEMENT, {(int)&_tiff_element_default} }, + { "PCX", CONFIGURE_VALUE_ELEMENT, {(int)&_pcx_element_default} }, + { "GIF", CONFIGURE_VALUE_ELEMENT, {(int)&_gif_element_default} }, + { "ICO", CONFIGURE_VALUE_ELEMENT, {(int)&_ico_element_default} }, + { "RAS", CONFIGURE_VALUE_ELEMENT, {(int)&_ras_element_default} }, + { "TGA", CONFIGURE_VALUE_ELEMENT, {(int)&_tga_element_default} }, + { "XBM", CONFIGURE_VALUE_ELEMENT, {(int)&_xbm_element_default} }, + { "XPM", CONFIGURE_VALUE_ELEMENT, {(int)&_xpm_element_default} }, }; /* * [Mux] matching table */ static conf_info_table conf_main_mux_table[] = { - { "3GP", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_3gp_element_default} }, - { "AMR", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_amrmux_element_default} }, - { "MP4", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_mp4_element_default} }, - { "AAC", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_aacmux_element_default} }, - { "MP3", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_mp3mux_element_default} }, - { "OGG", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_ogg_element_default} }, - { "WAV", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_wav_element_default} }, - { "AVI", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_avi_element_default} }, - { "WMA", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_wma_element_default} }, - { "WMV", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_wmv_element_default} }, - { "MID", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_mid_element_default} }, - { "MMF", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_mmfmux_element_default} }, - { "MATROSKA", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_matroska_element_default} }, + { "3GP", CONFIGURE_VALUE_ELEMENT, {(int)&_3gp_element_default} }, + { "AMR", CONFIGURE_VALUE_ELEMENT, {(int)&_amrmux_element_default} }, + { "MP4", CONFIGURE_VALUE_ELEMENT, {(int)&_mp4_element_default} }, + { "AAC", CONFIGURE_VALUE_ELEMENT, {(int)&_aacmux_element_default} }, + { "MP3", CONFIGURE_VALUE_ELEMENT, {(int)&_mp3mux_element_default} }, + { "OGG", CONFIGURE_VALUE_ELEMENT, {(int)&_ogg_element_default} }, + { "WAV", CONFIGURE_VALUE_ELEMENT, {(int)&_wav_element_default} }, + { "AVI", CONFIGURE_VALUE_ELEMENT, {(int)&_avi_element_default} }, + { "WMA", CONFIGURE_VALUE_ELEMENT, {(int)&_wma_element_default} }, + { "WMV", CONFIGURE_VALUE_ELEMENT, {(int)&_wmv_element_default} }, + { "MID", CONFIGURE_VALUE_ELEMENT, {(int)&_mid_element_default} }, + { "MMF", CONFIGURE_VALUE_ELEMENT, {(int)&_mmfmux_element_default} }, + { "MATROSKA", CONFIGURE_VALUE_ELEMENT, {(int)&_matroska_element_default} }, }; @@ -815,79 +816,85 @@ static conf_info_table conf_main_mux_table[] = { * [Camera] matching table */ static conf_info_table conf_ctrl_camera_table[] = { - { "InputIndex", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "DeviceName", CONFIGURE_VALUE_STRING, {NULL} }, - { "PreviewResolution", CONFIGURE_VALUE_INT_PAIR_ARRAY, {NULL} }, - { "CaptureResolution", CONFIGURE_VALUE_INT_PAIR_ARRAY, {NULL} }, - { "FPS", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "PictureFormat", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "Overlay", CONFIGURE_VALUE_INT_RANGE, {NULL} }, + { "InputIndex", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "DeviceName", CONFIGURE_VALUE_STRING, {(int)NULL} }, + { "PreviewResolution", CONFIGURE_VALUE_INT_PAIR_ARRAY, {(int)NULL} }, + { "CaptureResolution", CONFIGURE_VALUE_INT_PAIR_ARRAY, {(int)NULL} }, + { "FPS", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "PictureFormat", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "Overlay", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, { "RecommendDisplayRotation", CONFIGURE_VALUE_INT, {3} }, { "RecommendPreviewFormatCapture", CONFIGURE_VALUE_INT, {MM_PIXEL_FORMAT_YUYV} }, { "RecommendPreviewFormatRecord", CONFIGURE_VALUE_INT, {MM_PIXEL_FORMAT_NV12} }, + { "RecommendPreviewResolution", CONFIGURE_VALUE_INT_PAIR_ARRAY, {(int)NULL} }, + { "FacingDirection", CONFIGURE_VALUE_INT, {MM_CAMCORDER_CAMERA_FACING_DIRECTION_REAR} }, }; /* * [Strobe] matching table */ static conf_info_table conf_ctrl_strobe_table[] = { - { "StrobeControl", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "StrobeMode", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "StrobeEV", CONFIGURE_VALUE_INT_RANGE, {NULL} }, + { "StrobeControl", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "StrobeMode", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "StrobeEV", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, }; /* * [Effect] matching table */ static conf_info_table conf_ctrl_effect_table[] = { - { "Brightness", CONFIGURE_VALUE_INT_RANGE, {NULL} }, - { "Contrast", CONFIGURE_VALUE_INT_RANGE, {NULL} }, - { "Saturation", CONFIGURE_VALUE_INT_RANGE, {NULL} }, - { "Sharpness", CONFIGURE_VALUE_INT_RANGE, {NULL} }, - { "WhiteBalance", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "ColorTone", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "Flip", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "WDR", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "PartColorMode", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "PartColor", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, + { "Brightness", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, + { "Contrast", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, + { "Saturation", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, + { "Sharpness", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, + { "WhiteBalance", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "ColorTone", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "Flip", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "WDR", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "PartColorMode", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "PartColor", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, }; /* * [Photograph] matching table */ static conf_info_table conf_ctrl_photograph_table[] = { - { "LensInit", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "DigitalZoom", CONFIGURE_VALUE_INT_RANGE, {NULL} }, - { "OpticalZoom", CONFIGURE_VALUE_INT_RANGE, {NULL} }, - { "FocusMode", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "AFType", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "AEType", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "ExposureValue", CONFIGURE_VALUE_INT_RANGE, {NULL} }, - { "FNumber", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "ShutterSpeed", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "ISO", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "ProgramMode", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "AntiHandshake", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, + { "LensInit", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "DigitalZoom", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, + { "OpticalZoom", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, + { "FocusMode", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "AFType", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "AEType", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "ExposureValue", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, + { "FNumber", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "ShutterSpeed", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "ISO", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "ProgramMode", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "AntiHandshake", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "VideoStabilization", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "FaceZoomMode", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "FaceZoomLevel", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, }; /* * [Capture] matching table */ static conf_info_table conf_ctrl_capture_table[] = { - { "OutputMode", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "JpegQuality", CONFIGURE_VALUE_INT_RANGE, {NULL} }, - { "MultishotNumber", CONFIGURE_VALUE_INT_RANGE, {NULL} }, + { "OutputMode", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "JpegQuality", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, + { "MultishotNumber", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, { "SensorEncodedCapture", CONFIGURE_VALUE_INT, {1} }, + { "SupportHDR", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, }; /* * [Detect] matching table */ static conf_info_table conf_ctrl_detect_table[] = { - { "DetectMode", CONFIGURE_VALUE_INT_ARRAY, {NULL} }, - { "DetectNumber", CONFIGURE_VALUE_INT_RANGE, {NULL} }, - { "DetectSelect", CONFIGURE_VALUE_INT_RANGE, {NULL} }, - { "DetectSelectNumber", CONFIGURE_VALUE_INT_RANGE, {NULL} }, + { "DetectMode", CONFIGURE_VALUE_INT_ARRAY, {(int)NULL} }, + { "DetectNumber", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, + { "DetectSelect", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, + { "DetectSelectNumber", CONFIGURE_VALUE_INT_RANGE, {(int)NULL} }, }; @@ -898,16 +905,14 @@ get_new_string( char* src_string ) return strdup(src_string); } -void -_mmcamcorder_conf_init( int type, camera_conf** configure_info ) +void _mmcamcorder_conf_init(int type, camera_conf** configure_info) { int i = 0; - int info_table_size = sizeof( conf_info_table ); - - _mmcam_dbg_log( "Entered..." ); + int info_table_size = sizeof(conf_info_table); - if( type == CONFIGURE_TYPE_MAIN ) - { + _mmcam_dbg_log("Entered..."); + + if (type == CONFIGURE_TYPE_MAIN) { conf_main_info_table[CONFIGURE_CATEGORY_MAIN_GENERAL] = conf_main_general_table; conf_main_info_table[CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT] = conf_main_video_input_table; conf_main_info_table[CONFIGURE_CATEGORY_MAIN_AUDIO_INPUT] = conf_main_audio_input_table; @@ -932,13 +937,10 @@ _mmcamcorder_conf_init( int type, camera_conf** configure_info ) (*configure_info)->info = (conf_info**)g_malloc0( sizeof( conf_info* ) * CONFIGURE_CATEGORY_MAIN_NUM ); - for( i = 0 ; i < CONFIGURE_CATEGORY_MAIN_NUM ; i++ ) - { + for (i = 0 ; i < CONFIGURE_CATEGORY_MAIN_NUM ; i++) { (*configure_info)->info[i] = NULL; } - } - else - { + } else { conf_ctrl_info_table[CONFIGURE_CATEGORY_CTRL_CAMERA] = conf_ctrl_camera_table; conf_ctrl_info_table[CONFIGURE_CATEGORY_CTRL_STROBE] = conf_ctrl_strobe_table; conf_ctrl_info_table[CONFIGURE_CATEGORY_CTRL_EFFECT] = conf_ctrl_effect_table; @@ -955,14 +957,14 @@ _mmcamcorder_conf_init( int type, camera_conf** configure_info ) (*configure_info)->info = (conf_info**)g_malloc0( sizeof( conf_info* ) * CONFIGURE_CATEGORY_CTRL_NUM ); - for( i = 0 ; i < CONFIGURE_CATEGORY_CTRL_NUM ; i++ ) - { - (*configure_info)->info[i] = NULL; + for (i = 0 ; i < CONFIGURE_CATEGORY_CTRL_NUM ; i++) { + (*configure_info)->info[i] = NULL; } } - - _mmcam_dbg_log( "Done." ); + _mmcam_dbg_log("Done."); + + return; } @@ -1146,6 +1148,7 @@ _mmcamcorder_conf_parse_info( int type, FILE* fd, camera_conf** configure_info ) if( count_details == 0 ) { _mmcam_dbg_warn( "category %s has no detail value... skip this category...", category_name ); + SAFE_FREE(category_name); continue; } @@ -1244,10 +1247,7 @@ _mmcamcorder_conf_parse_info( int type, FILE* fd, camera_conf** configure_info ) } } - if( category_name ) - { - SAFE_FREE( category_name ); - } + SAFE_FREE(category_name); } //(*configure_info) = new_conf; @@ -2993,203 +2993,155 @@ _mmcamcorder_get_type_element(MMHandleType handle, int type) } -int -_mmcamcorder_get_audio_codec_format(MMHandleType handle, char * name) +int _mmcamcorder_get_audio_codec_format(MMHandleType handle, char *name) { - int i = 0; - char* audio_fmt_type[] = { - "AMR", /**< AMR codec*/ - "G723_1", /**< G723.1 codec*/ - "MP3", /**< MP3 codec*/ - "OGG", /**< OGG codec*/ - "AAC", /**< AAC codec*/ - "WMA", /**< WMA codec*/ - "MMF", /**< MMF codec*/ - "ADPCM", /**< ADPCM codec */ - "WAVE", /**< WAVE codec */ - "WAVE_NEW", /**< WAVE codec */ - "MIDI", /**< MIDI codec */ - "IMELODY", /**< IMELODY codec */ - "MXMF", - "MPA", /**< MPEG1-Layer1 codec */ - "MP2", /**< MPEG1-Layer2 codec */ - "G711", /**< G711 codec */ - "G722", /**< G722 wideband speech codec */ - "G722_1", /**< G722.1 codec */ - "G722_2", /**< G722.2 (AMR-WB) codec */ - "G723", /**< G723 wideband speech codec */ - "G726", /**< G726 (ADPCM) codec */ - "G728", /**< G728 speech codec */ - "G729", /**< G729 codec */ - "G729A", /**< G729a codec */ - "G729_1", /**< G729.1 codec */ - "REAL", /**< Real audio */ - "AAC_LC", /**< AAC-Low complexity codec */ - "AAC_MAIN", /**< AAC-Main profile codec */ - "AAC_SRS", /**< AAC-Scalable sample rate codec */ - "AAC_LTP", /**< AAC-Long term prediction codec */ - "AAC_HE_V1", /**< AAC-High Efficiency v1 codec */ - "AAC_HE_V2", /**< AAC-High efficiency v2 codec */ - "AC3", /**< DolbyDigital codec */ - "ALAC", /**< Apple Lossless audio codec */ - "ATRAC", /**< Sony audio codec */ - "SPEEX", /**< SPEEX audio codec */ - "VORBIS", /**< Vor*/ - "AIFF", /**< AIFF codec*/ - "AU", /**< AU codec*/ - "NONE", /**< None (will be deprecated) */ - "PCM", /**< PCM codec */ - "ALAW", /**< ALAW codec */ - "MULAW", /**< MULAW codec */ - "MS_ADPCM" /**< MS ADPCM codec */ - }; - - for (i = 0; i < MM_AUDIO_CODEC_NUM; i++) - { - if (!strcmp(name, audio_fmt_type[i])) - { -// _mmcam_dbg_log( "Audio codec[%d]", i); - return i; - } + int codec_index = MM_AUDIO_CODEC_INVALID; + + if (!name) { + _mmcam_dbg_err("name is NULL"); + return MM_AUDIO_CODEC_INVALID; + } + + if (!strcmp(name, "AMR")) { + codec_index = MM_AUDIO_CODEC_AMR; + } else if (!strcmp(name, "G723_1")) { + codec_index = MM_AUDIO_CODEC_G723_1; + } else if (!strcmp(name, "MP3")) { + codec_index = MM_AUDIO_CODEC_MP3; + } else if (!strcmp(name, "AAC")) { + codec_index = MM_AUDIO_CODEC_AAC; + } else if (!strcmp(name, "MMF")) { + codec_index = MM_AUDIO_CODEC_MMF; + } else if (!strcmp(name, "ADPCM")) { + codec_index = MM_AUDIO_CODEC_ADPCM; + } else if (!strcmp(name, "WAVE")) { + codec_index = MM_AUDIO_CODEC_WAVE; + } else if (!strcmp(name, "MIDI")) { + codec_index = MM_AUDIO_CODEC_MIDI; + } else if (!strcmp(name, "IMELODY")) { + codec_index = MM_AUDIO_CODEC_IMELODY; + } else if (!strcmp(name, "VORBIS")) { + codec_index = MM_AUDIO_CODEC_VORBIS; } - _mmcam_dbg_err( "Not supported audio codec[%s]", name); - return -1; + _mmcam_dbg_log("audio codec index %d", codec_index); + return codec_index; } -int -_mmcamcorder_get_video_codec_format(MMHandleType handle, char * name) +int _mmcamcorder_get_video_codec_format(MMHandleType handle, char *name) { - int i = 0; - char* video_fmt_type[] = { - "NONE", /**< None (will be deprecated) */ - "H263", /**< H263 codec*/ - "H264", /**< H264 codec*/ - "H26L", /**< H26L codec*/ - "MPEG4", /**< MPEG4 codec*/ - "MPEG1", /**< MPEG1 codec*/ - "WMV", /**< WMV codec*/ - "DIVX", /**< DIVX codec*/ - "XVID", /**< XVID codec*/ - "H261", /**< H261 codec*/ - "H262", /**< H262/MPEG2-part2 codec*/ - "H263V2", /**< H263v2 codec*/ - "H263V3", /**< H263v3 codec*/ - "MJPEG", /**< Motion JPEG Video codec*/ - "MPEG2", /**< MPEG2 codec*/ - "MPEG4_SIMPLE", /**< MPEG4 part-2 Simple profile codec*/ - "MPEG4_ADV_SIMPLE",/**< MPEG4 part-2 Advanced Simple profile codec*/ - "MPEG4_MAIN", /**< MPEG4 part-2 Main profile codec*/ - "MPEG4_CORE", /**< MPEG4 part-2 Core profile codec*/ - "MPEG4_ACE", /**< MPEG4 part-2 Adv Coding Eff profile codec*/ - "MPEG4_ARTS", /**< MPEG4 part-2 Adv RealTime Simple profile codec*/ - "MPEG4_AVC", /**< MPEG4 part-10 (h.264) codec*/ - "REAL", /**< Real video*/ - "VC1", /**< VC-1 video*/ - "AVS", /**< AVS video*/ - "CINEPAK", /**< Cinepak videocodec */ - "INDEO", /**< Indeo videocodec */ - "THEORA" /**< Theora videocodec */ - }; - - for (i = 0; i < MM_VIDEO_CODEC_NUM; i++) - { - if (!strcmp(name, video_fmt_type[i])) - { -// _mmcam_dbg_log( "Video codec[%d]", i); - return i; - } + int codec_index = MM_VIDEO_CODEC_INVALID; + + if (!name) { + _mmcam_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, "H26L")) { + codec_index = MM_VIDEO_CODEC_H26L; + } else if (!strcmp(name, "MPEG4")) { + codec_index = MM_VIDEO_CODEC_MPEG4; + } else if (!strcmp(name, "MPEG1")) { + codec_index = MM_VIDEO_CODEC_MPEG1; + } else if (!strcmp(name, "THEORA")) { + codec_index = MM_VIDEO_CODEC_THEORA; } - _mmcam_dbg_err( "Not supported Video codec[%s]", name); - return -1; + _mmcam_dbg_log("video codec index %d", codec_index); + return codec_index; } -int -_mmcamcorder_get_image_codec_format(MMHandleType handle, char * name) +int _mmcamcorder_get_image_codec_format(MMHandleType handle, char *name) { - int i = 0; - char* image_fmt_type[] = { - "JPEG", /**< JPEG codec */ - "PNG", /**< PNG codec */ - "BMP", /**< BMP codec */ - "WBMP", /**< WBMP codec */ - "TIFF", /**< TIFF codec */ - "PCX", /**< PCX codec */ - "GIF", /**< GIF codec */ - "ICO", /**< ICO codec */ - "RAS", /**< RAS codec */ - "TGA", /**< TGA codec */ - "XBM", /**< XBM codec */ - "XPM" /**< XPM codec */ - "SRW" /**< SRW (Samsung standard RAW) */ - "JPEG_SRW" /**< JPEG + SRW */ - }; - - for (i = 0; i < MM_IMAGE_CODEC_NUM; i++) - { - if (!strcmp(name, image_fmt_type[i])) - { -// _mmcam_dbg_log( "Image codec[%d]", i); - return i; - } + int codec_index = MM_IMAGE_CODEC_INVALID; + + if (!name) { + _mmcam_dbg_err("name is NULL"); + return MM_IMAGE_CODEC_INVALID; + } + + if (!strcmp(name, "JPEG")) { + codec_index = MM_IMAGE_CODEC_JPEG; + } else if (!strcmp(name, "PNG")) { + codec_index = MM_IMAGE_CODEC_PNG; + } else if (!strcmp(name, "BMP")) { + codec_index = MM_IMAGE_CODEC_BMP; + } else if (!strcmp(name, "WBMP")) { + codec_index = MM_IMAGE_CODEC_WBMP; + } else if (!strcmp(name, "TIFF")) { + codec_index = MM_IMAGE_CODEC_TIFF; + } else if (!strcmp(name, "PCX")) { + codec_index = MM_IMAGE_CODEC_PCX; + } else if (!strcmp(name, "GIF")) { + codec_index = MM_IMAGE_CODEC_GIF; + } else if (!strcmp(name, "ICO")) { + codec_index = MM_IMAGE_CODEC_ICO; + } else if (!strcmp(name, "RAS")) { + codec_index = MM_IMAGE_CODEC_RAS; + } else if (!strcmp(name, "TGA")) { + codec_index = MM_IMAGE_CODEC_TGA; + } else if (!strcmp(name, "XBM")) { + codec_index = MM_IMAGE_CODEC_XBM; + } else if (!strcmp(name, "XPM")) { + codec_index = MM_IMAGE_CODEC_XPM; } - _mmcam_dbg_err( "Not supported Image codec[%s]", name); - return -1; + _mmcam_dbg_log("image codec index %d", codec_index); + return codec_index; } -int -_mmcamcorder_get_mux_format(MMHandleType handle, char * name) +int _mmcamcorder_get_mux_format(MMHandleType handle, char *name) { - int i = 0; - char* mux_fmt_type[] = { - "3GP", /**< 3GP file format */ - "ASF", /**< Advanced Systems File file format */ - "AVI", /**< Audio Video Interleaved file format */ - "MATROSKA", /**< MATROSAK file format */ - "MP4", /**< MP4 file format */ - "OGG", /**< OGG file format */ - "NUT", /**< NUT file format */ - "QT", /**< MOV file format */ - "REAL", /**< RealMedia file format */ - "AMR", /**< AMR file format */ - "AAC", /**< AAC file format */ - "MP3", /**< MP3 file format */ - "AIFF", /**< AIFF file format */ - "AU", /**< Audio file format */ - "WAV", /**< WAV file format */ - "MID", /**< MID file format */ - "MMF", /**< MMF file format */ - "DIVX", /**< DivX file format */ - "FLV", /**< Flash video file format */ - "VOB", /**< DVD-Video Object file format */ - "IMELODY", /**< IMelody file format */ - "WMA", /**< WMA file format */ - "WMV", /**< WMV file format */ - "JPG" /**< JPEG file format */ - }; - - for (i = 0; i < MM_FILE_FORMAT_NUM; i++) - { - if (!strcmp(name, mux_fmt_type[i])) - { -// _mmcam_dbg_log( "Mux[%d]", i); - return i; - } + int mux_index = MM_FILE_FORMAT_INVALID; + + if (!name) { + _mmcam_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, "AAC")) { + mux_index = MM_FILE_FORMAT_AAC; + } else if (!strcmp(name, "MP3")) { + mux_index = MM_FILE_FORMAT_MP3; + } else if (!strcmp(name, "OGG")) { + mux_index = MM_FILE_FORMAT_OGG; + } else if (!strcmp(name, "WAV")) { + mux_index = MM_FILE_FORMAT_WAV; + } else if (!strcmp(name, "AVI")) { + mux_index = MM_FILE_FORMAT_AVI; + } else if (!strcmp(name, "WMA")) { + mux_index = MM_FILE_FORMAT_WMA; + } else if (!strcmp(name, "WMV")) { + mux_index = MM_FILE_FORMAT_WMV; + } else if (!strcmp(name, "MID")) { + mux_index = MM_FILE_FORMAT_MID; + } else if (!strcmp(name, "MMF")) { + mux_index = MM_FILE_FORMAT_MMF; + } else if (!strcmp(name, "MATROSKA")) { + mux_index = MM_FILE_FORMAT_MATROSKA; } - _mmcam_dbg_err( "Not supported Mux[%s]", name); - return -1; + _mmcam_dbg_log("mux index %d", mux_index); + return mux_index; } @@ -3235,42 +3187,37 @@ _mmcamcorder_get_available_format(MMHandleType handle, int conf_category, int ** configure_info = hcamcorder->conf_main; - if( configure_info->info[conf_category] ) - { - int count = configure_info->info[conf_category]->count; - conf_info* info = configure_info->info[conf_category]; + if (configure_info->info[conf_category]) { int i = 0; int fmt = 0; - char* name = NULL; + char *name = NULL; + int count = configure_info->info[conf_category]->count; + conf_info *info = configure_info->info[conf_category]; _mmcam_dbg_log("count[%d], info[%p]", count, info); - if ((count <= 0) || (!info)) - { + if (count <= 0 || !info) { return total_count; } arr = (int*) g_malloc0(count * sizeof(int)); - for( i = 0 ; i < count ; i++ ) - { - if( info->detail_info[i] == NULL ) - { + for (i = 0 ; i < count ; i++) { + if (info->detail_info[i] == NULL) { continue; } - + name = ((type_element*)(info->detail_info[i]))->name; - - if ((fmt = _mmcamcorder_get_format(handle, conf_category, name)) >= 0) - { + fmt = _mmcamcorder_get_format(handle, conf_category, name); + if (fmt >= 0) { arr[total_count++] = fmt; } + _mmcam_dbg_log("name:%s, fmt:%d", name, fmt); } } - + *format = arr; return total_count; } - diff --git a/src/mm_camcorder_exifinfo.c b/src/mm_camcorder_exifinfo.c index a1a2f2e..1c03789 100644 --- a/src/mm_camcorder_exifinfo.c +++ b/src/mm_camcorder_exifinfo.c @@ -33,9 +33,14 @@ #include #include -#define MM_EXIFINFO_USE_BINARY_EXIFDATA 1 -#define JPEG_MAX_SIZE 20000000 -#define JPEG_THUMBNAIL_MAX_SIZE (128*1024) +#define MM_EXIFINFO_USE_BINARY_EXIFDATA 1 +#define JPEG_MAX_SIZE 20000000 +#define JPEG_THUMBNAIL_MAX_SIZE (128*1024) +#define JPEG_DATA_OFFSET 2 +#define EXIF_MARKER_SOI_LENGTH 2 +#define EXIF_MARKER_APP1_LENGTH 2 +#define EXIF_APP1_LENGTH 2 + #if MM_EXIFINFO_USE_BINARY_EXIFDATA /** * Exif Binary Data. @@ -86,6 +91,7 @@ _exif_set_uint16 (int is_motorola, void * out, unsigned short in) } +#ifdef _MMCAMCORDER_EXIF_GET_JPEG_MARKER_OFFSET static unsigned long _exif_get_jpeg_marker_offset (void *jpeg, int jpeg_size, unsigned short marker) { @@ -129,6 +135,7 @@ _exif_get_jpeg_marker_offset (void *jpeg, int jpeg_size, unsigned short marker) mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s]Marker not found.\n", __LINE__, __func__); return 0UL; } +#endif /* _MMCAMCORDER_EXIF_GET_JPEG_MARKER_OFFSET */ ExifData* @@ -210,45 +217,48 @@ mm_exif_set_exif_to_info (mm_exif_info_t *info, ExifData *exif) int mm_exif_set_add_entry (ExifData *exif, ExifIfd ifd, ExifTag tag,ExifFormat format,unsigned long components,unsigned char* data) { -// mmf_debug (MMF_DEBUG_LOG, "%s()\n", __func__); - ExifData *ed = (ExifData *)exif; - ExifEntry *e = NULL; + /*mmf_debug (MMF_DEBUG_LOG, "%s()\n", __func__);*/ + ExifData *ed = (ExifData *)exif; + ExifEntry *e = NULL; - if(exif==NULL || format<=0 || components<=0 || data==NULL) - { - mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] invalid argument exif=%p format=%d, components=%lu data=%p!\n", __LINE__, __func__,exif,format,components,data); + if (exif == NULL || format <= 0 || components <= 0 || data == NULL) { + mmf_debug(MMF_DEBUG_ERROR,"[%05d][%s] invalid argument exif=%p format=%d, components=%lu data=%p!\n", + __LINE__, __func__,exif,format,components,data); return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; } + /*remove same tag in EXIF*/ - exif_content_remove_entry (ed->ifd[ifd], exif_content_get_entry(ed->ifd[ifd], tag)); + exif_content_remove_entry(ed->ifd[ifd], exif_content_get_entry(ed->ifd[ifd], tag)); + /*create new tag*/ - e = exif_entry_new (); - if(e==NULL) - { - mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] entry create error!\n", __LINE__, __func__); + e = exif_entry_new(); + if (e == NULL) { + mmf_debug(MMF_DEBUG_ERROR,"[%05d][%s] entry create error!\n", __LINE__, __func__); return MM_ERROR_CAMCORDER_LOW_MEMORY; } - exif_entry_initialize (e, tag); - e->tag = tag; - e->format = format; - e->components = components; + exif_entry_initialize(e, tag); - if(e->size==0) - { - e->data=NULL; - e->data=malloc(exif_format_get_size(format)*e->components); - if(!e->data) - { + e->tag = tag; + e->format = format; + e->components = components; + + if (e->size == 0) { + e->data = NULL; + e->data = malloc(exif_format_get_size(format) * e->components); + if (!e->data) { exif_entry_unref(e); return MM_ERROR_CAMCORDER_LOW_MEMORY; } - if(format==EXIF_FORMAT_ASCII) - memset (e->data, '\0', exif_format_get_size(format)*e->components); + + if (format == EXIF_FORMAT_ASCII) { + memset(e->data, '\0', exif_format_get_size(format) * e->components); + } } - e->size = exif_format_get_size(format)*e->components; + + e->size = exif_format_get_size(format) * e->components; memcpy(e->data,data,e->size); - exif_content_add_entry (ed->ifd[ifd], e); + exif_content_add_entry(ed->ifd[ifd], e); exif_entry_unref(e); return MM_ERROR_NONE; @@ -265,64 +275,63 @@ mm_exif_set_add_entry (ExifData *exif, ExifIfd ifd, ExifTag tag,ExifFormat forma int mm_exif_create_exif_info (mm_exif_info_t **info) { - mm_exif_info_t *x = NULL; + mm_exif_info_t *x = NULL; #if (MM_EXIFINFO_USE_BINARY_EXIFDATA == 0) - ExifData *ed = NULL; - unsigned char *eb = NULL; - unsigned int ebs; + ExifData *ed = NULL; + unsigned char *eb = NULL; + unsigned int ebs; #endif - mmf_debug (MMF_DEBUG_LOG,"[%05d][%s]\n", __LINE__, __func__); - x = malloc (sizeof (mm_exif_info_t)); - if(!x) - { - mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s]malloc error\n", __LINE__, __func__); + if (!info) { + mmf_debug(MMF_DEBUG_ERROR,"[%05d][%s] NULL pointer\n", __LINE__, __func__); + return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + } + + x = malloc(sizeof(mm_exif_info_t)); + if (!x) { + mmf_debug(MMF_DEBUG_ERROR,"[%05d][%s]malloc error\n", __LINE__, __func__); return MM_ERROR_CAMCORDER_LOW_MEMORY; - } + } #if MM_EXIFINFO_USE_BINARY_EXIFDATA - x->data=NULL; - x->data = malloc (_EXIF_BIN_SIZE_); - if(!x->data) - { - mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s]malloc error\n", __LINE__, __func__); + x->data = NULL; + x->data = malloc(_EXIF_BIN_SIZE_); + if (!x->data) { + mmf_debug(MMF_DEBUG_ERROR,"[%05d][%s]malloc error\n", __LINE__, __func__); free(x); return MM_ERROR_CAMCORDER_LOW_MEMORY; - } - memcpy (x->data, g_exif_bin, _EXIF_BIN_SIZE_); + } + memcpy(x->data, g_exif_bin, _EXIF_BIN_SIZE_); x->size = _EXIF_BIN_SIZE_; #else - ed = exif_data_new (); - if(!ed ) - { - mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s]exif data new error\n", __LINE__, __func__); + ed = exif_data_new(); + if (!ed) { + mmf_debug(MMF_DEBUG_ERROR,"[%05d][%s]exif data new error\n", __LINE__, __func__); return MM_ERROR_CAMCORDER_LOW_MEMORY; - } - - exif_data_set_byte_order (ed, EXIF_BYTE_ORDER_INTEL); - exif_data_set_data_type (ed, EXIF_DATA_TYPE_COMPRESSED); - exif_data_set_option (ed, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); - - exif_data_fix (ed); - - exif_data_save_data (ed, &eb, &ebs); - if(eb==NULL) - { - mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s]exif_data_save_data error\n", __LINE__, __func__); + } + + exif_data_set_byte_order(ed, EXIF_BYTE_ORDER_INTEL); + exif_data_set_data_type(ed, EXIF_DATA_TYPE_COMPRESSED); + exif_data_set_option(ed, EXIF_DATA_OPTION_FOLLOW_SPECIFICATION); + + exif_data_fix(ed); + + exif_data_save_data(ed, &eb, &ebs); + if (eb == NULL) { + mmf_debug(MMF_DEBUG_ERROR,"[%05d][%s]exif_data_save_data error\n", __LINE__, __func__); free(x->data); free(x); - exif_data_unref (ed); + exif_data_unref(ed); return MM_ERROR_CAMCORDER_INTERNAL; - } - exif_data_unref (ed); + } + exif_data_unref(ed); x->data = eb; x->size = ebs; #endif - *info = x; - //mmf_debug (MMF_DEBUG_LOG, "%s() Data:%p Size:%d\n", __func__, x->data, x->size); + mmf_debug(MMF_DEBUG_LOG, "%s() Data:%p Size:%d\n", __func__, x->data, x->size); return MM_ERROR_NONE; } @@ -368,7 +377,7 @@ mm_exif_add_thumbnail_info (mm_exif_info_t *info, void *thumbnail, int width, in /* get ExifData from info*/ ed = mm_exif_get_exif_from_info(info); - ed->data=thumbnail; + ed->data = thumbnail; ed->size = len; /* set thumbnail data */ @@ -400,7 +409,7 @@ mm_exif_add_thumbnail_info (mm_exif_info_t *info, void *thumbnail, int width, in if (ret != MM_ERROR_NONE) { goto exit; } - + ed->data = NULL; ed->size = 0; exif_data_unref (ed); @@ -524,24 +533,17 @@ int mm_exif_mnote_set_add_entry (ExifData *exif, MnoteSamsungTag tag, int index, int mm_exif_write_exif_jpeg_to_file (char *filename, mm_exif_info_t *info, void *jpeg, int jpeg_len) { - FILE *fp = NULL; - unsigned long offset_jpeg_start; - unsigned short head[2]={0,}; - unsigned short head_len=0; - unsigned char *eb = NULL; - unsigned int ebs; + FILE *fp = NULL; + unsigned short head[2] = {0,}; + unsigned short head_len = 0; + unsigned char *eb = NULL; + unsigned int ebs; mmf_debug (MMF_DEBUG_LOG,"[%05d][%s]\n", __LINE__, __func__); eb = info->data; ebs = info->size; - /*get DQT*/ - offset_jpeg_start = _exif_get_jpeg_marker_offset (jpeg, jpeg_len, 0xffdb); - if (offset_jpeg_start == 0) { - return -1; - } - /*create file*/ fp = fopen (filename, "wb"); if (!fp) { @@ -554,19 +556,19 @@ mm_exif_write_exif_jpeg_to_file (char *filename, mm_exif_info_t *info, void *jp _exif_set_uint16 (0, &head[1], 0xffe1); /*set header length*/ _exif_set_uint16 (0, &head_len, (unsigned short)(ebs + 2)); - + if(head[0]==0 || head[1]==0 || head_len==0) { mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s]setting error\n", __LINE__, __func__); fclose (fp); return -1; } - - fwrite (&head[0], 1, 2, fp); /*SOI marker*/ - fwrite (&head[1], 1, 2, fp); /*APP1 marker*/ - fwrite (&head_len, 1, 2, fp); /*length of APP1*/ - fwrite (eb, 1, ebs, fp); /*EXIF*/ - fwrite (jpeg + offset_jpeg_start, 1, jpeg_len - offset_jpeg_start, fp); /*IMAGE*/ + + fwrite (&head[0], 1, EXIF_MARKER_SOI_LENGTH, fp); /*SOI marker*/ + fwrite (&head[1], 1, EXIF_MARKER_APP1_LENGTH, fp); /*APP1 marker*/ + fwrite (&head_len, 1, EXIF_APP1_LENGTH, fp); /*length of APP1*/ + fwrite (eb, 1, ebs, fp); /*EXIF*/ + fwrite (jpeg + JPEG_DATA_OFFSET, 1, jpeg_len - JPEG_DATA_OFFSET, fp); /*IMAGE*/ fclose (fp); @@ -576,15 +578,15 @@ mm_exif_write_exif_jpeg_to_file (char *filename, mm_exif_info_t *info, void *jp int mm_exif_write_exif_jpeg_to_memory (void **mem, unsigned int *length, mm_exif_info_t *info, void *jpeg, unsigned int jpeg_len) { + unsigned short head[2] = {0,}; + unsigned short head_len = 0; + unsigned char *eb = NULL; + unsigned int ebs; + /*output*/ - unsigned char *m = NULL; - int m_len = 0; - /**/ - unsigned long offset_jpeg_start; - unsigned short head[2]={0,}; - unsigned short head_len=0; - unsigned char *eb = NULL; - unsigned int ebs; + unsigned char *m = NULL; + int m_len = 0; + mmf_debug (MMF_DEBUG_LOG,"[%05d][%s]\n", __LINE__, __func__); if(info==NULL || jpeg==NULL) @@ -601,15 +603,10 @@ mm_exif_write_exif_jpeg_to_memory (void **mem, unsigned int *length, mm_exif_inf eb = info->data; ebs = info->size; - /*get DQT*/ - offset_jpeg_start = _exif_get_jpeg_marker_offset (jpeg, (int)jpeg_len, 0xffdb); - if (offset_jpeg_start == 0) { - return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; - } /*length of output image*/ /*SOI + APP1 + length of APP1 + length of EXIF + IMAGE*/ - m_len = 2 + 2 + 2 + ebs + (jpeg_len - offset_jpeg_start); + m_len = EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH + EXIF_APP1_LENGTH + ebs + (jpeg_len - JPEG_DATA_OFFSET); /*alloc output image*/ m = malloc (m_len); if (!m) { @@ -622,17 +619,30 @@ mm_exif_write_exif_jpeg_to_memory (void **mem, unsigned int *length, mm_exif_inf _exif_set_uint16 (0, &head[1], 0xffe1); /*set header length*/ _exif_set_uint16 (0, &head_len, (unsigned short)(ebs + 2)); - if(head[0]==0 || head[1]==0 || head_len==0) - { + if (head[0] == 0 || head[1] == 0 || head_len == 0) { mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s]setting error\n", __LINE__, __func__); free(m); return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; - } - memcpy (m, &head[0], 2); /*SOI marker*/ - memcpy (m + 2, &head[1], 2); /*APP1 marker*/ - memcpy (m + 2 + 2, &head_len, 2); /*length of APP1*/ - memcpy (m + 2 + 2 + 2, eb, ebs); /*EXIF*/ - memcpy (m + 2 + 2 + 2 + ebs, jpeg + offset_jpeg_start, jpeg_len - offset_jpeg_start); /*IMAGE*/ + } + + /* Complete JPEG+EXIF */ + /*SOI marker*/ + memcpy(m, &head[0], EXIF_MARKER_SOI_LENGTH); + /*APP1 marker*/ + memcpy(m + EXIF_MARKER_SOI_LENGTH, + &head[1], EXIF_MARKER_APP1_LENGTH); + /*length of APP1*/ + memcpy(m + EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH, + &head_len, EXIF_APP1_LENGTH); + /*EXIF*/ + memcpy(m + EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH + EXIF_APP1_LENGTH, + eb, ebs); + /*IMAGE*/ + memcpy(m + EXIF_MARKER_SOI_LENGTH + EXIF_MARKER_APP1_LENGTH + EXIF_APP1_LENGTH + ebs, + jpeg + JPEG_DATA_OFFSET, jpeg_len - JPEG_DATA_OFFSET); + + mmf_debug(MMF_DEBUG_LOG,"[%05d][%s] JPEG+EXIF Copy DONE(original:%d, copied:%d)\n", + __LINE__, __func__, jpeg_len, jpeg_len - JPEG_DATA_OFFSET); /*set ouput param*/ *mem = m; diff --git a/src/mm_camcorder_gstcommon.c b/src/mm_camcorder_gstcommon.c index b631caf..7998bc2 100644 --- a/src/mm_camcorder_gstcommon.c +++ b/src/mm_camcorder_gstcommon.c @@ -40,7 +40,7 @@ gboolean audiocodec_fileformat_compatibility_table[MM_AUDIO_CODEC_NUM][MM_FILE_F /*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, 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, }, @@ -121,7 +121,6 @@ gboolean videocodec_fileformat_compatibility_table[MM_VIDEO_CODEC_NUM][MM_FILE_F -----------------------------------------------------------------------*/ #define USE_AUDIO_CLOCK_TUNE #define _MMCAMCORDER_WAIT_EOS_TIME 5.0 //sec -#define _DPRAM_RAW_PCM_LOCATION "/dev/rawPCM0" /*----------------------------------------------------------------------- | LOCAL FUNCTION PROTOTYPES: | @@ -140,8 +139,6 @@ gboolean videocodec_fileformat_compatibility_table[MM_VIDEO_CODEC_NUM][MM_FILE_F * @see __mmcamcorder_create_preview_pipeline() */ static gboolean __mmcamcorder_video_dataprobe_preview(GstPad *pad, GstBuffer *buffer, gpointer u_data); -static gboolean __mmcamcorder_video_dataprobe_vsink(GstPad *pad, GstBuffer *buffer, gpointer u_data); -static gboolean __mmcamcorder_video_dataprobe_vsink_drop_by_time(GstPad *pad, GstBuffer *buffer, gpointer u_data); static int __mmcamcorder_get_amrnb_bitrate_mode(int bitrate); @@ -155,14 +152,16 @@ int _mmcamcorder_create_videosrc_bin(MMHandleType handle) { int err = MM_ERROR_NONE; int rotate = 0; + int flip = 0; int fps = 0; - int slow_fps = 0; int hold_af = 0; int UseVideoscale = 0; - int PictureFormat = 0; int codectype = 0; int capture_width = 0; int capture_height = 0; + int capture_jpg_quality = 100; + int video_stabilization = 0; + int anti_shake = 0; char *videosrc_name = NULL; char *err_name = NULL; @@ -203,13 +202,16 @@ int _mmcamcorder_create_videosrc_bin(MMHandleType handle) } err = mm_camcorder_get_attributes(handle, &err_name, - MMCAM_CAMERA_FORMAT, &PictureFormat, + MMCAM_CAMERA_FORMAT, &sc->info_image->preview_format, MMCAM_CAMERA_FPS, &fps, - "camera-slow-motion-fps", &slow_fps, MMCAM_CAMERA_ROTATION, &rotate, + MMCAM_CAMERA_FLIP, &flip, + MMCAM_CAMERA_VIDEO_STABILIZATION, &video_stabilization, + MMCAM_CAMERA_ANTI_HANDSHAKE, &anti_shake, MMCAM_CAPTURE_WIDTH, &capture_width, MMCAM_CAPTURE_HEIGHT, &capture_height, MMCAM_IMAGE_ENCODER, &codectype, + MMCAM_IMAGE_ENCODER_QUALITY, &capture_jpg_quality, "camera-hold-af-after-capturing", &hold_af, NULL); if (err != MM_ERROR_NONE) { @@ -219,7 +221,7 @@ int _mmcamcorder_create_videosrc_bin(MMHandleType handle) } /* Get fourcc from picture format */ - sc->fourcc = _mmcamcorder_get_fourcc(PictureFormat, codectype, hcamcorder->use_zero_copy_format); + sc->fourcc = _mmcamcorder_get_fourcc(sc->info_image->preview_format, codectype, hcamcorder->use_zero_copy_format); /* Get videosrc element and its name from configure */ _mmcamcorder_conf_get_element(hcamcorder->conf_main, @@ -240,69 +242,86 @@ int _mmcamcorder_create_videosrc_bin(MMHandleType handle) __ta__(" videosrc_capsfilter", _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSRC_FILT, "capsfilter", "videosrc_filter", element_list, err); ); + __ta__(" videosrc_queue", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSRC_QUE, "queue", "videosrc_queue", element_list, err); + ); - sc->is_slow = FALSE; + /* init high-speed-fps */ MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "high-speed-fps", 0); + + /* set capture size, quality and flip setting which were set before mm_camcorder_realize */ MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-width", capture_width); MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-height", capture_height); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-jpg-quality", capture_jpg_quality); - if (hcamcorder->type == MM_CAMCORDER_MODE_VIDEO) { - _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, - CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, - "UseVideoscale", - &UseVideoscale); - if (UseVideoscale) { - int set_width = 0; - int set_height = 0; - int scale_width = 0; - int scale_height = 0; - int scale_method = 0; - char *videoscale_name = NULL; - type_element *VideoscaleElement = NULL; - - _mmcamcorder_conf_get_element(hcamcorder->conf_main, - CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, - "VideoscaleElement", - &VideoscaleElement); - _mmcamcorder_conf_get_value_element_name(VideoscaleElement, &videoscale_name); - __ta__(" videosrc_scale", - _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSRC_SCALE, videoscale_name, "videosrc_scale", element_list, err); - ); - __ta__(" videoscale_capsfilter", - _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSRC_VSFLT, "capsfilter", "videosrc_scalefilter", element_list, err); - ); + /* set camera flip */ + _mmcamcorder_set_videosrc_flip(handle, flip); - _mmcamcorder_conf_get_value_element_int(VideoscaleElement, "width", &scale_width); - _mmcamcorder_conf_get_value_element_int(VideoscaleElement, "height", &scale_height); - _mmcamcorder_conf_get_value_element_int(VideoscaleElement, "method", &scale_method); + /* set flush cache as FALSE */ + if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ITLV_JPEG_UYVY) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "flush-cache", FALSE); + } - if (rotate == MM_VIDEO_INPUT_ROTATION_90 || - rotate == MM_VIDEO_INPUT_ROTATION_270) { - set_width = scale_height; - set_height = scale_width; - } else { - set_width = scale_width; - set_height = scale_height; - } + /* set video stabilization mode */ + _mmcamcorder_set_videosrc_stabilization(handle, video_stabilization); - _mmcam_dbg_log("VideoSRC Scale[%dx%d], Method[%d]", set_width, set_height, scale_method); + /* set anti handshake mode */ + _mmcamcorder_set_videosrc_anti_shake(handle, anti_shake); - caps = gst_caps_new_simple("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, sc->fourcc, - "width", G_TYPE_INT, set_width, - "height", G_TYPE_INT, set_height, - NULL); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_VSFLT].gst, "caps", caps); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SCALE].gst, "method", scale_method); + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, + "UseVideoscale", + &UseVideoscale); + if (UseVideoscale) { + int set_width = 0; + int set_height = 0; + int scale_width = 0; + int scale_height = 0; + int scale_method = 0; + char *videoscale_name = NULL; + type_element *VideoscaleElement = NULL; - gst_caps_unref(caps); - caps = NULL; - } + _mmcamcorder_conf_get_element(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, + "VideoscaleElement", + &VideoscaleElement); + _mmcamcorder_conf_get_value_element_name(VideoscaleElement, &videoscale_name); + __ta__(" videosrc_scale", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSRC_SCALE, videoscale_name, "videosrc_scale", element_list, err); + ); + __ta__(" videoscale_capsfilter", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSRC_VSFLT, "capsfilter", "videosrc_scalefilter", element_list, err); + ); - if (slow_fps > 0) { - sc->is_slow = TRUE; - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "high-speed-fps", fps); + _mmcamcorder_conf_get_value_element_int(VideoscaleElement, "width", &scale_width); + _mmcamcorder_conf_get_value_element_int(VideoscaleElement, "height", &scale_height); + _mmcamcorder_conf_get_value_element_int(VideoscaleElement, "method", &scale_method); + + if (rotate == MM_VIDEO_INPUT_ROTATION_90 || + rotate == MM_VIDEO_INPUT_ROTATION_270) { + set_width = scale_height; + set_height = scale_width; + } else { + set_width = scale_width; + set_height = scale_height; } + + _mmcam_dbg_log("VideoSRC Scale[%dx%d], Method[%d]", set_width, set_height, scale_method); + + caps = gst_caps_new_simple("video/x-raw-yuv", + "format", GST_TYPE_FOURCC, sc->fourcc, + "width", G_TYPE_INT, set_width, + "height", G_TYPE_INT, set_height, + NULL); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_VSFLT].gst, "caps", caps); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SCALE].gst, "method", scale_method); + + gst_caps_unref(caps); + caps = NULL; + } + + if (sc->is_modified_rate) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "high-speed-fps", fps); } __ta__(" tee", @@ -603,7 +622,7 @@ int _mmcamcorder_create_videosink_bin(MMHandleType handle) int camera_width = 0; int camera_height = 0; int rotate = 0; - int camera_format = MM_PIXEL_FORMAT_NV12; + int flip = 0; int UseVideoscale = 0, EnableConvertedSC = 0; int scale_method = 0; char* videosink_name = NULL; @@ -631,10 +650,10 @@ int _mmcamcorder_create_videosink_bin(MMHandleType handle) err = mm_camcorder_get_attributes(handle, &err_name, MMCAM_CAMERA_WIDTH, &camera_width, MMCAM_CAMERA_HEIGHT, &camera_height, - MMCAM_CAMERA_FORMAT, &camera_format, MMCAM_DISPLAY_RECT_WIDTH, &rect_width, MMCAM_DISPLAY_RECT_HEIGHT, &rect_height, MMCAM_DISPLAY_ROTATION, &rotate, + MMCAM_DISPLAY_FLIP, &flip, "enable-converted-stream-callback", &EnableConvertedSC, NULL); if (err != MM_ERROR_NONE) { @@ -668,15 +687,26 @@ int _mmcamcorder_create_videosink_bin(MMHandleType handle) if (EnableConvertedSC || !strcmp(videosink_name, "evasimagesink") || !strcmp(videosink_name, "ximagesink")) { - if (camera_format == MM_PIXEL_FORMAT_NV12 || - camera_format == MM_PIXEL_FORMAT_NV12T) { + GstElementFactory *factory = gst_element_factory_find("fimcconvert"); + + if ((sc->fourcc == GST_MAKE_FOURCC('S','N','2','1') || + sc->fourcc == GST_MAKE_FOURCC('S','N','1','2') || + sc->fourcc == GST_MAKE_FOURCC('S','T','1','2') || + sc->fourcc == GST_MAKE_FOURCC('S','4','2','0')) && + factory) { int set_rotate = 0; + int set_flip = 0; + + gst_object_unref(factory); + factory = NULL; __ta__(" videosink_fimcconvert", _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSINK_CLS, "fimcconvert", NULL, element_list, err); ); - if (rotate < MM_DISPLAY_ROTATION_FLIP_HORZ) { + /* set rotate */ + if (rotate > MM_VIDEO_INPUT_ROTATION_NONE && + rotate < MM_VIDEO_INPUT_ROTATION_NUM) { set_rotate = rotate * 90; } else { set_rotate = 0; @@ -695,11 +725,35 @@ int _mmcamcorder_create_videosink_bin(MMHandleType handle) } } - _mmcam_dbg_log("Fimcconvert set values - %dx%d, rotate: %d", rect_width, rect_height, set_rotate); + /* set flip */ + switch (flip) { + case MM_FLIP_HORIZONTAL: + set_flip = FIMCCONVERT_FLIP_HORIZONTAL; + break; + case MM_FLIP_VERTICAL: + set_flip = FIMCCONVERT_FLIP_VERTICAL; + break; + case MM_FLIP_BOTH: /* both flip has same effect with 180 rotation */ + set_rotate = (set_rotate + 180) % 360; + case MM_FLIP_NONE: + default: + set_flip = FIMCCONVERT_FLIP_NONE; + break; + } + + _mmcam_dbg_log("Fimcconvert set values - %dx%d, rotate: %d, flip: %d", + rect_width, rect_height, set_rotate, set_flip); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_CLS].gst, "src-width", rect_width); MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_CLS].gst, "src-height", rect_height); MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_CLS].gst, "rotate", set_rotate); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_CLS].gst, "flip", set_flip); } else { + if (factory) { + gst_object_unref(factory); + factory = NULL; + } + __ta__(" videosink_ffmpegcolorspace", _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSINK_CLS, "ffmpegcolorspace", NULL, element_list, err); ); @@ -752,9 +806,8 @@ int _mmcamcorder_create_videosink_bin(MMHandleType handle) _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSINK_SINK, videosink_name, NULL, element_list, err); ); - if (!strcmp(videosink_name, "xvimagesink") || - !strcmp(videosink_name, "ximagesink") || - !strcmp(videosink_name, "evasimagesink")) { + if (!strcmp(videosink_name, "xvimagesink") || !strcmp(videosink_name, "ximagesink") || + !strcmp(videosink_name, "evasimagesink") || !strcmp(videosink_name, "evaspixmapsink")) { if (_mmcamcorder_videosink_window_set(handle, sc->VideosinkElement) != MM_ERROR_NONE) { _mmcam_dbg_err("_mmcamcorder_videosink_window_set error"); err = MM_ERROR_CAMCORDER_INVALID_ARGUMENT; @@ -816,12 +869,11 @@ pipeline_creation_error: } -int _mmcamcorder_create_encodesink_bin(MMHandleType handle) +int _mmcamcorder_create_encodesink_bin(MMHandleType handle, MMCamcorderEncodebinProfile profile) { int err = MM_ERROR_NONE; int result = 0; int channel = 0; - int profile = 0; int audio_enc = 0; int v_bitrate = 0; int a_bitrate = 0; @@ -879,33 +931,27 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle) ); /* check element availability */ - err = mm_camcorder_get_attributes(handle, &err_name, - MMCAM_MODE, &profile, - MMCAM_AUDIO_ENCODER, &audio_enc, - MMCAM_AUDIO_CHANNEL, &channel, - MMCAM_VIDEO_ENCODER_BITRATE, &v_bitrate, - MMCAM_AUDIO_ENCODER_BITRATE, &a_bitrate, - NULL); - if (err != MM_ERROR_NONE) { - _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err); - SAFE_FREE (err_name); - return err; - } + mm_camcorder_get_attributes(handle, &err_name, + MMCAM_AUDIO_ENCODER, &audio_enc, + MMCAM_AUDIO_CHANNEL, &channel, + MMCAM_VIDEO_ENCODER_BITRATE, &v_bitrate, + MMCAM_AUDIO_ENCODER_BITRATE, &a_bitrate, + NULL); _mmcam_dbg_log("Profile[%d]", profile); /* Set information */ - if (profile == MM_CAMCORDER_MODE_VIDEO) { + if (profile == MM_CAMCORDER_ENCBIN_PROFILE_VIDEO) { str_profile = "VideoProfile"; str_aac = "VideoAutoAudioConvert"; str_aar = "VideoAutoAudioResample"; str_acs = "VideoAutoColorSpace"; - } else if (profile == MM_CAMCORDER_MODE_AUDIO) { + } else if (profile == MM_CAMCORDER_ENCBIN_PROFILE_AUDIO) { str_profile = "AudioProfile"; str_aac = "AudioAutoAudioConvert"; str_aar = "AudioAutoAudioResample"; str_acs = "AudioAutoColorSpace"; - } else if (profile == MM_CAMCORDER_MODE_IMAGE) { + } else if (profile == MM_CAMCORDER_ENCBIN_PROFILE_IMAGE) { str_profile = "ImageProfile"; str_aac = "ImageAutoAudioConvert"; str_aar = "ImageAutoAudioResample"; @@ -927,7 +973,7 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle) MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "use-video-toggle", FALSE); /* Codec */ - if (profile == MM_CAMCORDER_MODE_VIDEO) { + if (profile == MM_CAMCORDER_ENCBIN_PROFILE_VIDEO) { int use_venc_queue = 0; VideoencElement = _mmcamcorder_get_type_element(handle, MM_CAM_VIDEO_ENCODER); @@ -950,59 +996,54 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle) if (use_venc_queue) { _MMCAMCORDER_ENCODEBIN_ELMGET(sc, _MMCAMCORDER_ENCSINK_VENC_QUE, "use-venc-queue", err); } - - if (!strcmp(gst_element_venc_name, "ari_h263enc")) { - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "auto-colorspace", TRUE); - } } - if (sc->is_slow == FALSE) { - if (profile == MM_CAMCORDER_MODE_AUDIO || profile == MM_CAMCORDER_MODE_VIDEO) { - int use_aenc_queue =0; + if (sc->audio_disable == FALSE && + profile != MM_CAMCORDER_ENCBIN_PROFILE_IMAGE) { + int use_aenc_queue =0; - AudioencElement = _mmcamcorder_get_type_element(handle, MM_CAM_AUDIO_ENCODER); - if (!AudioencElement) { - _mmcam_dbg_err("Fail to get type element"); - err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; - goto pipeline_creation_error; - } + AudioencElement = _mmcamcorder_get_type_element(handle, MM_CAM_AUDIO_ENCODER); + if (!AudioencElement) { + _mmcam_dbg_err("Fail to get type element"); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } - _mmcamcorder_conf_get_value_element_name(AudioencElement, &gst_element_aenc_name); + _mmcamcorder_conf_get_value_element_name(AudioencElement, &gst_element_aenc_name); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "aenc-name", gst_element_aenc_name); - _MMCAMCORDER_ENCODEBIN_ELMGET(sc, _MMCAMCORDER_ENCSINK_AENC, "audio-encode", err); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "aenc-name", gst_element_aenc_name); + _MMCAMCORDER_ENCODEBIN_ELMGET(sc, _MMCAMCORDER_ENCSINK_AENC, "audio-encode", err); - if (audio_enc == MM_AUDIO_CODEC_AMR && channel == 2) { - caps = gst_caps_new_simple("audio/x-raw-int", - "channels", G_TYPE_INT, 1, - NULL); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "auto-audio-convert", TRUE); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "acaps", caps); - gst_caps_unref (caps); - caps = NULL; - } + if (audio_enc == MM_AUDIO_CODEC_AMR && channel == 2) { + caps = gst_caps_new_simple("audio/x-raw-int", + "channels", G_TYPE_INT, 1, + NULL); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "auto-audio-convert", TRUE); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_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); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "auto-audio-convert", TRUE); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "acaps", caps); - gst_caps_unref (caps); - caps = NULL; - _mmcam_dbg_log("***** MM_AUDIO_CODEC_OGG : setting audio/x-raw-int "); - } + if (audio_enc == MM_AUDIO_CODEC_OGG) { + caps = gst_caps_new_simple("audio/x-raw-int", + NULL); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "auto-audio-convert", TRUE); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "acaps", caps); + gst_caps_unref (caps); + caps = NULL; + _mmcam_dbg_log("***** MM_AUDIO_CODEC_OGG : setting audio/x-raw-int "); + } - _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, - CONFIGURE_CATEGORY_MAIN_RECORD, - "UseAudioEncoderQueue", - &use_aenc_queue); - if (use_aenc_queue) { - _MMCAMCORDER_ENCODEBIN_ELMGET(sc, _MMCAMCORDER_ENCSINK_AENC_QUE, "use-aenc-queue", err); - } + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_RECORD, + "UseAudioEncoderQueue", + &use_aenc_queue); + if (use_aenc_queue) { + _MMCAMCORDER_ENCODEBIN_ELMGET(sc, _MMCAMCORDER_ENCSINK_AENC_QUE, "use-aenc-queue", err); } } - if (profile == MM_CAMCORDER_MODE_IMAGE) { + if (profile == MM_CAMCORDER_ENCBIN_PROFILE_IMAGE) { ImageencElement = _mmcamcorder_get_type_element(handle, MM_CAM_IMAGE_ENCODER); if (!ImageencElement) { _mmcam_dbg_err("Fail to get type element"); @@ -1017,7 +1058,7 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle) } /* Mux */ - if (profile == MM_CAMCORDER_MODE_AUDIO || profile == MM_CAMCORDER_MODE_VIDEO) { + if (profile != MM_CAMCORDER_ENCBIN_PROFILE_IMAGE) { MuxElement = _mmcamcorder_get_type_element(handle, MM_CAM_FILE_FORMAT); if (!MuxElement) { _mmcam_dbg_err("Fail to get type element"); @@ -1036,7 +1077,8 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle) } /* Sink */ - if (profile == MM_CAMCORDER_MODE_AUDIO || profile == MM_CAMCORDER_MODE_VIDEO) { + if (profile != MM_CAMCORDER_ENCBIN_PROFILE_IMAGE) { + /* for recording */ _mmcamcorder_conf_get_element(hcamcorder->conf_main, CONFIGURE_CATEGORY_MAIN_RECORD, "RecordsinkElement", @@ -1055,7 +1097,7 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle) ); } - if (profile == MM_CAMCORDER_MODE_VIDEO) { + if (profile == MM_CAMCORDER_ENCBIN_PROFILE_VIDEO) { /* video encoder attribute setting */ if (v_bitrate > 0) { MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "bitrate", v_bitrate); @@ -1066,35 +1108,29 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle) _mmcamcorder_conf_set_value_element_property(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, VideoencElement); } - if (sc->is_slow == FALSE) { - if (profile == MM_CAMCORDER_MODE_AUDIO || profile == MM_CAMCORDER_MODE_VIDEO) { - /* audio encoder attribute setting */ - if (a_bitrate > 0) { - switch (audio_enc) { - case MM_AUDIO_CODEC_AMR: - result = __mmcamcorder_get_amrnb_bitrate_mode(a_bitrate); - - _mmcam_dbg_log("Set AMR encoder[%s] mode [%d]", gst_element_aenc_name, result); - - if(!strcmp(gst_element_aenc_name, "ari_amrnbenc")) { - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "mode", result); - } else { - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "band-mode", result); - } - break; - case MM_AUDIO_CODEC_AAC: - _mmcam_dbg_log("Set AAC encoder[%s] bitrate [%d]", gst_element_aenc_name, a_bitrate); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "bitrate", a_bitrate); - break; - default: - _mmcam_dbg_log("Audio codec is not AMR or AAC... you need to implement setting function for audio encoder bit-rate"); - break; - } - } else { - _mmcam_dbg_warn("Setting bitrate is too small, so skip setting. Use DEFAULT value."); + if (sc->audio_disable == FALSE && + profile != MM_CAMCORDER_ENCBIN_PROFILE_IMAGE) { + /* audio encoder attribute setting */ + if (a_bitrate > 0) { + switch (audio_enc) { + case MM_AUDIO_CODEC_AMR: + result = __mmcamcorder_get_amrnb_bitrate_mode(a_bitrate); + _mmcam_dbg_log("Set AMR encoder[%s] mode [%d]", gst_element_aenc_name, result); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "band-mode", result); + break; + case MM_AUDIO_CODEC_AAC: + _mmcam_dbg_log("Set AAC encoder[%s] bitrate [%d]", gst_element_aenc_name, a_bitrate); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "bitrate", a_bitrate); + break; + default: + _mmcam_dbg_log("Audio codec is not AMR or AAC... you need to implement setting function for audio encoder bit-rate"); + break; } - _mmcamcorder_conf_set_value_element_property( sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, AudioencElement ); + } else { + _mmcam_dbg_warn("Setting bitrate is too small, so skip setting. Use DEFAULT value."); } + + _mmcamcorder_conf_set_value_element_property(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, AudioencElement); } _mmcam_dbg_log("Element creation complete"); @@ -1108,7 +1144,7 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle) _mmcam_dbg_log("Element add complete"); - if (profile == MM_CAMCORDER_MODE_VIDEO) { + if (profile == MM_CAMCORDER_ENCBIN_PROFILE_VIDEO) { pad = gst_element_get_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video"); if (gst_element_add_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, gst_ghost_pad_new("video_sink0", pad)) < 0) { gst_object_unref(pad); @@ -1120,7 +1156,7 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle) gst_object_unref(pad); pad = NULL; - if (sc->is_slow == FALSE) { + if (sc->audio_disable == FALSE) { pad = gst_element_get_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio"); if (gst_element_add_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, gst_ghost_pad_new("audio_sink0", pad)) < 0) { gst_object_unref(pad); @@ -1132,7 +1168,7 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle) gst_object_unref(pad); pad = NULL; } - } else if (profile == MM_CAMCORDER_MODE_AUDIO) { + } else if (profile == MM_CAMCORDER_ENCBIN_PROFILE_AUDIO) { pad = gst_element_get_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio"); if (gst_element_add_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, gst_ghost_pad_new("audio_sink0", pad)) < 0) { gst_object_unref(pad); @@ -1396,27 +1432,20 @@ int _mmcamcorder_create_preview_pipeline(MMHandleType handle) _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error); /* Set data probe function */ - srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "src"); + srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "src"); MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_PREVIEW, __mmcamcorder_video_dataprobe_preview, hcamcorder); gst_object_unref(srcpad); srcpad = NULL; - if (hcamcorder->type == MM_CAMCORDER_MODE_IMAGE) { - sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "sink"); - MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_PREVIEW, - __mmcamcorder_video_dataprobe_vsink, hcamcorder); - } else if (hcamcorder->type == MM_CAMCORDER_MODE_VIDEO) { - sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "sink"); - MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_PREVIEW, - __mmcamcorder_video_dataprobe_vsink_drop_by_time, hcamcorder); - } - gst_object_unref(sinkpad); - sinkpad = NULL; + bus = gst_pipeline_get_bus(GST_PIPELINE(sc->element[_MMCAMCORDER_MAIN_PIPE].gst)); /* Register message callback */ - bus = gst_pipeline_get_bus(GST_PIPELINE(sc->element[_MMCAMCORDER_MAIN_PIPE].gst)); - hcamcorder->pipeline_cb_event_id = gst_bus_add_watch(bus, _mmcamcorder_pipeline_cb_message, hcamcorder); + hcamcorder->pipeline_cb_event_id = gst_bus_add_watch(bus, _mmcamcorder_pipeline_cb_message, (gpointer)hcamcorder); + + /* set sync handler */ + gst_bus_set_sync_handler(bus, _mmcamcorder_pipeline_bus_sync_callback, (gpointer)hcamcorder); + gst_object_unref(bus); bus = NULL; @@ -1455,9 +1484,9 @@ void _mmcamcorder_negosig_handler(GstElement *videosrc, MMHandleType handle) sc->cam_stability_count = _MMCAMCORDER_CAMSTABLE_COUNT; } - if (hcamcorder->type == MM_CAMCORDER_MODE_IMAGE) { + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { _MMCamcorderImageInfo *info = NULL; - info = sc->info; + info = sc->info_image; if (info->resolution_change == TRUE) { _mmcam_dbg_log("open toggle of stillshot sink."); MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); @@ -1478,12 +1507,13 @@ int _mmcamcorder_videosink_window_set(MMHandleType handle, type_element* Videosi int visible = 0; int rotation = MM_DISPLAY_ROTATION_NONE; int rotation_degree = 0; - int display_device = MM_DISPLAY_DEVICE_MAINLCD; - int display_mode = 0; + int flip = MM_FLIP_NONE; + int display_mode = MM_DISPLAY_MODE_DEFAULT; int display_geometry_method = MM_DISPLAY_METHOD_LETTER_BOX; int origin_size = 0; int zoom_attr = 0; int zoom_level = 0; + int do_scaling = FALSE; int *overlay = NULL; gulong xid; char *err_name = NULL; @@ -1513,41 +1543,42 @@ int _mmcamcorder_videosink_window_set(MMHandleType handle, type_element* Videosi MMCAM_DISPLAY_RECT_WIDTH, &retwidth, MMCAM_DISPLAY_RECT_HEIGHT, &retheight, MMCAM_DISPLAY_ROTATION, &rotation, + MMCAM_DISPLAY_FLIP, &flip, MMCAM_DISPLAY_VISIBLE, &visible, MMCAM_DISPLAY_HANDLE, (void**)&overlay, &size, - MMCAM_DISPLAY_DEVICE, &display_device, + MMCAM_DISPLAY_MODE, &display_mode, MMCAM_DISPLAY_GEOMETRY_METHOD, &display_geometry_method, MMCAM_DISPLAY_SCALE, &zoom_attr, + MMCAM_DISPLAY_EVAS_DO_SCALING, &do_scaling, NULL); ); - if (err != MM_ERROR_NONE) { - _mmcam_dbg_warn("Get display attrs fail. (%s:%x)", err_name, err); - SAFE_FREE(err_name); - return err; - } _mmcam_dbg_log("(overlay=%p, size=%d)", overlay, size); _mmcamcorder_conf_get_value_element_name(VideosinkElement, &videosink_name); - /* Set xid */ - if (!strcmp(videosink_name, "xvimagesink") || !strcmp(videosink_name, "ximagesink")) { + /* Set display handle */ + if (!strcmp(videosink_name, "xvimagesink") || + !strcmp(videosink_name, "ximagesink")) { if (overlay) { xid = *overlay; _mmcam_dbg_log("xid = %lu )", xid); gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(vsink), xid); } else { - _mmcam_dbg_warn( "Set xid as 0.. but, it's not recommended." ); + _mmcam_dbg_warn("Handle is NULL. Set xid as 0.. but, it's not recommended."); gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(vsink), 0); } _mmcam_dbg_log("%s set: display_geometry_method[%d],origin-size[%d],visible[%d],rotate[enum:%d]", videosink_name, display_geometry_method, origin_size, visible, rotation); - } else if (!strcmp(videosink_name, "evasimagesink")) { + } else if (!strcmp(videosink_name, "evasimagesink") || + !strcmp(videosink_name, "evaspixmapsink")) { + _mmcam_dbg_log("videosink : %s, handle : %p", videosink_name, overlay); if (overlay) { - MMCAMCORDER_G_OBJECT_SET( vsink, "evas-object", overlay ); + MMCAMCORDER_G_OBJECT_SET(vsink, "evas-object", overlay); + MMCAMCORDER_G_OBJECT_SET(vsink, "origin-size", !do_scaling); } else { - _mmcam_dbg_err("Evas Object pointer is NULL"); + _mmcam_dbg_err("display handle(eavs object) is NULL"); return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; } } else { @@ -1555,24 +1586,36 @@ int _mmcamcorder_videosink_window_set(MMHandleType handle, type_element* Videosi } /* Set attribute */ - if (!strcmp(videosink_name, "xvimagesink")) { - switch (rotation) { - case MM_DISPLAY_ROTATION_NONE : - rotation_degree = 0; - break; - case MM_DISPLAY_ROTATION_90 : - rotation_degree = 1; - break; - case MM_DISPLAY_ROTATION_180 : - rotation_degree = 2; - break; - case MM_DISPLAY_ROTATION_270 : - rotation_degree = 3; - break; - default: - _mmcam_dbg_warn("Unsupported rotation value. set as default(0)."); - rotation_degree = 0; - break; + if (!strcmp(videosink_name, "xvimagesink") || + !strcmp(videosink_name, "evaspixmapsink")) { + + if (!strcmp(videosink_name, "xvimagesink")) { + /* set rotation */ + switch (rotation) { + case MM_DISPLAY_ROTATION_NONE : + rotation_degree = 0; + break; + case MM_DISPLAY_ROTATION_90 : + rotation_degree = 1; + break; + case MM_DISPLAY_ROTATION_180 : + rotation_degree = 2; + break; + case MM_DISPLAY_ROTATION_270 : + rotation_degree = 3; + break; + default: + _mmcam_dbg_warn("Unsupported rotation value. set as default(0)."); + rotation_degree = 0; + break; + } + MMCAMCORDER_G_OBJECT_SET(vsink, "rotate", rotation_degree); + + /* set flip */ + MMCAMCORDER_G_OBJECT_SET(vsink, "flip", flip); + + _mmcam_dbg_log("set videosink[%s] rotate %d, flip %d", + videosink_name, rotation_degree, flip); } switch (zoom_attr) { @@ -1591,25 +1634,9 @@ int _mmcamcorder_videosink_window_set(MMHandleType handle, type_element* Videosi break; } - switch (display_device) { - case MM_DISPLAY_DEVICE_TVOUT: - display_mode = 2; - break; - case MM_DISPLAY_DEVICE_MAINLCD_AND_TVOUT: - display_mode = 1; - break; - case MM_DISPLAY_DEVICE_MAINLCD: - case MM_DISPLAY_DEVICE_SUBLCD: - case MM_DISPLAY_DEVICE_MAINLCD_AND_SUBLCD: - default: - display_mode = 3; - break; - } - MMCAMCORDER_G_OBJECT_SET(vsink, "display-geometry-method", display_geometry_method); MMCAMCORDER_G_OBJECT_SET(vsink, "display-mode", display_mode); MMCAMCORDER_G_OBJECT_SET(vsink, "visible", visible); - MMCAMCORDER_G_OBJECT_SET(vsink, "rotate", rotation_degree); MMCAMCORDER_G_OBJECT_SET(vsink, "zoom", zoom_level); if (display_geometry_method == MM_DISPLAY_METHOD_CUSTOM_ROI) { @@ -1704,6 +1731,8 @@ static gboolean __mmcamcorder_video_dataprobe_preview(GstPad *pad, GstBuffer *bu _MMCamcorderSubContext *sc = NULL; _MMCamcorderKPIMeasure *kpi = NULL; + mmf_return_val_if_fail(buffer, FALSE); + mmf_return_val_if_fail(GST_BUFFER_DATA(buffer), FALSE); mmf_return_val_if_fail(hcamcorder, TRUE); sc = MMF_CAMCORDER_SUBCONTEXT(u_data); @@ -1760,21 +1789,7 @@ static gboolean __mmcamcorder_video_dataprobe_preview(GstPad *pad, GstBuffer *bu } } - return TRUE; -} - - -static gboolean __mmcamcorder_video_dataprobe_vsink(GstPad *pad, GstBuffer *buffer, gpointer u_data) -{ - mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); - - mmf_return_val_if_fail(hcamcorder, FALSE); - - if (buffer == NULL || GST_BUFFER_DATA(buffer) == NULL) { - _mmcam_dbg_err("Null buffer!!"); - return FALSE; - } - + /* video stream callback */ if (hcamcorder->vstream_cb && buffer) { GstCaps *caps = NULL; GstStructure *structure = NULL; @@ -1794,6 +1809,9 @@ static gboolean __mmcamcorder_video_dataprobe_vsink(GstPad *pad, GstBuffer *buff return TRUE; } + /* clear stream data structure */ + memset(&stream, 0x0, sizeof(MMCamcorderVideoStreamDataType)); + structure = gst_caps_get_structure( caps, 0 ); gst_structure_get_int(structure, "width", &(stream.width)); gst_structure_get_int(structure, "height", &(stream.height)); @@ -1812,10 +1830,95 @@ static gboolean __mmcamcorder_video_dataprobe_vsink(GstPad *pad, GstBuffer *buff return TRUE; } - stream.data = (void *)GST_BUFFER_DATA(buffer); - stream.length = GST_BUFFER_SIZE(buffer); + /* set size and timestamp */ + stream.length_total = GST_BUFFER_SIZE(buffer); stream.timestamp = (unsigned int)(GST_BUFFER_TIMESTAMP(buffer)/1000000); /* nano sec -> mili sec */ + /* set data pointers */ + if (stream.format == MM_PIXEL_FORMAT_NV12 || stream.format == MM_PIXEL_FORMAT_I420) { + if (hcamcorder->use_zero_copy_format && GST_BUFFER_MALLOCDATA(buffer)) { + SCMN_IMGB *scmn_imgb = (SCMN_IMGB *)GST_BUFFER_MALLOCDATA(buffer); + + if (stream.format == MM_PIXEL_FORMAT_NV12) { + stream.data_type = MM_CAM_STREAM_DATA_YUV420SP; + stream.num_planes = 2; + stream.data.yuv420sp.y = scmn_imgb->a[0]; + stream.data.yuv420sp.length_y = stream.width * stream.height; + stream.data.yuv420sp.uv = scmn_imgb->a[1]; + stream.data.yuv420sp.length_uv = stream.data.yuv420sp.length_y >> 1; + + _mmcam_dbg_log("SN12[num_planes:%d] [Y]p:0x%x,size:%d [UV]p:0x%x,size:%d", + stream.num_planes, + stream.data.yuv420sp.y, stream.data.yuv420sp.length_y, + stream.data.yuv420sp.uv, stream.data.yuv420sp.length_uv); + } else { + stream.data_type = MM_CAM_STREAM_DATA_YUV420P; + stream.num_planes = 3; + stream.data.yuv420p.y = scmn_imgb->a[0]; + stream.data.yuv420p.length_y = stream.width * stream.height; + stream.data.yuv420p.u = scmn_imgb->a[1]; + stream.data.yuv420p.length_u = stream.data.yuv420p.length_y >> 2; + stream.data.yuv420p.v = scmn_imgb->a[2]; + stream.data.yuv420p.length_v = stream.data.yuv420p.length_u; + + _mmcam_dbg_log("S420[num_planes:%d] [Y]p:0x%x,size:%d [U]p:0x%x,size:%d [V]p:0x%x,size:%d", + stream.num_planes, + stream.data.yuv420p.y, stream.data.yuv420p.length_y, + stream.data.yuv420p.u, stream.data.yuv420p.length_u, + stream.data.yuv420p.v, stream.data.yuv420p.length_v); + } + } else { + if (stream.format == MM_PIXEL_FORMAT_NV12) { + stream.data_type = MM_CAM_STREAM_DATA_YUV420SP; + stream.num_planes = 2; + stream.data.yuv420sp.y = GST_BUFFER_DATA(buffer); + stream.data.yuv420sp.length_y = stream.width * stream.height; + stream.data.yuv420sp.uv = stream.data.yuv420sp.y + stream.data.yuv420sp.length_y; + stream.data.yuv420sp.length_uv = stream.data.yuv420sp.length_y >> 1; + + _mmcam_dbg_log("NV12[num_planes:%d] [Y]p:0x%x,size:%d [UV]p:0x%x,size:%d", + stream.num_planes, + stream.data.yuv420sp.y, stream.data.yuv420sp.length_y, + stream.data.yuv420sp.uv, stream.data.yuv420sp.length_uv); + } else { + stream.data_type = MM_CAM_STREAM_DATA_YUV420P; + stream.num_planes = 3; + stream.data.yuv420p.y = GST_BUFFER_DATA(buffer); + stream.data.yuv420p.length_y = stream.width * stream.height; + stream.data.yuv420p.u = stream.data.yuv420p.y + stream.data.yuv420p.length_y; + stream.data.yuv420p.length_u = stream.data.yuv420p.length_y >> 2; + stream.data.yuv420p.v = stream.data.yuv420p.u + stream.data.yuv420p.length_u; + stream.data.yuv420p.length_v = stream.data.yuv420p.length_u; + + _mmcam_dbg_log("I420[num_planes:%d] [Y]p:0x%x,size:%d [U]p:0x%x,size:%d [V]p:0x%x,size:%d", + stream.num_planes, + stream.data.yuv420p.y, stream.data.yuv420p.length_y, + stream.data.yuv420p.u, stream.data.yuv420p.length_u, + stream.data.yuv420p.v, stream.data.yuv420p.length_v); + } + } + } else { + if (stream.format == MM_PIXEL_FORMAT_YUYV || + stream.format == MM_PIXEL_FORMAT_UYVY || + stream.format == MM_PIXEL_FORMAT_422P || + stream.format == MM_PIXEL_FORMAT_ITLV_JPEG_UYVY) { + stream.data_type = MM_CAM_STREAM_DATA_YUV422; + stream.data.yuv422.yuv = GST_BUFFER_DATA(buffer); + stream.data.yuv422.length_yuv = stream.length_total; + } else { + stream.data_type = MM_CAM_STREAM_DATA_YUV420; + stream.data.yuv420.yuv = GST_BUFFER_DATA(buffer); + stream.data.yuv420.length_yuv = stream.length_total; + } + + stream.num_planes = 1; + + _mmcam_dbg_log("%c%c%c%c[num_planes:%d] [0]p:0x%x,size:%d", + fourcc, fourcc>>8, fourcc>>16, fourcc>>24, + stream.num_planes, stream.data.yuv420.yuv, stream.data.yuv420.length_yuv); + } + + /* call application callback */ _MMCAMCORDER_LOCK_VSTREAM_CALLBACK(hcamcorder); if (hcamcorder->vstream_cb) { hcamcorder->vstream_cb(&stream, hcamcorder->vstream_cb_param); @@ -1823,49 +1926,12 @@ static gboolean __mmcamcorder_video_dataprobe_vsink(GstPad *pad, GstBuffer *buff _MMCAMCORDER_UNLOCK_VSTREAM_CALLBACK(hcamcorder); } - return TRUE; -} - - -static gboolean __mmcamcorder_video_dataprobe_vsink_drop_by_time(GstPad *pad, GstBuffer *buffer, gpointer u_data) -{ - static GstClockTime next_time = 0; - static GstClockTime current_time = 0; - GstClockTime interval = 30 * GST_MSECOND; //30ms(about 33 fps) - - mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); - _MMCamcorderSubContext *sc = NULL; - - mmf_return_val_if_fail(hcamcorder, TRUE); - - sc = MMF_CAMCORDER_SUBCONTEXT(u_data); - mmf_return_val_if_fail(sc, TRUE); - -/* - _mmcam_dbg_log("VIDEO SRC time stamp : [%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer))); -*/ - - /* Call video stream callback */ - if (__mmcamcorder_video_dataprobe_vsink(pad, buffer, u_data) == FALSE) { - _mmcam_dbg_warn( "__mmcamcorder_video_dataprobe_vsink failed." ); - return FALSE; + /* Do force flush cache */ + if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ITLV_JPEG_UYVY) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "force-flush-cache", FALSE); } - if (sc->is_slow) { - if (GST_BUFFER_TIMESTAMP(buffer) < current_time) { - next_time = 0; - } - current_time = GST_BUFFER_TIMESTAMP(buffer); - - if (current_time >= next_time) { - next_time = current_time + interval; - return TRUE; - } else { - return FALSE; - } - } else { - return TRUE; - } + return TRUE; } @@ -2075,11 +2141,6 @@ bool _mmcamcorder_set_display_rotation(MMHandleType handle, int display_rotate) /* Get videosink name */ _mmcamcorder_conf_get_value_element_name(sc->VideosinkElement, &videosink_name); if (!strcmp(videosink_name, "xvimagesink")) { - if (display_rotate < MM_DISPLAY_ROTATION_NONE || - display_rotate > MM_DISPLAY_ROTATION_270) { - display_rotate = 0; - _mmcam_dbg_log( "Rotate: Out of range. set as default(0)..."); - } MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "rotate", display_rotate); _mmcam_dbg_log("Set display-rotate [%d] done.", display_rotate); @@ -2095,6 +2156,39 @@ bool _mmcamcorder_set_display_rotation(MMHandleType handle, int display_rotate) } +bool _mmcamcorder_set_display_flip(MMHandleType handle, int display_flip) +{ + char* videosink_name = NULL; + + mmf_camcorder_t *hcamcorder = NULL; + _MMCamcorderSubContext *sc = NULL; + + hcamcorder = MMF_CAMCORDER(handle); + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + if (sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst) { + /* Get videosink name */ + _mmcamcorder_conf_get_value_element_name(sc->VideosinkElement, &videosink_name); + if (!strcmp(videosink_name, "xvimagesink")) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, + "flip", display_flip); + _mmcam_dbg_log("Set display flip [%d] done.", display_flip); + return TRUE; + } else { + _mmcam_dbg_warn("videosink[%s] does not support DISPLAY_FLIP", videosink_name); + return FALSE; + } + } else { + _mmcam_dbg_err("Videosink element is null"); + return FALSE; + } +} + + bool _mmcamcorder_set_videosrc_rotation(MMHandleType handle, int videosrc_rotate) { int width = 0; @@ -2103,8 +2197,6 @@ bool _mmcamcorder_set_videosrc_rotation(MMHandleType handle, int videosrc_rotate int set_height = 0; int set_rotate = 0; int fps = 0; - int slow_fps = 0; - int set_fps = 0; gboolean do_set_caps = FALSE; GstCaps *caps = NULL; @@ -2134,7 +2226,6 @@ bool _mmcamcorder_set_videosrc_rotation(MMHandleType handle, int videosrc_rotate MMCAM_CAMERA_WIDTH, &width, MMCAM_CAMERA_HEIGHT, &height, MMCAM_CAMERA_FPS, &fps, - "camera-slow-motion-fps", &slow_fps, NULL); _mmcamcorder_conf_get_value_int_array(hcamcorder->conf_ctrl, @@ -2146,48 +2237,53 @@ bool _mmcamcorder_set_videosrc_rotation(MMHandleType handle, int videosrc_rotate return FALSE; } - /* Define width, height, rotate and flip in caps */ - if (input_index->default_value == MM_VIDEO_DEVICE_CAMERA1) { - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "vflip", 1); - } else { - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "vflip", 0); - } - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hflip", 0); + /* Interleaved format does not support rotation */ + if (sc->info_image->preview_format != MM_PIXEL_FORMAT_ITLV_JPEG_UYVY) { + /* store videosrc rotation */ + sc->videosrc_rotate = videosrc_rotate; - /* This will be applied when rotate is 0, 90, 180, 270 if rear camera. - This will be applied when rotate is 0, 180 if front camera. */ - set_rotate = videosrc_rotate * 90; + /* Define width, height and rotate in caps */ - if (videosrc_rotate == MM_VIDEO_INPUT_ROTATION_90 || - videosrc_rotate == MM_VIDEO_INPUT_ROTATION_270) { - set_width = height; - set_height = width; + /* This will be applied when rotate is 0, 90, 180, 270 if rear camera. + This will be applied when rotate is 0, 180 if front camera. */ + set_rotate = videosrc_rotate * 90; - if (input_index->default_value == MM_VIDEO_DEVICE_CAMERA1) { - if (videosrc_rotate == MM_VIDEO_INPUT_ROTATION_90) { - set_rotate = 270; - } else { - set_rotate = 90; + if (videosrc_rotate == MM_VIDEO_INPUT_ROTATION_90 || + videosrc_rotate == MM_VIDEO_INPUT_ROTATION_270) { + set_width = height; + set_height = width; + if (input_index->default_value == MM_VIDEO_DEVICE_CAMERA1) { + if (videosrc_rotate == MM_VIDEO_INPUT_ROTATION_90) { + set_rotate = 270; + } else { + set_rotate = 90; + } } + } else { + set_width = width; + set_height = height; } } else { + sc->videosrc_rotate = MM_VIDEO_INPUT_ROTATION_NONE; + set_rotate = 0; set_width = width; set_height = height; - if (videosrc_rotate == MM_VIDEO_INPUT_ROTATION_FLIP_HORZ) { - set_rotate = 0; - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hflip", 1); - } else if (videosrc_rotate == MM_VIDEO_INPUT_ROTATION_FLIP_VERT) { - set_rotate = 0; - if (input_index->default_value == MM_VIDEO_DEVICE_CAMERA1) { - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "vflip", 0); - } else { - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "vflip", 1); - } - } + _mmcam_dbg_warn("ITLV format doe snot support INPUT ROTATE. Ignore ROTATE[%d]", + videosrc_rotate); } - set_fps = sc->is_slow ? slow_fps : fps; + /* correct size because ITLV does not support QCIF */ + if (input_index->default_value == MM_VIDEO_DEVICE_CAMERA0 && + sc->fourcc == GST_MAKE_FOURCC('I','T','L','V')) { + if ((set_width == 176 && set_height == 144) || + (set_width == 144 && set_height == 176)) { + set_width = set_width << 1; + set_height = set_height << 1; + _mmcam_dbg_log("ITLV format is not supported QCIF, so we set CIF(%dx%d)", + set_width, set_height); + } + } MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_VIDEOSRC_FILT].gst, "caps", &caps); if (caps) { @@ -2205,7 +2301,7 @@ bool _mmcamcorder_set_videosrc_rotation(MMHandleType handle, int videosrc_rotate gst_structure_get_int(structure, "fps", &caps_fps); gst_structure_get_int(structure, "rotate", &caps_rotate); if (set_width == caps_width && set_height == caps_height && - set_rotate == caps_rotate && set_fps == caps_fps) { + set_rotate == caps_rotate && fps == caps_fps) { _mmcam_dbg_log("No need to replace caps."); } else { _mmcam_dbg_log("something is different. set new one..."); @@ -2228,7 +2324,7 @@ bool _mmcamcorder_set_videosrc_rotation(MMHandleType handle, int videosrc_rotate "format", GST_TYPE_FOURCC, sc->fourcc, "width", G_TYPE_INT, set_width, "height", G_TYPE_INT, set_height, - "framerate", GST_TYPE_FRACTION, set_fps, 1, + "framerate", GST_TYPE_FRACTION, fps, 1, "rotate", G_TYPE_INT, set_rotate, NULL); MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_FILT].gst, "caps", caps); @@ -2236,8 +2332,158 @@ bool _mmcamcorder_set_videosrc_rotation(MMHandleType handle, int videosrc_rotate caps = NULL; _mmcam_dbg_log("vidoesrc new caps set. format[%c%c%c%c],width[%d],height[%d],fps[%d],rotate[%d]", (sc->fourcc), (sc->fourcc)>>8, (sc->fourcc)>>16, (sc->fourcc)>>24, - set_width, set_height, set_fps, set_rotate); + set_width, set_height, fps, set_rotate); } return TRUE; } + + +bool _mmcamcorder_set_videosrc_flip(MMHandleType handle, int videosrc_flip) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + type_int_array *input_index = NULL; + + mmf_return_val_if_fail(hcamcorder, FALSE); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, TRUE); + + _mmcam_dbg_log("Set FLIP %d", videosrc_flip); + + if (sc->element && sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) { + int hflip = 0; + int vflip = 0; + + /* Interleaved format does not support FLIP */ + if (sc->info_image->preview_format != MM_PIXEL_FORMAT_ITLV_JPEG_UYVY) { + _mmcamcorder_conf_get_value_int_array(hcamcorder->conf_ctrl, + CONFIGURE_CATEGORY_CTRL_CAMERA, + "InputIndex", + &input_index ); + + hflip = (videosrc_flip & MM_FLIP_HORIZONTAL) == MM_FLIP_HORIZONTAL; + vflip = (videosrc_flip & MM_FLIP_VERTICAL) == MM_FLIP_VERTICAL; + + _mmcam_dbg_log("videosrc flip H:%d, V:%d", hflip, vflip); + + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hflip", hflip); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "vflip", vflip); + } else { + _mmcam_dbg_warn("ITLV format does not support FLIP. Ignore FLIP[%d]", + videosrc_flip); + } + } else { + _mmcam_dbg_warn("element is NULL"); + return FALSE; + } + + return TRUE; +} + + +bool _mmcamcorder_set_videosrc_anti_shake(MMHandleType handle, int anti_shake) +{ + GstCameraControl *control = NULL; + _MMCamcorderSubContext *sc = NULL; + GstElement *v_src = NULL; + + int set_value = 0; + + mmf_return_val_if_fail(handle, FALSE); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, TRUE); + + v_src = sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst; + + if (!v_src) { + _mmcam_dbg_warn("videosrc element is NULL"); + return FALSE; + } + + set_value = _mmcamcorder_convert_msl_to_sensor(handle, MM_CAM_CAMERA_ANTI_HANDSHAKE, anti_shake); + + /* set anti-shake with camera control */ + if (!GST_IS_CAMERA_CONTROL(v_src)) { + _mmcam_dbg_warn("Can't cast Video source into camera control."); + return FALSE; + } + + control = GST_CAMERA_CONTROL(v_src); + if (gst_camera_control_set_ahs(control, set_value)) { + _mmcam_dbg_log("Succeed in operating anti-handshake. value[%d]", set_value); + return TRUE; + } else { + _mmcam_dbg_warn("Failed to operate anti-handshake. value[%d]", set_value); + } + + return FALSE; +} + + +bool _mmcamcorder_set_videosrc_stabilization(MMHandleType handle, int stabilization) +{ + _MMCamcorderSubContext *sc = NULL; + GstElement *v_src = NULL; + + mmf_return_val_if_fail(handle, FALSE); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, TRUE); + + v_src = sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst; + + if (!v_src) { + _mmcam_dbg_warn("videosrc element is NULL"); + return FALSE; + } + + /* check property of videosrc element - support VDIS */ + if(g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(v_src)), "enable-vdis-mode")) { + int camera_format =MM_PIXEL_FORMAT_INVALID; + int camera_width = 0; + int camera_height = 0; + + if (stabilization == MM_CAMCORDER_VIDEO_STABILIZATION_ON) { + _mmcam_dbg_log("ENABLE video stabilization"); + + /* VDIS mode only supports NV12 and [720p or 1080p] */ + mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAMERA_FORMAT, &camera_format, + MMCAM_CAMERA_WIDTH, &camera_width, + MMCAM_CAMERA_HEIGHT, &camera_height, + NULL); + if (camera_format == MM_PIXEL_FORMAT_NV12 && + camera_width >= 1280 && + camera_height >= 720) { + _mmcam_dbg_log("preview format %d, size %dx%d, ENABLE video stabilization", + camera_format, camera_width, camera_height, stabilization); + /* set vdis mode */ + g_object_set(G_OBJECT(v_src), + "enable-vdis-mode", TRUE, + NULL); + } else { + _mmcam_dbg_warn("invalid preview format %d or size %dx%d", + camera_format, camera_width, camera_height); + return FALSE; + } + } else { + /* set vdis mode */ + g_object_set(G_OBJECT(v_src), + "enable-vdis-mode", FALSE, + NULL); + + _mmcam_dbg_log("DISABLE video stabilization"); + } + } else if (stabilization == MM_CAMCORDER_VIDEO_STABILIZATION_ON) { + _mmcam_dbg_err("no property for video stabilization, so can not set ON"); + return FALSE; + } else { + _mmcam_dbg_warn("no property for video stabilization"); + } + + return TRUE; +} + diff --git a/src/mm_camcorder_internal.c b/src/mm_camcorder_internal.c index 50528e9..bc1b1f1 100644 --- a/src/mm_camcorder_internal.c +++ b/src/mm_camcorder_internal.c @@ -47,9 +47,9 @@ /*--------------------------------------------------------------------------------------- | LOCAL VARIABLE DEFINITIONS for internal | ---------------------------------------------------------------------------------------*/ - -//#define _MMCAM_USING_CAPTUREMODE -#define __MMCAMCORDER_CMD_ITERATE_MAX 3 +#define __MMCAMCORDER_CMD_ITERATE_MAX 3 +#define __MMCAMCORDER_SECURITY_HANDLE_DEFAULT -1 +#define __MMCAMCORDER_SET_GST_STATE_TIMEOUT 5 /*--------------------------------------------------------------------------------------- | LOCAL FUNCTION PROTOTYPES: | @@ -68,12 +68,16 @@ static gboolean __mmcamcorder_handle_gst_warning(MMHandleType handle, GstMessage static int __mmcamcorder_asm_get_event_type(int sessionType); static void __mmcamcorder_force_stop(mmf_camcorder_t *hcamcorder); static void __mmcamcorder_force_resume(mmf_camcorder_t *hcamcorder); -ASM_cb_result_t _mmcamcorder_asm_callback(int handle, ASM_event_sources_t event_src, - ASM_sound_commands_t command, - unsigned int sound_status, void *cb_data); - +ASM_cb_result_t _mmcamcorder_asm_callback_sh(int handle, ASM_event_sources_t event_src, + ASM_sound_commands_t command, + unsigned int sound_status, void *cb_data); +ASM_cb_result_t _mmcamcorder_asm_callback_ex(int handle, ASM_event_sources_t event_src, + ASM_sound_commands_t command, + unsigned int sound_status, void *cb_data); + +#ifdef _MMCAMCORDER_USE_SET_ATTR_CB static gboolean __mmcamcorder_set_attr_to_camsensor_cb(gpointer data); - +#endif /* _MMCAMCORDER_USE_SET_ATTR_CB */ /*======================================================================================= | FUNCTION DEFINITIONS | @@ -87,19 +91,24 @@ int _mmcamcorder_create(MMHandleType *handle, MMCamPreset *info) { int ret = MM_ERROR_NONE; int UseConfCtrl = 0; - int sessionType = MM_SESSION_TYPE_EXCLUSIVE; + int sessionType = MM_SESSION_TYPE_SHARE; int errorcode = MM_ERROR_NONE; int rcmd_fmt_capture = MM_PIXEL_FORMAT_YUYV; int rcmd_fmt_recording = MM_PIXEL_FORMAT_NV12; int rcmd_dpy_rotation = MM_DISPLAY_ROTATION_270; + int play_capture_sound = TRUE; + int camera_device_count = MM_VIDEO_DEVICE_NUM; + int camera_facing_direction = MM_CAMCORDER_CAMERA_FACING_DIRECTION_REAR; char *err_attr_name = NULL; char *ConfCtrlFile = NULL; mmf_camcorder_t *hcamcorder = NULL; ASM_resource_t mm_resource = ASM_RESOURCE_NONE; + type_element *EvasSurfaceElement = NULL; _mmcam_dbg_log("Entered"); - mmf_return_val_if_fail( handle, MM_ERROR_CAMCORDER_INVALID_ARGUMENT ); + mmf_return_val_if_fail(handle, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + mmf_return_val_if_fail(info, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); /* Create mmf_camcorder_t handle and initialize every variable */ hcamcorder = (mmf_camcorder_t *)malloc(sizeof(mmf_camcorder_t)); @@ -107,10 +116,10 @@ int _mmcamcorder_create(MMHandleType *handle, MMCamPreset *info) memset(hcamcorder, 0x00, sizeof(mmf_camcorder_t)); /* init values */ - hcamcorder->type=0; - hcamcorder->state=MM_CAMCORDER_STATE_NULL; - hcamcorder->sub_context=NULL; - hcamcorder->target_state=MM_CAMCORDER_STATE_NULL; + hcamcorder->type = 0; + hcamcorder->state = MM_CAMCORDER_STATE_NONE; + hcamcorder->sub_context = NULL; + hcamcorder->target_state = MM_CAMCORDER_STATE_NULL; /* thread - for g_mutex_new() */ if (!g_thread_supported()) { @@ -144,29 +153,34 @@ int _mmcamcorder_create(MMHandleType *handle, MMCamPreset *info) /* Check and register ASM */ if (MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType)) { - _mmcam_dbg_warn("Read _mm_session_util_read_type failed. use default \"exclusive\" type"); - sessionType = MM_SESSION_TYPE_EXCLUSIVE; - if (MM_ERROR_NONE != mm_session_init(sessionType)) { - _mmcam_dbg_err("mm_session_init() failed"); - ret = MM_ERROR_POLICY_INTERNAL; - goto _ERR_DEFAULT_VALUE_INIT; - } + _mmcam_dbg_log("_mm_session_util_read_type Fail. but keep going..."); + sessionType = MM_SESSION_TYPE_SHARE; } + + /* Call will not be interrupted. so does not need callback function */ if ((sessionType != MM_SESSION_TYPE_CALL) && (sessionType != MM_SESSION_TYPE_VIDEOCALL)) { - int asm_session_type = ASM_EVENT_NONE; - int asm_handle; int pid = -1; /* process id of itself */ - asm_session_type = __mmcamcorder_asm_get_event_type( sessionType ); - /* Call will not be interrupted. so does not need callback function */ - if (!ASM_register_sound(pid, &asm_handle, asm_session_type, ASM_STATE_NONE, - (ASM_sound_cb_t)_mmcamcorder_asm_callback, + /* set SHARE session */ + if (!ASM_register_sound(pid, &(hcamcorder->asm_handle_sh), ASM_EVENT_SHARE_MMCAMCORDER, ASM_STATE_NONE, + (ASM_sound_cb_t)_mmcamcorder_asm_callback_sh, (void*)hcamcorder, mm_resource, &errorcode)) { - _mmcam_dbg_err("ASM_register_sound() failed[%x]", errorcode); + _mmcam_dbg_err("SHARE ASM_register_sound() failed[%x]", errorcode); ret = MM_ERROR_POLICY_INTERNAL; goto _ERR_DEFAULT_VALUE_INIT; } - hcamcorder->asm_handle = asm_handle; + + /* set EXCLUSIVE session */ + if (!ASM_register_sound(pid, &(hcamcorder->asm_handle_ex), ASM_EVENT_EXCLUSIVE_MMCAMCORDER, ASM_STATE_NONE, + (ASM_sound_cb_t)_mmcamcorder_asm_callback_ex, + (void*)hcamcorder, mm_resource, &errorcode)) { + _mmcam_dbg_err("EXCLUSIVE ASM_register_sound() failed[%x]", errorcode); + ret = MM_ERROR_POLICY_INTERNAL; + goto _ERR_DEFAULT_VALUE_INIT; + } + + _mmcam_dbg_log("ASM handle - SHARE %d, EXCLUSIVE %d", + hcamcorder->asm_handle_sh, hcamcorder->asm_handle_ex); } /* Get Camera Configure information from Camcorder INI file */ @@ -181,8 +195,8 @@ int _mmcamcorder_create(MMHandleType *handle, MMCamPreset *info) goto _ERR_AUDIO_BLOCKED; } - __ta__(" _mmcamcorder_alloc_attribute", - hcamcorder->attributes= _mmcamcorder_alloc_attribute((MMHandleType)hcamcorder, info); + __ta__(" _mmcamcorder_alloc_attribute", + hcamcorder->attributes = _mmcamcorder_alloc_attribute((MMHandleType)hcamcorder, info); ); if (!(hcamcorder->attributes)) { _mmcam_dbg_err("_mmcamcorder_create::alloc attribute error."); @@ -247,6 +261,62 @@ int _mmcamcorder_create(MMHandleType *handle, MMCamPreset *info) if (ret != MM_ERROR_NONE) { _mmcam_dbg_warn("converting table initialize error!!"); } + + /* Get device info, recommend preview fmt and display rotation from INI */ + _mmcamcorder_conf_get_value_int(hcamcorder->conf_ctrl, + CONFIGURE_CATEGORY_CTRL_CAMERA, + "RecommendPreviewFormatCapture", + &rcmd_fmt_capture); + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_ctrl, + CONFIGURE_CATEGORY_CTRL_CAMERA, + "RecommendPreviewFormatRecord", + &rcmd_fmt_recording); + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_ctrl, + CONFIGURE_CATEGORY_CTRL_CAMERA, + "RecommendDisplayRotation", + &rcmd_dpy_rotation); + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_CAPTURE, + "PlayCaptureSound", + &play_capture_sound); + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, + "DeviceCount", + &camera_device_count); + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_ctrl, + CONFIGURE_CATEGORY_CTRL_CAMERA, + "FacingDirection", + &camera_facing_direction); + + _mmcam_dbg_log("Recommend fmt[cap:%d,rec:%d], dpy rot[%d], cap snd[%d], dev cnt[%d], cam facing dir[%d]", + rcmd_fmt_capture, rcmd_fmt_recording, rcmd_dpy_rotation, + play_capture_sound, camera_device_count, camera_facing_direction); + + mm_camcorder_set_attributes((MMHandleType)hcamcorder, &err_attr_name, + MMCAM_CAMERA_DEVICE_COUNT, camera_device_count, + MMCAM_CAMERA_FACING_DIRECTION, camera_facing_direction, + MMCAM_RECOMMEND_PREVIEW_FORMAT_FOR_CAPTURE, rcmd_fmt_capture, + MMCAM_RECOMMEND_PREVIEW_FORMAT_FOR_RECORDING, rcmd_fmt_recording, + MMCAM_RECOMMEND_DISPLAY_ROTATION, rcmd_dpy_rotation, + "capture-sound-enable", play_capture_sound, + NULL); + if (err_attr_name) { + _mmcam_dbg_err("Set %s FAILED.", err_attr_name); + free(err_attr_name); + err_attr_name = NULL; + } + + /* Get UseZeroCopyFormat value from INI */ + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, + "UseZeroCopyFormat", + &(hcamcorder->use_zero_copy_format)); + _mmcam_dbg_log("UseZeroCopyFormat : %d", hcamcorder->use_zero_copy_format); } else { @@ -264,53 +334,6 @@ int _mmcamcorder_create(MMHandleType *handle, MMCamPreset *info) goto _ERR_ALLOC_ATTRIBUTE; } - /* Get recommend preview format and display rotation from INI */ - rcmd_fmt_capture = MM_PIXEL_FORMAT_YUYV; - rcmd_fmt_recording = MM_PIXEL_FORMAT_NV12; - rcmd_dpy_rotation = MM_DISPLAY_ROTATION_270; - err_attr_name = NULL; - - _mmcamcorder_conf_get_value_int(hcamcorder->conf_ctrl, - CONFIGURE_CATEGORY_CTRL_CAMERA, - "RecommendPreviewFormatCapture", - &rcmd_fmt_capture); - - _mmcamcorder_conf_get_value_int(hcamcorder->conf_ctrl, - CONFIGURE_CATEGORY_CTRL_CAMERA, - "RecommendPreviewFormatRecord", - &rcmd_fmt_recording); - - _mmcamcorder_conf_get_value_int(hcamcorder->conf_ctrl, - CONFIGURE_CATEGORY_CTRL_CAMERA, - "RecommendDisplayRotation", - &rcmd_dpy_rotation); - - _mmcam_dbg_log("Recommend prv[capture:%d,recording:%d], rot[%d]", - rcmd_fmt_capture, rcmd_fmt_recording, rcmd_dpy_rotation); - - ret = mm_camcorder_set_attributes((MMHandleType)hcamcorder, &err_attr_name, - MMCAM_RECOMMEND_PREVIEW_FORMAT_FOR_CAPTURE, rcmd_fmt_capture, - MMCAM_RECOMMEND_PREVIEW_FORMAT_FOR_RECORDING, rcmd_fmt_recording, - MMCAM_RECOMMEND_DISPLAY_ROTATION, rcmd_dpy_rotation, - NULL); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_err( "Set %s FAILED.", err_attr_name ); - if (err_attr_name != NULL) { - free( err_attr_name ); - err_attr_name = NULL; - } - - goto _ERR_ALLOC_ATTRIBUTE; - } - - /* Get UseZeroCopyFormat value from INI */ - _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, - CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, - "UseZeroCopyFormat", - &(hcamcorder->use_zero_copy_format)); - _mmcam_dbg_log("UseZeroCopyFormat : %d", hcamcorder->use_zero_copy_format); - - /* Make some attributes as read-only type */ __ta__( " _mmcamcorder_lock_readonly_attributes", _mmcamcorder_lock_readonly_attributes((MMHandleType)hcamcorder); @@ -330,6 +353,30 @@ int _mmcamcorder_create(MMHandleType *handle, MMCamPreset *info) _mmcamcorder_create_command_loop((MMHandleType)hcamcorder); } + /* Get videosink name for evas surface */ + _mmcamcorder_conf_get_element(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT, + "VideosinkElementEvas", + &EvasSurfaceElement); + if (EvasSurfaceElement) { + int attr_index = 0; + char *evassink_name = NULL; + mmf_attribute_t *item_evassink_name = NULL; + mmf_attrs_t *attrs = (mmf_attrs_t *)MMF_CAMCORDER_ATTRS(hcamcorder); + + _mmcamcorder_conf_get_value_element_name(EvasSurfaceElement, &evassink_name); + mm_attrs_get_index((MMHandleType)attrs, MMCAM_DISPLAY_EVAS_SURFACE_SINK, &attr_index); + item_evassink_name = &attrs->items[attr_index]; + mmf_attribute_set_string(item_evassink_name, evassink_name, strlen(evassink_name)); + mmf_attribute_commit(item_evassink_name); + + _mmcam_dbg_log("Evassink name : %s", evassink_name); + } + + /* get shutter sound policy */ + vconf_get_int(VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY, &hcamcorder->shutter_sound_policy); + _mmcam_dbg_log("current shutter sound policy : %d", hcamcorder->shutter_sound_policy); + /* Set initial state */ _mmcamcorder_set_state((MMHandleType)hcamcorder, MM_CAMCORDER_STATE_NULL); _mmcam_dbg_log("_mmcamcorder_set_state"); @@ -342,17 +389,22 @@ _ERR_ALLOC_ATTRIBUTE: _ERR_AUDIO_BLOCKED: /* unregister audio session manager */ { - sessionType = MM_SESSION_TYPE_EXCLUSIVE; errorcode = MM_ERROR_NONE; if (MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType)) { - sessionType = MM_SESSION_TYPE_EXCLUSIVE; + _mmcam_dbg_log("_mm_session_util_read_type Fail. but keep going..."); + sessionType = MM_SESSION_TYPE_SHARE; } if((sessionType != MM_SESSION_TYPE_CALL) && (sessionType != MM_SESSION_TYPE_VIDEOCALL)) { - int asm_session_type = __mmcamcorder_asm_get_event_type( sessionType ); - if (!ASM_unregister_sound(hcamcorder->asm_handle, asm_session_type, &errorcode)) { - _mmcam_dbg_err("ASM_unregister_sound() failed(hdl:%p, stype:%d, err:%x)", - (void*)hcamcorder->asm_handle, sessionType, errorcode); + /* unregister SHARE session */ + if (!ASM_unregister_sound(hcamcorder->asm_handle_sh, ASM_EVENT_SHARE_MMCAMCORDER, &errorcode)) { + _mmcam_dbg_err("ASM_unregister_sound() SHARE failed(hdl:%p, stype:%d, err:%x)", + (void*)hcamcorder->asm_handle_sh, sessionType, errorcode); + } + /* unregister EXCLUSIVE session */ + if (!ASM_unregister_sound(hcamcorder->asm_handle_ex, ASM_EVENT_EXCLUSIVE_MMCAMCORDER, &errorcode)) { + _mmcam_dbg_err("ASM_unregister_sound() EXCLUSIVE failed(hdl:%p, stype:%d, err:%x)", + (void*)hcamcorder->asm_handle_ex, sessionType, errorcode); } } } @@ -382,11 +434,10 @@ int _mmcamcorder_destroy(MMHandleType handle) int state = MM_CAMCORDER_STATE_NONE; int state_FROM = MM_CAMCORDER_STATE_NULL; int state_TO = MM_CAMCORDER_STATE_NONE; - int asm_session_type = ASM_EVENT_EXCLUSIVE_MMCAMCORDER; int sessionType = MM_SESSION_TYPE_SHARE; int errorcode = MM_ERROR_NONE; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); - _MMCamcorderMsgItem msg; _mmcam_dbg_log(""); @@ -416,12 +467,6 @@ int _mmcamcorder_destroy(MMHandleType handle) goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; } - /* Release sound handle */ - __ta__("_mmcamcorder_sound_finalize", - ret = _mmcamcorder_sound_finalize(handle); - ); - _mmcam_dbg_log("sound finalize [%d]", ret); - /* Release SubContext and pipeline */ if (hcamcorder->sub_context) { if (hcamcorder->sub_context->element) { @@ -472,13 +517,20 @@ int _mmcamcorder_destroy(MMHandleType handle) /* Unregister ASM */ if (MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType)) { - _mmcam_dbg_err("_mm_session_util_read_type Fail"); + _mmcam_dbg_log("_mm_session_util_read_type Fail. but keep going..."); + sessionType = MM_SESSION_TYPE_SHARE; } if ((sessionType != MM_SESSION_TYPE_CALL) && (sessionType != MM_SESSION_TYPE_VIDEOCALL)) { - asm_session_type = __mmcamcorder_asm_get_event_type(sessionType); - if (!ASM_unregister_sound(hcamcorder->asm_handle, asm_session_type, &errorcode)) { - _mmcam_dbg_err("ASM_unregister_sound() failed(hdl:%p, stype:%d, err:%x)", - (void*)hcamcorder->asm_handle, sessionType, errorcode); + /* unregister SHARE session */ + if (!ASM_unregister_sound(hcamcorder->asm_handle_sh, ASM_EVENT_SHARE_MMCAMCORDER, &errorcode)) { + _mmcam_dbg_err("SHARE ASM_unregister_sound() failed(hdl:%p, err:%x)", + (void*)hcamcorder->asm_handle_sh, errorcode); + } + + /* unregister EXCLUSIVE session */ + if (!ASM_unregister_sound(hcamcorder->asm_handle_ex, ASM_EVENT_EXCLUSIVE_MMCAMCORDER, &errorcode)) { + _mmcam_dbg_err("EXCLUSIVE ASM_unregister_sound() failed(hdl:%p, err:%x)", + (void*)hcamcorder->asm_handle_ex, errorcode); } } @@ -537,18 +589,12 @@ _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: _MMCAMCORDER_UNLOCK_CMD(hcamcorder); _ERR_CAMCORDER_CMD_PRECON: - /*send message*/ if (hcamcorder) { - _mmcam_dbg_err("Destroy fail (%d, %d)", hcamcorder->type, state); - msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; - msg.param.state.previous = state; - msg.param.state.current = state; - msg.param.state.code = ret; - _mmcamcroder_send_message(handle, &msg); - } else { - _mmcam_dbg_err("Destroy fail (%d)", state); + _mmcam_dbg_err("Destroy fail (type %d, state %d)", hcamcorder->type, state); } + _mmcam_dbg_err("Destroy fail (ret %x)", ret); + return ret; } @@ -559,12 +605,13 @@ int _mmcamcorder_realize(MMHandleType handle) int state = MM_CAMCORDER_STATE_NONE; int state_FROM = MM_CAMCORDER_STATE_NULL; int state_TO = MM_CAMCORDER_STATE_READY; - int sessionType = MM_SESSION_TYPE_EXCLUSIVE; + int sessionType = MM_SESSION_TYPE_SHARE; int errorcode = MM_ERROR_NONE; int display_surface_type = MM_DISPLAY_SURFACE_X; + double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE; char *videosink_element_type = NULL; char *videosink_name = NULL; - _MMCamcorderMsgItem msg; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _mmcam_dbg_log(""); @@ -595,6 +642,18 @@ int _mmcamcorder_realize(MMHandleType handle) goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; } + /* set camera state to vconf key */ + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + int vconf_camera_state = 0; + + /* get current camera state of vconf key */ + vconf_get_int(VCONFKEY_CAMERA_STATE, &vconf_camera_state); + vconf_set_int(VCONFKEY_CAMERA_STATE, VCONFKEY_CAMERA_STATE_OPEN); + + _mmcam_dbg_log("VCONFKEY_CAMERA_STATE prev %d -> cur %d", + vconf_camera_state, VCONFKEY_CAMERA_STATE_OPEN); + } + /* Set async state */ ret = _mmcamcorder_set_async_state(handle, state_TO); if (ret < 0) { @@ -602,37 +661,37 @@ int _mmcamcorder_realize(MMHandleType handle) goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; } + mm_camcorder_get_attributes(handle, NULL, + MMCAM_MODE, &hcamcorder->type, + MMCAM_DISPLAY_SURFACE, &display_surface_type, + MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate, + NULL); + /* Get profile mode */ - mm_camcorder_get_attributes(handle, NULL, MMCAM_MODE, &hcamcorder->type, NULL); _mmcam_dbg_log("Profile mode set is (%d)", hcamcorder->type); - /* Check and register ASM */ + /* Check and make SHARE session as PLAYING */ if (MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType)) { - _mmcam_dbg_warn("Read _mm_session_util_read_type failed. use default \"exclusive\" type"); - sessionType = MM_SESSION_TYPE_EXCLUSIVE; + _mmcam_dbg_log("_mm_session_util_read_type Fail. but keep going..."); + sessionType = MM_SESSION_TYPE_SHARE; } if ((sessionType != MM_SESSION_TYPE_CALL) && (sessionType != MM_SESSION_TYPE_VIDEOCALL)) { - int asm_session_type = ASM_EVENT_NONE; ASM_resource_t mm_resource = ASM_RESOURCE_NONE; - asm_session_type = __mmcamcorder_asm_get_event_type(sessionType); switch (hcamcorder->type) { - case MM_CAMCORDER_MODE_VIDEO: - mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY | ASM_RESOURCE_HW_ENCODER; - break; case MM_CAMCORDER_MODE_AUDIO: mm_resource = ASM_RESOURCE_NONE; break; - case MM_CAMCORDER_MODE_IMAGE: + case MM_CAMCORDER_MODE_VIDEO_CAPTURE: default: - mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY; + mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY | ASM_RESOURCE_HW_ENCODER; break; } - if (!ASM_set_sound_state(hcamcorder->asm_handle, asm_session_type, + if (!ASM_set_sound_state(hcamcorder->asm_handle_sh, ASM_EVENT_SHARE_MMCAMCORDER, ASM_STATE_PLAYING, mm_resource, &errorcode)) { - debug_error("Set state to playing failed 0x%X\n", errorcode); - ret = MM_ERROR_POLICY_BLOCKED; + _mmcam_dbg_err("Set state to playing failed 0x%x", errorcode); + ret = MM_ERROR_POLICY_BLOCKED; goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; } } @@ -645,7 +704,15 @@ int _mmcamcorder_realize(MMHandleType handle) } /* Set basic configure information */ - mm_camcorder_get_attributes(handle, NULL, MMCAM_DISPLAY_SURFACE, &display_surface_type, NULL); + if (motion_rate != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) { + hcamcorder->sub_context->is_modified_rate = TRUE; + } + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_CAPTURE, + "UseEncodebin", + &(hcamcorder->sub_context->bencbin_capture)); + switch (display_surface_type) { case MM_DISPLAY_SURFACE_X: videosink_element_type = strdup("VideosinkElementX"); @@ -663,18 +730,28 @@ int _mmcamcorder_realize(MMHandleType handle) videosink_element_type = strdup("VideosinkElementX"); break; } - _mmcamcorder_conf_get_element(hcamcorder->conf_main, - CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT, - videosink_element_type, - &hcamcorder->sub_context->VideosinkElement ); - _mmcamcorder_conf_get_value_element_name( hcamcorder->sub_context->VideosinkElement, &videosink_name ); - _mmcam_dbg_log( "Videosink name : %s", videosink_name ); + /* check string of videosink element */ if (videosink_element_type) { + _mmcamcorder_conf_get_element(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT, + videosink_element_type, + &hcamcorder->sub_context->VideosinkElement); free(videosink_element_type); videosink_element_type = NULL; + } else { + _mmcam_dbg_warn("strdup failed(display_surface_type %d). Use default X type", + display_surface_type); + + _mmcamcorder_conf_get_element(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT, + _MMCAMCORDER_DEFAULT_VIDEOSINK_TYPE, + &hcamcorder->sub_context->VideosinkElement ); } + _mmcamcorder_conf_get_value_element_name(hcamcorder->sub_context->VideosinkElement, &videosink_name); + _mmcam_dbg_log("Videosink name : %s", videosink_name); + _mmcamcorder_conf_get_value_int(hcamcorder->conf_ctrl, CONFIGURE_CATEGORY_CTRL_CAPTURE, "SensorEncodedCapture", @@ -685,7 +762,14 @@ int _mmcamcorder_realize(MMHandleType handle) __ta__(" _mmcamcorder_create_pipeline", ret = _mmcamcorder_create_pipeline(handle, hcamcorder->type); ); - if(ret<0) { + if (ret != MM_ERROR_NONE) { + /* check internal error of gstreamer */ + if (hcamcorder->sub_context->error_code != MM_ERROR_NONE) { + ret = hcamcorder->sub_context->error_code; + _mmcam_dbg_log("gstreamer error is occurred. return it %x", ret); + } + + /* release sub context */ _mmcamcorder_dealloc_subcontext(hcamcorder->sub_context); hcamcorder->sub_context = NULL; goto _ERR_CAMCORDER_CMD; @@ -693,8 +777,7 @@ int _mmcamcorder_realize(MMHandleType handle) /* set command function */ ret = _mmcamcorder_set_functions(handle, hcamcorder->type); - - if(ret<0) { + if (ret != MM_ERROR_NONE) { _mmcamcorder_destroy_pipeline(handle, hcamcorder->type); _mmcamcorder_dealloc_subcontext(hcamcorder->sub_context); hcamcorder->sub_context = NULL; @@ -702,6 +785,7 @@ int _mmcamcorder_realize(MMHandleType handle) } _mmcamcorder_set_state(handle, state_TO); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); return MM_ERROR_NONE; @@ -714,14 +798,20 @@ _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: _MMCAMCORDER_UNLOCK_CMD(hcamcorder); _ERR_CAMCORDER_CMD_PRECON: - /* send message */ - _mmcam_dbg_err("Realize fail (%d, %d, %x)", hcamcorder->type, state, ret); + _mmcam_dbg_err("Realize fail (type %d, state %d, ret %x)", + hcamcorder->type, state, ret); - msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; - msg.param.state.previous = state; - msg.param.state.current = state; - msg.param.state.code = ret; - _mmcamcroder_send_message(handle, &msg); + /* rollback camera state to vconf key */ + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + int vconf_camera_state = 0; + + /* get current camera state of vconf key */ + vconf_get_int(VCONFKEY_CAMERA_STATE, &vconf_camera_state); + vconf_set_int(VCONFKEY_CAMERA_STATE, VCONFKEY_CAMERA_STATE_NULL); + + _mmcam_dbg_log("VCONFKEY_CAMERA_STATE prev %d -> cur %d", + vconf_camera_state, VCONFKEY_CAMERA_STATE_NULL); + } return ret; } @@ -734,9 +824,8 @@ int _mmcamcorder_unrealize(MMHandleType handle) int state_FROM = MM_CAMCORDER_STATE_READY; int state_TO = MM_CAMCORDER_STATE_NULL; int sessionType = MM_SESSION_TYPE_SHARE; - int asm_session_type = ASM_EVENT_NONE; ASM_resource_t mm_resource = ASM_RESOURCE_NONE; - _MMCamcorderMsgItem msg; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _mmcam_dbg_log(""); @@ -767,12 +856,6 @@ int _mmcamcorder_unrealize(MMHandleType handle) goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; } - /* Release sound handle */ - __ta__("_mmcamcorder_sound_finalize", - ret = _mmcamcorder_sound_finalize(handle); - ); - _mmcam_dbg_log("sound finalize [%d]", ret); - /* Release SubContext */ if (hcamcorder->sub_context) { /* destroy pipeline */ @@ -786,36 +869,49 @@ int _mmcamcorder_unrealize(MMHandleType handle) hcamcorder->command = NULL; - if (MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType)) { - _mmcam_dbg_err("_mm_session_util_read_type Fail\n"); - } - - if ((sessionType != MM_SESSION_TYPE_CALL) && (sessionType != MM_SESSION_TYPE_VIDEOCALL)) { - asm_session_type = ASM_EVENT_NONE; - mm_resource = ASM_RESOURCE_NONE; - asm_session_type = __mmcamcorder_asm_get_event_type( sessionType ); - - switch (hcamcorder->type) { - case MM_CAMCORDER_MODE_VIDEO: - mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY | ASM_RESOURCE_HW_ENCODER; - break; - case MM_CAMCORDER_MODE_AUDIO: - mm_resource = ASM_RESOURCE_NONE; - break; - case MM_CAMCORDER_MODE_IMAGE: - default: - mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY; - break; + /* check who calls unrealize. it's no need to set ASM state if caller is ASM */ + if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) { + if (MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType)) { + _mmcam_dbg_log("_mm_session_util_read_type Fail. but keep going..."); + sessionType = MM_SESSION_TYPE_SHARE; } /* Call session is not ended here */ - if (!ASM_set_sound_state(hcamcorder->asm_handle, asm_session_type, - ASM_STATE_STOP, mm_resource, &ret)) { - _mmcam_dbg_err("Set state to playing failed 0x%X\n", ret); + if ((sessionType != MM_SESSION_TYPE_CALL) && (sessionType != MM_SESSION_TYPE_VIDEOCALL)) { + mm_resource = ASM_RESOURCE_NONE; + + switch (hcamcorder->type) { + case MM_CAMCORDER_MODE_AUDIO: + mm_resource = ASM_RESOURCE_NONE; + break; + case MM_CAMCORDER_MODE_VIDEO_CAPTURE: + default: + mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY | ASM_RESOURCE_HW_ENCODER; + break; + } + + /* STOP SHARE session */ + if (!ASM_set_sound_state(hcamcorder->asm_handle_sh, ASM_EVENT_SHARE_MMCAMCORDER, + ASM_STATE_STOP, mm_resource, &ret)) { + _mmcam_dbg_err("SHARE Set state to STOP failed 0x%x", ret); + } } } _mmcamcorder_set_state(handle, state_TO); + + /* set camera state to vconf key */ + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + int vconf_camera_state = 0; + + /* get current camera state of vconf key */ + vconf_get_int(VCONFKEY_CAMERA_STATE, &vconf_camera_state); + vconf_set_int(VCONFKEY_CAMERA_STATE, VCONFKEY_CAMERA_STATE_NULL); + + _mmcam_dbg_log("VCONFKEY_CAMERA_STATE prev %d -> cur %d", + vconf_camera_state, VCONFKEY_CAMERA_STATE_NULL); + } + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); return MM_ERROR_NONE; @@ -825,13 +921,8 @@ _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: _ERR_CAMCORDER_CMD_PRECON: /* send message */ - _mmcam_dbg_err("Unrealize fail (%d, %d)", hcamcorder->type, state); - - msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; - msg.param.state.previous = state; - msg.param.state.current = state; - msg.param.state.code = ret; - _mmcamcroder_send_message(handle, &msg); + _mmcam_dbg_err("Unrealize fail (type %d, state %d, ret %x)", + hcamcorder->type, state, ret); return ret; } @@ -842,7 +933,7 @@ int _mmcamcorder_start(MMHandleType handle) int state = MM_CAMCORDER_STATE_NONE; int state_FROM = MM_CAMCORDER_STATE_READY; int state_TO =MM_CAMCORDER_STATE_PREPARE; - _MMCamcorderMsgItem msg; + _MMCamcorderSubContext *sc = NULL; mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); @@ -877,6 +968,9 @@ int _mmcamcorder_start(MMHandleType handle) goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; } + /* initialize error code */ + hcamcorder->sub_context->error_code = MM_ERROR_NONE; + /* set async state */ ret = _mmcamcorder_set_async_state(handle, state_TO); if (ret != MM_ERROR_NONE) { @@ -892,7 +986,18 @@ int _mmcamcorder_start(MMHandleType handle) _mmcamcorder_set_state(handle, state_TO); if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + int vconf_camera_state = 0; + _mmcamcorder_set_attribute_to_camsensor(handle); + + /* check camera state of vconf key */ + vconf_get_int(VCONFKEY_CAMERA_STATE, &vconf_camera_state); + + /* set camera state to vconf key */ + vconf_set_int(VCONFKEY_CAMERA_STATE, VCONFKEY_CAMERA_STATE_PREVIEW); + + _mmcam_dbg_log("VCONFKEY_CAMERA_STATE prev %d -> cur %d", + vconf_camera_state, VCONFKEY_CAMERA_STATE_PREVIEW); } _MMCAMCORDER_UNLOCK_CMD(hcamcorder); @@ -907,14 +1012,16 @@ _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: _MMCAMCORDER_UNLOCK_CMD(hcamcorder); _ERR_CAMCORDER_CMD_PRECON: - /* send message */ - _mmcam_dbg_err("Start fail (%d, %d)", hcamcorder->type, state); + /* check internal error of gstreamer */ + if (hcamcorder->sub_context->error_code != MM_ERROR_NONE) { + ret = hcamcorder->sub_context->error_code; + hcamcorder->sub_context->error_code = MM_ERROR_NONE; - msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; - msg.param.state.previous = state; - msg.param.state.current = state; - msg.param.state.code = ret; - _mmcamcroder_send_message(handle, &msg); + _mmcam_dbg_log("gstreamer error is occurred. return it %x", ret); + } + + _mmcam_dbg_err("Start fail (type %d, state %d, ret %x)", + hcamcorder->type, state, ret); return ret; } @@ -926,7 +1033,7 @@ int _mmcamcorder_stop(MMHandleType handle) int state_FROM = MM_CAMCORDER_STATE_PREPARE; int state_TO = MM_CAMCORDER_STATE_READY; int frame_rate = 0; - _MMCamcorderMsgItem msg; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _mmcam_dbg_log(""); @@ -967,6 +1074,20 @@ int _mmcamcorder_stop(MMHandleType handle) __ta__(__tafmt__("MM_CAM_006:: Frame per sec : %d", frame_rate), ;); _mmcamcorder_set_state(handle, state_TO); + + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + int vconf_camera_state = 0; + + /* check camera state of vconf key */ + vconf_get_int(VCONFKEY_CAMERA_STATE, &vconf_camera_state); + + /* set camera state to vconf key */ + vconf_set_int(VCONFKEY_CAMERA_STATE, VCONFKEY_CAMERA_STATE_OPEN); + + _mmcam_dbg_log("VCONFKEY_CAMERA_STATE prev %d -> cur %d", + vconf_camera_state, VCONFKEY_CAMERA_STATE_OPEN); + } + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); return MM_ERROR_NONE; @@ -980,13 +1101,8 @@ _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: _ERR_CAMCORDER_CMD_PRECON: /* send message */ - _mmcam_dbg_err("Stop fail (%d, %d)", hcamcorder->type, state); - - msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; - msg.param.state.previous = state; - msg.param.state.current = state; - msg.param.state.code = ret; - _mmcamcroder_send_message(handle, &msg); + _mmcam_dbg_err("Stop fail (type %d, state %d, ret %x)", + hcamcorder->type, state, ret); return ret; } @@ -996,11 +1112,12 @@ int _mmcamcorder_capture_start(MMHandleType handle) { int ret = MM_ERROR_NONE; int state = MM_CAMCORDER_STATE_NONE; - int state_FROM = MM_CAMCORDER_STATE_PREPARE; + int state_FROM_0 = MM_CAMCORDER_STATE_PREPARE; + int state_FROM_1 = MM_CAMCORDER_STATE_RECORDING; + int state_FROM_2 = MM_CAMCORDER_STATE_PAUSED; int state_TO = MM_CAMCORDER_STATE_CAPTURING; char *err_name = NULL; - _MMCamcorderMsgItem msg; mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _mmcam_dbg_log(""); @@ -1018,7 +1135,9 @@ int _mmcamcorder_capture_start(MMHandleType handle) } state = _mmcamcorder_get_state(handle); - if (state != state_FROM) { + if (state != state_FROM_0 && + state != state_FROM_1 && + state != state_FROM_2) { _mmcam_dbg_err("Wrong state(%d)", state); ret = MM_ERROR_CAMCORDER_INVALID_STATE; goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; @@ -1036,7 +1155,10 @@ int _mmcamcorder_capture_start(MMHandleType handle) goto _ERR_CAMCORDER_CMD; } - _mmcamcorder_set_state(handle, state_TO); + /* Do not change state when recording snapshot capture */ + if (state == state_FROM_0) { + _mmcamcorder_set_state(handle, state_TO); + } /* Init break continuous shot attr */ mm_camcorder_set_attributes(handle, &err_name, "capture-break-cont-shot", 0, NULL); @@ -1054,13 +1176,8 @@ _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: _ERR_CAMCORDER_CMD_PRECON: /* send message */ - _mmcam_dbg_err("Capture start fail (%d, %d)", hcamcorder->type, state); - - msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; - msg.param.state.previous = state; - msg.param.state.current = state; - msg.param.state.code = ret; - _mmcamcroder_send_message(handle, &msg); + _mmcam_dbg_err("Capture start fail (type %d, state %d, ret %x)", + hcamcorder->type, state, ret); return ret; } @@ -1071,7 +1188,6 @@ int _mmcamcorder_capture_stop(MMHandleType handle) int state = MM_CAMCORDER_STATE_NONE; int state_FROM = MM_CAMCORDER_STATE_CAPTURING; int state_TO = MM_CAMCORDER_STATE_PREPARE; - _MMCamcorderMsgItem msg; mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _mmcam_dbg_log(""); @@ -1109,21 +1225,10 @@ int _mmcamcorder_capture_stop(MMHandleType handle) _mmcamcorder_set_state(handle, state_TO); - /* Set strobe mode - strobe mode can not be set to driver while captuing */ -{ - __ta__("Set strobe mode after capture", - mmf_attrs_t *attr = (mmf_attrs_t *)MMF_CAMCORDER_ATTRS(handle); - if (attr) { - mmf_attribute_set_modified(&(attr->items[MM_CAM_STROBE_MODE])); - if (mmf_attrs_commit((MMHandleType) attr) == -1) { - _mmcam_dbg_warn("Failed to set strobe mode"); - } - } - ); -} - _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + MMTA_ACUM_ITEM_END("Real First Capture Start", FALSE); + return MM_ERROR_NONE; _ERR_CAMCORDER_CMD: @@ -1135,13 +1240,8 @@ _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: _ERR_CAMCORDER_CMD_PRECON: /* send message */ - _mmcam_dbg_err("Capture stop fail (%d, %d)", hcamcorder->type, state); - - msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; - msg.param.state.previous = state; - msg.param.state.current = state; - msg.param.state.code = ret; - _mmcamcroder_send_message(handle, &msg); + _mmcam_dbg_err("Capture stop fail (type %d, state %d, ret %x)", + hcamcorder->type, state, ret); return ret; } @@ -1153,7 +1253,8 @@ int _mmcamcorder_record(MMHandleType handle) int state_FROM1 = MM_CAMCORDER_STATE_PREPARE; int state_FROM2 = MM_CAMCORDER_STATE_PAUSED; int state_TO = MM_CAMCORDER_STATE_RECORDING; - _MMCamcorderMsgItem msg; + int sessionType = MM_SESSION_TYPE_SHARE; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _mmcam_dbg_log(""); @@ -1177,6 +1278,36 @@ int _mmcamcorder_record(MMHandleType handle) goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; } + /* initialize error code */ + hcamcorder->sub_context->error_code = MM_ERROR_NONE; + + /* Check and register EXCLUSIVE ASM */ + if (MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType)) { + _mmcam_dbg_log("_mm_session_util_read_type Fail. but keep going..."); + sessionType = MM_SESSION_TYPE_SHARE; + } + if ((sessionType != MM_SESSION_TYPE_CALL) && (sessionType != MM_SESSION_TYPE_VIDEOCALL)) { + int errorcode; + ASM_resource_t mm_resource = ASM_RESOURCE_NONE; + + switch (hcamcorder->type) { + case MM_CAMCORDER_MODE_AUDIO: + mm_resource = ASM_RESOURCE_NONE; + break; + case MM_CAMCORDER_MODE_VIDEO_CAPTURE: + default: + mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY | ASM_RESOURCE_HW_ENCODER; + break; + } + + if (!ASM_set_sound_state(hcamcorder->asm_handle_ex, ASM_EVENT_EXCLUSIVE_MMCAMCORDER, + ASM_STATE_PLAYING, mm_resource, &errorcode)) { + _mmcam_dbg_err("Set state to playing failed 0x%x", errorcode); + ret = MM_ERROR_POLICY_BLOCKED; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + } + /* set async state */ ret = _mmcamcorder_set_async_state(handle, state_TO); if (ret != MM_ERROR_NONE) { @@ -1190,6 +1321,19 @@ int _mmcamcorder_record(MMHandleType handle) } _mmcamcorder_set_state(handle, state_TO); + + /* set camera state to vconf key */ + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + int vconf_camera_state = 0; + + /* get current camera state of vconf key */ + vconf_get_int(VCONFKEY_CAMERA_STATE, &vconf_camera_state); + vconf_set_int(VCONFKEY_CAMERA_STATE, VCONFKEY_CAMERA_STATE_RECORDING); + + _mmcam_dbg_log("VCONFKEY_CAMERA_STATE prev %d -> cur %d", + vconf_camera_state, VCONFKEY_CAMERA_STATE_RECORDING); + } + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); return MM_ERROR_NONE; @@ -1202,14 +1346,16 @@ _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: _MMCAMCORDER_UNLOCK_CMD(hcamcorder); _ERR_CAMCORDER_CMD_PRECON: - /* send message */ - _mmcam_dbg_err("Record fail (%d, %d)", hcamcorder->type, state); + /* check internal error of gstreamer */ + if (hcamcorder->sub_context->error_code != MM_ERROR_NONE) { + ret = hcamcorder->sub_context->error_code; + hcamcorder->sub_context->error_code = MM_ERROR_NONE; - msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; - msg.param.state.previous = state; - msg.param.state.current = state; - msg.param.state.code = ret; - _mmcamcroder_send_message(handle, &msg); + _mmcam_dbg_log("gstreamer error is occurred. return it %x", ret); + } + + _mmcam_dbg_err("Record fail (type %d, state %d, ret %x)", + hcamcorder->type, state, ret); return ret; } @@ -1221,7 +1367,7 @@ int _mmcamcorder_pause(MMHandleType handle) int state = MM_CAMCORDER_STATE_NONE; int state_FROM = MM_CAMCORDER_STATE_RECORDING; int state_TO = MM_CAMCORDER_STATE_PAUSED; - _MMCamcorderMsgItem msg; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _mmcam_dbg_log(""); @@ -1258,6 +1404,19 @@ int _mmcamcorder_pause(MMHandleType handle) } _mmcamcorder_set_state(handle, state_TO); + + /* set camera state to vconf key */ + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + int vconf_camera_state = 0; + + /* get current camera state of vconf key */ + vconf_get_int(VCONFKEY_CAMERA_STATE, &vconf_camera_state); + vconf_set_int(VCONFKEY_CAMERA_STATE, VCONFKEY_CAMERA_STATE_RECORDING_PAUSE); + + _mmcam_dbg_log("VCONFKEY_CAMERA_STATE prev %d -> cur %d", + vconf_camera_state, VCONFKEY_CAMERA_STATE_RECORDING_PAUSE); + } + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); return MM_ERROR_NONE; @@ -1271,13 +1430,8 @@ _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: _ERR_CAMCORDER_CMD_PRECON: /* send message */ - _mmcam_dbg_err("Pause fail (%d, %d)", hcamcorder->type, state); - - msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; - msg.param.state.previous = state; - msg.param.state.current = state; - msg.param.state.code = ret; - _mmcamcroder_send_message(handle, &msg); + _mmcam_dbg_err("Pause fail (type %d, state %d, ret %x)", + hcamcorder->type, state, ret); return ret; } @@ -1290,7 +1444,7 @@ int _mmcamcorder_commit(MMHandleType handle) int state_FROM1 = MM_CAMCORDER_STATE_RECORDING; int state_FROM2 = MM_CAMCORDER_STATE_PAUSED; int state_TO = MM_CAMCORDER_STATE_PREPARE; - _MMCamcorderMsgItem msg; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _mmcam_dbg_log(""); @@ -1327,6 +1481,49 @@ int _mmcamcorder_commit(MMHandleType handle) } _mmcamcorder_set_state(handle,state_TO); + + /* set camera state to vconf key */ + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + int vconf_camera_state = 0; + + /* get current camera state of vconf key */ + vconf_get_int(VCONFKEY_CAMERA_STATE, &vconf_camera_state); + vconf_set_int(VCONFKEY_CAMERA_STATE, VCONFKEY_CAMERA_STATE_PREVIEW); + + _mmcam_dbg_log("VCONFKEY_CAMERA_STATE prev %d -> cur %d", + vconf_camera_state, VCONFKEY_CAMERA_STATE_PREVIEW); + } + + /* check who calls unrealize. it's no need to set ASM state if caller is ASM */ + if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) { + int sessionType = MM_SESSION_TYPE_SHARE; + ASM_resource_t mm_resource = ASM_RESOURCE_NONE; + + if (MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType)) { + _mmcam_dbg_log("_mm_session_util_read_type Fail. but keep going..."); + sessionType = MM_SESSION_TYPE_SHARE; + } + + /* Call session is not ended here */ + if ((sessionType != MM_SESSION_TYPE_CALL) && (sessionType != MM_SESSION_TYPE_VIDEOCALL)) { + switch (hcamcorder->type) { + case MM_CAMCORDER_MODE_AUDIO: + mm_resource = ASM_RESOURCE_NONE; + break; + case MM_CAMCORDER_MODE_VIDEO_CAPTURE: + default: + mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY | ASM_RESOURCE_HW_ENCODER; + break; + } + + /* STOP EXCLUSIVE session */ + if (!ASM_set_sound_state(hcamcorder->asm_handle_ex, ASM_EVENT_EXCLUSIVE_MMCAMCORDER, + ASM_STATE_STOP, mm_resource, &ret)) { + _mmcam_dbg_err("EXCLUSIVE Set state to STOP failed 0x%x", ret); + } + } + } + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); return MM_ERROR_NONE; @@ -1340,13 +1537,8 @@ _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: _ERR_CAMCORDER_CMD_PRECON: /* send message */ - _mmcam_dbg_err("Commit fail (%d, %d)", hcamcorder->type, state); - - msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; - msg.param.state.previous = state; - msg.param.state.current = state; - msg.param.state.code = ret; - _mmcamcroder_send_message(handle, &msg); + _mmcam_dbg_err("Commit fail (type %d, state %d, ret %x)", + hcamcorder->type, state, ret); return ret; } @@ -1359,7 +1551,8 @@ int _mmcamcorder_cancel(MMHandleType handle) int state_FROM1 = MM_CAMCORDER_STATE_RECORDING; int state_FROM2 = MM_CAMCORDER_STATE_PAUSED; int state_TO = MM_CAMCORDER_STATE_PREPARE; - _MMCamcorderMsgItem msg; + int sessionType = MM_SESSION_TYPE_SHARE; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _mmcam_dbg_log(""); @@ -1396,6 +1589,46 @@ int _mmcamcorder_cancel(MMHandleType handle) } _mmcamcorder_set_state(handle, state_TO); + + /* read session type */ + if (MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType)) { + _mmcam_dbg_log("_mm_session_util_read_type Fail. but keep going..."); + sessionType = MM_SESSION_TYPE_SHARE; + } + + /* Call session is not ended here */ + if ((sessionType != MM_SESSION_TYPE_CALL) && (sessionType != MM_SESSION_TYPE_VIDEOCALL)) { + ASM_resource_t mm_resource = ASM_RESOURCE_NONE; + + switch (hcamcorder->type) { + case MM_CAMCORDER_MODE_AUDIO: + mm_resource = ASM_RESOURCE_NONE; + break; + case MM_CAMCORDER_MODE_VIDEO_CAPTURE: + default: + mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY | ASM_RESOURCE_HW_ENCODER; + break; + } + + /* STOP EXCLUSIVE session */ + if (!ASM_set_sound_state(hcamcorder->asm_handle_ex, ASM_EVENT_EXCLUSIVE_MMCAMCORDER, + ASM_STATE_STOP, mm_resource, &ret)) { + _mmcam_dbg_err("EXCLUSIVE Set state to STOP failed 0x%x", ret); + } + } + + /* set camera state to vconf key */ + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + int vconf_camera_state = 0; + + /* get current camera state of vconf key */ + vconf_get_int(VCONFKEY_CAMERA_STATE, &vconf_camera_state); + vconf_set_int(VCONFKEY_CAMERA_STATE, VCONFKEY_CAMERA_STATE_PREVIEW); + + _mmcam_dbg_log("VCONFKEY_CAMERA_STATE prev %d -> cur %d", + vconf_camera_state, VCONFKEY_CAMERA_STATE_PREVIEW); + } + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); return MM_ERROR_NONE; @@ -1409,13 +1642,8 @@ _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: _ERR_CAMCORDER_CMD_PRECON: /* send message */ - _mmcam_dbg_err("Cancel fail (%d, %d)", hcamcorder->type, state); - - msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; - msg.param.state.previous = state; - msg.param.state.current = state; - msg.param.state.code = ret; - _mmcamcroder_send_message(handle, &msg); + _mmcam_dbg_err("Cancel fail (type %d, state %d, ret %x)", + hcamcorder->type, state, ret); return ret; } @@ -1550,12 +1778,14 @@ int _mmcamcorder_get_current_state(MMHandleType handle) int _mmcamcorder_init_focusing(MMHandleType handle) { - int ret = 0; + int ret = TRUE; int state = MM_CAMCORDER_STATE_NONE; int focus_mode = MM_CAMCORDER_FOCUS_MODE_NONE; int af_range = MM_CAMCORDER_AUTO_FOCUS_NORMAL; int sensor_focus_mode = 0; int sensor_af_range = 0; + int current_focus_mode = 0; + int current_af_range = 0; mmf_camcorder_t *hcamcorder = NULL; _MMCamcorderSubContext *sc = NULL; mmf_attrs_t *attr = NULL; @@ -1603,10 +1833,18 @@ int _mmcamcorder_init_focusing(MMHandleType handle) MMCAM_CAMERA_FOCUS_MODE, &focus_mode, MMCAM_CAMERA_AF_SCAN_RANGE, &af_range, NULL); - sensor_af_range = _mmcamcorder_convert_msl_to_sensor(MM_CAM_CAMERA_AF_SCAN_RANGE, af_range); - sensor_focus_mode = _mmcamcorder_convert_msl_to_sensor(MM_CAM_CAMERA_FOCUS_MODE, focus_mode); + sensor_af_range = _mmcamcorder_convert_msl_to_sensor(handle, MM_CAM_CAMERA_AF_SCAN_RANGE, af_range); + sensor_focus_mode = _mmcamcorder_convert_msl_to_sensor(handle, MM_CAM_CAMERA_FOCUS_MODE, focus_mode); - ret = gst_camera_control_set_focus(control, sensor_focus_mode, sensor_af_range); + gst_camera_control_get_focus(control, ¤t_focus_mode, ¤t_af_range); + + if (current_focus_mode != sensor_focus_mode || + current_af_range != sensor_af_range) { + ret = gst_camera_control_set_focus(control, sensor_focus_mode, sensor_af_range); + } else { + _mmcam_dbg_log("No need to init FOCUS [mode:%d, range:%d]", focus_mode, af_range ); + ret = TRUE; + } _MMCAMCORDER_UNLOCK_CMD(hcamcorder); @@ -1724,7 +1962,6 @@ int _mmcamcorder_adjust_manual_focus(MMHandleType handle, int direction) int _mmcamcorder_adjust_auto_focus(MMHandleType handle) { - int af_mode = MM_CAMCORDER_FOCUS_MODE_AUTO; gboolean ret; mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); GstCameraControl *control = NULL; @@ -1745,11 +1982,6 @@ int _mmcamcorder_adjust_auto_focus(MMHandleType handle) /* Start AF */ ret = gst_camera_control_start_auto_focus(control); if (ret) { - mm_camcorder_get_attributes(handle, NULL, MMCAM_CAMERA_FOCUS_MODE, &af_mode, NULL); - if (af_mode == MM_CAMCORDER_FOCUS_MODE_CONTINUOUS) { - sc->now_continuous_af = TRUE; - _mmcam_dbg_log("Set now_continuous_af as TRUE"); - } _mmcam_dbg_log("Auto focusing start success."); return MM_ERROR_NONE; } else { @@ -1793,8 +2025,6 @@ int _mmcamcorder_stop_focusing(MMHandleType handle) control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); ret = gst_camera_control_stop_auto_focus(control); - sc->now_continuous_af = FALSE; - _mmcam_dbg_log("Set now_continuous_af as FALSE"); _MMCAMCORDER_UNLOCK_CMD(hcamcorder); @@ -1866,7 +2096,7 @@ __mmcamcorder_gstreamer_init(camera_conf * conf) ); if (!ret) { - _mmcam_dbg_err("Could not initialize GStreamer: %s\n", + _mmcam_dbg_err("Could not initialize GStreamer: %s ", err ? err->message : "unknown error occurred"); if (err) { g_error_free (err); @@ -1953,6 +2183,7 @@ void _mmcamcorder_set_state(MMHandleType handle, int state) msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED_BY_ASM; msg.param.state.code = hcamcorder->asm_event_code; break; + case _MMCAMCORDER_STATE_CHANGE_NORMAL: default: msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; msg.param.state.code = MM_ERROR_NONE; @@ -2096,44 +2327,49 @@ _MMCamcorderSubContext *_mmcamcorder_alloc_subcontext(int type) /* alloc info for each mode */ switch (type) { - case MM_CAMCORDER_MODE_IMAGE: - sc->info = malloc( sizeof(_MMCamcorderImageInfo)); - if(sc->info == NULL) { + case MM_CAMCORDER_MODE_AUDIO: + sc->info_audio = malloc( sizeof(_MMCamcorderAudioInfo)); + if(sc->info_audio == NULL) { _mmcam_dbg_err("Failed to alloc info structure"); free(sc); return NULL; } - memset(sc->info, 0x00, sizeof(_MMCamcorderImageInfo)); + memset(sc->info_audio, 0x00, sizeof(_MMCamcorderAudioInfo)); break; - case MM_CAMCORDER_MODE_AUDIO: - sc->info = malloc( sizeof(_MMCamcorderAudioInfo)); - if(sc->info == NULL) { + case MM_CAMCORDER_MODE_VIDEO_CAPTURE: + default: + sc->info_image = malloc( sizeof(_MMCamcorderImageInfo)); + if(sc->info_image == NULL) { _mmcam_dbg_err("Failed to alloc info structure"); free(sc); return NULL; } - memset(sc->info, 0x00, sizeof(_MMCamcorderAudioInfo)); - break; - case MM_CAMCORDER_MODE_VIDEO: - sc->info = malloc( sizeof(_MMCamcorderVideoInfo)); - if(sc->info == NULL) { + memset(sc->info_image, 0x00, sizeof(_MMCamcorderImageInfo)); + + /* init sound status */ + sc->info_image->sound_status = _SOUND_STATUS_INIT; + + sc->info_video = malloc( sizeof(_MMCamcorderVideoInfo)); + if(sc->info_video == NULL) { _mmcam_dbg_err("Failed to alloc info structure"); + free(sc->info_image); free(sc); return NULL; } - memset(sc->info, 0x00, sizeof(_MMCamcorderVideoInfo)); + memset(sc->info_video, 0x00, sizeof(_MMCamcorderVideoInfo)); break; - default: - _mmcam_dbg_err("unknown type[%d]", type); - free(sc); - return NULL; } /* alloc element array */ sc->element = (_MMCamcorderGstElement *)malloc(sizeof(_MMCamcorderGstElement) * sc->element_num); if(!sc->element) { _mmcam_dbg_err("Failed to alloc element structure"); - free(sc->info); + if (type == MM_CAMCORDER_MODE_AUDIO) { + free(sc->info_audio); + } else { + free(sc->info_image); + free(sc->info_video); + } free(sc); return NULL; } @@ -2144,10 +2380,10 @@ _MMCamcorderSubContext *_mmcamcorder_alloc_subcontext(int type) } sc->fourcc = 0x80000000; - sc->cam_stability_count = 0; - sc->drop_vframe = 0; - sc->pass_first_vframe = 0; + sc->drop_vframe = 0; + sc->pass_first_vframe = 0; + sc->is_modified_rate = FALSE; return sc; } @@ -2163,9 +2399,22 @@ void _mmcamcorder_dealloc_subcontext(_MMCamcorderSubContext *sc) sc->element = NULL; } - if (sc->info) { - free(sc->info); - sc->info = NULL; + if (sc->info_image) { + _mmcam_dbg_log("release info_image"); + free(sc->info_image); + sc->info_image = NULL; + } + + if (sc->info_video) { + _mmcam_dbg_log("release info_video"); + free(sc->info_video); + sc->info_video = NULL; + } + + if (sc->info_audio) { + _mmcam_dbg_log("release info_audio"); + free(sc->info_audio); + sc->info_audio = NULL; } free(sc); @@ -2183,17 +2432,12 @@ int _mmcamcorder_set_functions(MMHandleType handle, int type) _mmcam_dbg_log(""); switch (type) { - case MM_CAMCORDER_MODE_VIDEO: - hcamcorder->command = _mmcamcorder_video_command; - break; case MM_CAMCORDER_MODE_AUDIO: hcamcorder->command = _mmcamcorder_audio_command; break; - case MM_CAMCORDER_MODE_IMAGE: - hcamcorder->command = _mmcamcorder_image_command; - break; + case MM_CAMCORDER_MODE_VIDEO_CAPTURE: default: - return MM_ERROR_CAMCORDER_INTERNAL; + hcamcorder->command = _mmcamcorder_video_capture_command; break; } @@ -2222,16 +2466,15 @@ gboolean _mmcamcorder_pipeline_cb_message(GstBus *bus, GstMessage *message, gpoi sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); mmf_return_val_if_fail(sc, TRUE); - mmf_return_val_if_fail(sc->info, TRUE); - if (hcamcorder->type == MM_CAMCORDER_MODE_VIDEO) { - _MMCamcorderVideoInfo *info = sc->info; - if (info->b_commiting) { + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + mmf_return_val_if_fail(sc->info_video, TRUE); + if (sc->info_video->b_commiting) { _mmcamcorder_video_handle_eos((MMHandleType)hcamcorder); } - } else if (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO) { - _MMCamcorderAudioInfo *info = sc->info; - if (info->b_commiting) { + } else { + mmf_return_val_if_fail(sc->info_audio, TRUE); + if (sc->info_audio->b_commiting) { _mmcamcorder_audio_handle_eos((MMHandleType)hcamcorder); } } @@ -2338,6 +2581,90 @@ gboolean _mmcamcorder_pipeline_cb_message(GstBus *bus, GstMessage *message, gpoi msg.id = MM_MESSAGE_CAMCORDER_FOCUS_CHANGED; msg.param.code = focus_state; _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + } else if (gst_structure_has_name(message->structure, "camerasrc-HDR")) { + int progress = 0; + int status = 0; + + gst_structure_get_int(message->structure, "progress", &progress); + gst_structure_get_int(message->structure, "status", &status); + _mmcam_dbg_log("HDR progress %d percent, status %d", progress, status); + + msg.id = MM_MESSAGE_CAMCORDER_HDR_PROGRESS; + msg.param.code = progress; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + } else if (gst_structure_has_name(message->structure, "camerasrc-FD")) { + int i = 0; + const GValue *g_value = gst_structure_get_value(message->structure, "face-info");; + GstCameraControlFaceDetectInfo *fd_info = NULL; + MMCamFaceDetectInfo *cam_fd_info = NULL; + + if (g_value) { + fd_info = (GstCameraControlFaceDetectInfo *)g_value_get_pointer(g_value); + } + + if (fd_info == NULL) { + _mmcam_dbg_warn("fd_info is NULL"); + return TRUE; + } + + cam_fd_info = (MMCamFaceDetectInfo *)malloc(sizeof(MMCamFaceDetectInfo)); + if (cam_fd_info == NULL) { + _mmcam_dbg_warn("cam_fd_info alloc failed"); + + free(fd_info); + fd_info = NULL; + + return TRUE; + } + + /* set total face count */ + cam_fd_info->num_of_faces = fd_info->num_of_faces; + + if (cam_fd_info->num_of_faces > 0) { + cam_fd_info->face_info = (MMCamFaceInfo *)malloc(sizeof(MMCamFaceInfo) * cam_fd_info->num_of_faces); + if (cam_fd_info->face_info) { + /* set information of each face */ + for (i = 0 ; i < fd_info->num_of_faces ; i++) { + cam_fd_info->face_info[i].id = fd_info->face_info[i].id; + cam_fd_info->face_info[i].score = fd_info->face_info[i].score; + cam_fd_info->face_info[i].rect.x = fd_info->face_info[i].rect.x; + cam_fd_info->face_info[i].rect.y = fd_info->face_info[i].rect.y; + cam_fd_info->face_info[i].rect.width = fd_info->face_info[i].rect.width; + cam_fd_info->face_info[i].rect.height = fd_info->face_info[i].rect.height; + /* + _mmcam_dbg_log("id %d, score %d, [%d,%d,%dx%d]", + fd_info->face_info[i].id, + fd_info->face_info[i].score, + fd_info->face_info[i].rect.x, + fd_info->face_info[i].rect.y, + fd_info->face_info[i].rect.width, + fd_info->face_info[i].rect.height); + */ + } + } else { + _mmcam_dbg_warn("MMCamFaceInfo alloc failed"); + + /* free allocated memory that is not sent */ + free(cam_fd_info); + cam_fd_info = NULL; + } + } else { + cam_fd_info->face_info = NULL; + } + + if (cam_fd_info) { + /* send message - cam_fd_info should be freed by application */ + msg.id = MM_MESSAGE_CAMCORDER_FACE_DETECT_INFO; + msg.param.data = cam_fd_info; + msg.param.size = sizeof(MMCamFaceDetectInfo); + msg.param.code = 0; + + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + } + + /* free fd_info allocated by plugin */ + free(fd_info); + fd_info = NULL; } break; case GST_MESSAGE_SEGMENT_START: @@ -2370,6 +2697,101 @@ gboolean _mmcamcorder_pipeline_cb_message(GstBus *bus, GstMessage *message, gpoi } +GstBusSyncReply _mmcamcorder_pipeline_bus_sync_callback(GstBus *bus, GstMessage *message, gpointer data) +{ + GstElement *element = NULL; + GError *err = NULL; + gchar *debug_info = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(hcamcorder, GST_BUS_PASS); + mmf_return_val_if_fail(message, GST_BUS_PASS); + + sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + mmf_return_val_if_fail(sc, GST_BUS_PASS); + + sc->error_code = MM_ERROR_NONE; + + if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) { + /* parse error message */ + gst_message_parse_error(message, &err, &debug_info); + + if (!err) { + _mmcam_dbg_warn("failed to parse error message"); + return GST_BUS_PASS; + } + + if (debug_info) { + _mmcam_dbg_err("GST ERROR : %s", debug_info); + g_free(debug_info); + debug_info = NULL; + } + + /* set videosrc element to compare */ + element = GST_ELEMENT_CAST(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); + + /* check domain[RESOURCE] and element[VIDEOSRC] */ + if (err->domain == GST_RESOURCE_ERROR && + GST_ELEMENT_CAST(message->src) == element) { + switch (err->code) { + case GST_RESOURCE_ERROR_BUSY: + _mmcam_dbg_err("Camera device [busy]"); + sc->error_code = MM_ERROR_CAMCORDER_DEVICE_BUSY; + break; + case GST_RESOURCE_ERROR_OPEN_READ_WRITE: + case GST_RESOURCE_ERROR_OPEN_WRITE: + _mmcam_dbg_err("Camera device [open failed]"); + sc->error_code = MM_ERROR_CAMCORDER_DEVICE_OPEN; + break; + case GST_RESOURCE_ERROR_OPEN_READ: + _mmcam_dbg_err("Camera device [register trouble]"); + sc->error_code = MM_ERROR_CAMCORDER_DEVICE_REG_TROUBLE; + break; + case GST_RESOURCE_ERROR_NOT_FOUND: + _mmcam_dbg_err("Camera device [device not found]"); + sc->error_code = MM_ERROR_CAMCORDER_DEVICE_NOT_FOUND; + break; + case GST_RESOURCE_ERROR_TOO_LAZY: + _mmcam_dbg_err("Camera device [timeout]"); + sc->error_code = MM_ERROR_CAMCORDER_DEVICE_TIMEOUT; + break; + case GST_RESOURCE_ERROR_SETTINGS: + _mmcam_dbg_err("Camera device [not supported]"); + sc->error_code = MM_ERROR_CAMCORDER_NOT_SUPPORTED; + break; + case GST_RESOURCE_ERROR_FAILED: + _mmcam_dbg_err("Camera device [working failed]."); + sc->error_code = MM_ERROR_CAMCORDER_DEVICE_IO; + break; + default: + _mmcam_dbg_err("Camera device [General(%d)]", err->code); + sc->error_code = MM_ERROR_CAMCORDER_DEVICE; + break; + } + + sc->error_occurs = TRUE; + } + + g_error_free(err); + + /* store error code and drop this message if cmd is running */ + if (sc->error_code != MM_ERROR_NONE) { + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("cmd is running and will be returned with this error %x", + sc->error_code); + return GST_BUS_DROP; + } + + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + } + } + + return GST_BUS_PASS; +} + + static int __mmcamcorder_asm_get_event_type(int sessionType) { switch (sessionType) { @@ -2390,9 +2812,9 @@ static int __mmcamcorder_asm_get_event_type(int sessionType) } } -ASM_cb_result_t _mmcamcorder_asm_callback(int handle, ASM_event_sources_t event_src, - ASM_sound_commands_t command, - unsigned int sound_status, void* cb_data) +ASM_cb_result_t _mmcamcorder_asm_callback_sh(int handle, ASM_event_sources_t event_src, + ASM_sound_commands_t command, + unsigned int sound_status, void* cb_data) { mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(cb_data); int current_state = MM_CAMCORDER_STATE_NONE; @@ -2411,6 +2833,8 @@ ASM_cb_result_t _mmcamcorder_asm_callback(int handle, ASM_event_sources_t event_ /* set ASM event code for sending it to application */ hcamcorder->asm_event_code = event_src; + _mmcam_dbg_log("ASM SHARE callback : event code 0x%x, command 0x%x", event_src, command); + switch (command) { case ASM_COMMAND_STOP: case ASM_COMMAND_PAUSE: @@ -2426,10 +2850,80 @@ ASM_cb_result_t _mmcamcorder_asm_callback(int handle, ASM_event_sources_t event_ if (current_state >= MM_CAMCORDER_STATE_PREPARE) { _mmcam_dbg_log("Already start previewing"); - return ASM_CB_RES_PLAYING; + } else { + __mmcamcorder_force_resume(hcamcorder); + } + + cb_res = ASM_CB_RES_PLAYING; + + _mmcam_dbg_log("Finish opeartion. Preview is started.(%d)", cb_res); + break; + case ASM_COMMAND_RESUME: + { + _MMCamcorderMsgItem msg; + + _mmcam_dbg_log("Got msg from asm to Resume(%d, %d)", command, current_state); + + msg.id = MM_MESSAGE_READY_TO_RESUME; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + cb_res = ASM_CB_RES_PLAYING; + + _mmcam_dbg_log("Finish opeartion.(%d)", cb_res); + break; + } + default: /* should not be reached here */ + cb_res = ASM_CB_RES_PLAYING; + _mmcam_dbg_err("Command err."); + break; + } + + /* restore value */ + hcamcorder->state_change_by_system = _MMCAMCORDER_STATE_CHANGE_NORMAL; + + return cb_res; +} + + +ASM_cb_result_t _mmcamcorder_asm_callback_ex(int handle, ASM_event_sources_t event_src, + ASM_sound_commands_t command, + unsigned int sound_status, void* cb_data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(cb_data); + int current_state = MM_CAMCORDER_STATE_NONE; + ASM_cb_result_t cb_res = ASM_CB_RES_NONE; + + mmf_return_val_if_fail((MMHandleType)hcamcorder, ASM_CB_RES_NONE); + + current_state = _mmcamcorder_get_state((MMHandleType)hcamcorder); + + _mmcam_dbg_log("ASM EXCLUSIVE callback : event code 0x%x, command 0x%x, current state %d", + event_src, command, current_state); + + /* set value to inform a status is changed by asm */ + hcamcorder->state_change_by_system = _MMCAMCORDER_STATE_CHANGE_BY_ASM; + + /* set ASM event code for sending it to application */ + hcamcorder->asm_event_code = event_src; + + switch (command) { + case ASM_COMMAND_STOP: + case ASM_COMMAND_PAUSE: + _mmcam_dbg_log("Got msg from asm to Stop or Pause(%d, %d)", command, current_state); + + __mmcamcorder_force_stop(hcamcorder); + cb_res = ASM_CB_RES_STOP; + + _mmcam_dbg_log("Finish opeartion. Camera is released.(%d)", cb_res); + break; + case ASM_COMMAND_PLAY: + _mmcam_dbg_log("Got msg from asm to Play(%d, %d)", command, current_state); + + if (current_state >= MM_CAMCORDER_STATE_PREPARE) { + _mmcam_dbg_log("Already start previewing"); + } else { + __mmcamcorder_force_resume(hcamcorder); } - __mmcamcorder_force_resume(hcamcorder); cb_res = ASM_CB_RES_PLAYING; _mmcam_dbg_log("Finish opeartion. Preview is started.(%d)", cb_res); @@ -2475,21 +2969,6 @@ int _mmcamcorder_create_pipeline(MMHandleType handle, int type) mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED); switch (type) { - case MM_CAMCORDER_MODE_IMAGE: - __ta__(" _mmcamcorder_create_preview_pipeline", - ret = _mmcamcorder_create_preview_pipeline(handle); - ); - if (ret != MM_ERROR_NONE) { - return ret; - } - - __ta__(" _mmcamcorder_add_stillshot_pipeline", - ret = _mmcamcorder_add_stillshot_pipeline(handle); - ); - if (ret != MM_ERROR_NONE) { - return ret; - } - break; case MM_CAMCORDER_MODE_AUDIO: __ta__(" _mmcamcorder_create_audio_pipeline", ret = _mmcamcorder_create_audio_pipeline(handle); @@ -2498,16 +2977,25 @@ int _mmcamcorder_create_pipeline(MMHandleType handle, int type) return ret; } break; - case MM_CAMCORDER_MODE_VIDEO: + case MM_CAMCORDER_MODE_VIDEO_CAPTURE: + default: __ta__(" _mmcamcorder_create_preview_pipeline", ret = _mmcamcorder_create_preview_pipeline(handle); ); if (ret != MM_ERROR_NONE) { return ret; } + + /* connect capture signal */ + if (!sc->bencbin_capture) { + __ta__(" _mmcamcorder_connect_capture_signal", + ret = _mmcamcorder_connect_capture_signal(handle); + ); + if (ret != MM_ERROR_NONE) { + return ret; + } + } break; - default: - return MM_ERROR_CAMCORDER_INTERNAL; } pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; @@ -2521,11 +3009,11 @@ int _mmcamcorder_create_pipeline(MMHandleType handle, int type) } } } - +#ifdef _MMCAMCORDER_GET_DEVICE_INFO if (!_mmcamcorder_get_device_info(handle)) { _mmcam_dbg_err("Getting device information error!!"); } - +#endif _mmcam_dbg_log("ret[%x]", ret); return ret; } @@ -2549,16 +3037,14 @@ void _mmcamcorder_destroy_pipeline(MMHandleType handle, int type) /* Inside each pipeline destroy function, Set GST_STATE_NULL to Main pipeline */ switch (type) { - case MM_CAMCORDER_MODE_IMAGE: - _mmcamcorder_destroy_image_pipeline(handle); + case MM_CAMCORDER_MODE_VIDEO_CAPTURE: + _mmcamcorder_destroy_video_capture_pipeline(handle); break; case MM_CAMCORDER_MODE_AUDIO: _mmcamcorder_destroy_audio_pipeline(handle); break; - case MM_CAMCORDER_MODE_VIDEO: - _mmcamcorder_destroy_video_pipeline(handle); - break; default: + _mmcam_dbg_err("unknown type %d", type); break; } @@ -2612,6 +3098,7 @@ int _mmcamcorder_gst_set_state_async(MMHandleType handle, GstElement *pipeline, } +#ifdef _MMCAMCORDER_USE_SET_ATTR_CB static gboolean __mmcamcorder_set_attr_to_camsensor_cb(gpointer data) { mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data); @@ -2630,6 +3117,7 @@ static gboolean __mmcamcorder_set_attr_to_camsensor_cb(gpointer data) /* once */ return FALSE; } +#endif /* _MMCAMCORDER_USE_SET_ATTR_CB */ int _mmcamcorder_gst_set_state (MMHandleType handle, GstElement *pipeline, GstState target_state) @@ -2638,7 +3126,7 @@ int _mmcamcorder_gst_set_state (MMHandleType handle, GstElement *pipeline, GstSt GstState pipeline_state = GST_STATE_VOID_PENDING; GstStateChangeReturn setChangeReturn = GST_STATE_CHANGE_FAILURE; GstStateChangeReturn getChangeReturn = GST_STATE_CHANGE_FAILURE; - GstClockTime get_timeout = 3 * GST_SECOND; + GstClockTime get_timeout = __MMCAMCORDER_SET_GST_STATE_TIMEOUT * GST_SECOND; mmf_return_val_if_fail(handle, MM_ERROR_CAMCORDER_NOT_INITIALIZED); @@ -2648,6 +3136,8 @@ int _mmcamcorder_gst_set_state (MMHandleType handle, GstElement *pipeline, GstSt for (k = 0; k < _MMCAMCORDER_STATE_SET_COUNT; k++) { setChangeReturn = gst_element_set_state(pipeline, target_state); + _mmcam_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) { @@ -2663,7 +3153,7 @@ int _mmcamcorder_gst_set_state (MMHandleType handle, GstElement *pipeline, GstSt case GST_STATE_CHANGE_ASYNC: _mmcam_dbg_log("status=GST_STATE_CHANGE_ASYNC."); break; - default : + default: _MMCAMCORDER_UNLOCK_GST_STATE(handle); _mmcam_dbg_log("status=GST_STATE_CHANGE_FAILURE."); return MM_ERROR_CAMCORDER_GST_STATECHANGE; @@ -2759,7 +3249,7 @@ static void __mmcamcorder_force_stop(mmf_camcorder_t *hcamcorder) _MMCamcorderImageInfo *info = NULL; mmf_return_if_fail(sc); - mmf_return_if_fail((info = sc->info)); + mmf_return_if_fail((info = sc->info_image)); _mmcam_dbg_log("Stop capturing."); @@ -3069,7 +3559,7 @@ static gboolean __mmcamcorder_handle_gst_error(MMHandleType handle, GstMessage * mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _MMCamcorderMsgItem msg; gchar *msg_src_element; - _MMCamcorderSubContext *sc = NULL; + _MMCamcorderSubContext *sc = NULL; return_val_if_fail(hcamcorder, FALSE); return_val_if_fail(error, FALSE); @@ -3100,7 +3590,7 @@ static gboolean __mmcamcorder_handle_gst_error(MMHandleType handle, GstMessage * } else if (error->domain == GST_STREAM_ERROR) { msg.param.code = __mmcamcorder_gst_handle_stream_error(handle, error->code, message); } else { - debug_warning("This error domain is not defined.\n"); + _mmcam_dbg_warn("This error domain is not defined."); /* we treat system error as an internal error */ msg.param.code = MM_ERROR_CAMCORDER_INTERNAL; @@ -3108,18 +3598,20 @@ static gboolean __mmcamcorder_handle_gst_error(MMHandleType handle, GstMessage * if (message->src) { msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src)); - debug_error("-Msg src : [%s] Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n", - msg_src_element, g_quark_to_string (error->domain), error->message, error->code, msg.param.code); + _mmcam_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 { - debug_error("Domain : [%s] Error : [%s] Code : [%d] is tranlated to error code : [0x%x]\n", - g_quark_to_string (error->domain), error->message, error->code, msg.param.code); + _mmcam_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 _MMCAMCORDER_SKIP_GST_FLOW_ERROR /* Check whether send this error to application */ if (msg.param.code == MM_ERROR_CAMCORDER_GST_FLOW_ERROR) { _mmcam_dbg_log("We got the error. But skip it."); return TRUE; } +#endif /* _MMCAMCORDER_SKIP_GST_FLOW_ERROR */ /* post error to application */ sc->error_occurs = TRUE; @@ -3207,7 +3699,7 @@ static gint __mmcamcorder_gst_handle_resource_error(MMHandleType handle, int cod { mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _MMCamcorderSubContext *sc = NULL; - GstElement *element =NULL; + GstElement *element = NULL; mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); @@ -3217,34 +3709,6 @@ static gint __mmcamcorder_gst_handle_resource_error(MMHandleType handle, int cod _mmcam_dbg_log(""); /* Specific plugin */ - /* video source */ - element = GST_ELEMENT_CAST(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); - if (GST_ELEMENT_CAST(message->src) == element) { - switch (code) { - case GST_RESOURCE_ERROR_BUSY: - _mmcam_dbg_err("Video device [busy]"); - return MM_ERROR_CAMCORDER_DEVICE_BUSY; - case GST_RESOURCE_ERROR_FAILED: - _mmcam_dbg_err("Video device [working failed]."); - return MM_ERROR_CAMCORDER_DEVICE_IO; - case GST_RESOURCE_ERROR_TOO_LAZY: - _mmcam_dbg_err("Video device [timeout]"); - return MM_ERROR_CAMCORDER_DEVICE_TIMEOUT; - case GST_RESOURCE_ERROR_OPEN_READ: - _mmcam_dbg_err("Video device [open failed]"); - return MM_ERROR_CAMCORDER_DEVICE_OPEN; - case GST_RESOURCE_ERROR_SETTINGS: - _mmcam_dbg_err("Video device [Not supported]"); - return MM_ERROR_CAMCORDER_NOT_SUPPORTED; - case GST_RESOURCE_ERROR_NOT_FOUND: - _mmcam_dbg_err("Video device [Register trouble]"); - return MM_ERROR_CAMCORDER_DEVICE_REG_TROUBLE; - default: - _mmcam_dbg_err("Video device [General(%d)]", code); - return MM_ERROR_CAMCORDER_DEVICE; - } - } - /* video sink */ element = GST_ELEMENT_CAST(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst); if (GST_ELEMENT_CAST(message->src) == element) { diff --git a/src/mm_camcorder_platform.c b/src/mm_camcorder_platform.c index 3497ab5..87f8bf8 100644 --- a/src/mm_camcorder_platform.c +++ b/src/mm_camcorder_platform.c @@ -162,29 +162,36 @@ _MMCamcorderEnumConvert _mmcamcorder_enum_conv_ahs = "AntiHandshake" }; -static int __enum_conv_picture_format[MM_PIXEL_FORMAT_NUM]; -_MMCamcorderEnumConvert _mmcamcorder_enum_conv_picture_format = +static int __enum_conv_video_stabilization[MM_CAMCORDER_VIDEO_STABILIZATION_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_video_stabilization = { - MM_PIXEL_FORMAT_NUM, - __enum_conv_picture_format, - CONFIGURE_CATEGORY_CTRL_CAMERA, - "PictureFormat" + MM_CAMCORDER_VIDEO_STABILIZATION_NUM, + __enum_conv_video_stabilization, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + "VideoStabilization" }; -static int __enum_conv_vid_dev[MM_VIDEO_DEVICE_NUM] = + +static int __enum_conv_hdr_capture[MM_CAMCORDER_HDR_CAPTURE_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_hdr_capture = { - //{Enum of (Plugin or Kernel) , Enum of MSL Camcorder} - 2, //MM_VIDEO_DEVICE_CAMERA0 - 1, //MM_VIDEO_DEVICE_CAMERA1 + MM_CAMCORDER_HDR_CAPTURE_NUM, + __enum_conv_hdr_capture, + CONFIGURE_CATEGORY_CTRL_CAPTURE, + "SupportHDR" }; -_MMCamcorderEnumConvert _mmcamcorder_enum_conv_vid_dev = +static int __enum_conv_detect_mode[MM_CAMCORDER_DETECT_MODE_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_detect_mode = { - MM_VIDEO_DEVICE_NUM, - __enum_conv_vid_dev, - 0, - NULL + MM_CAMCORDER_DETECT_MODE_NUM, + __enum_conv_detect_mode, + CONFIGURE_CATEGORY_CTRL_DETECT, + "DetectMode" }; @@ -207,24 +214,24 @@ static _MMCamcorderInfoConverting g_display_info[] = { { CONFIGURE_TYPE_MAIN, CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT, - MM_CAM_DISPLAY_SURFACE, + MM_CAM_DISPLAY_MODE, MM_CAMCORDER_ATTR_NONE, - "Videosink", + "DisplayMode", MM_CAMCONVERT_TYPE_INT_ARRAY, NULL, }, -}; - -static _MMCamcorderInfoConverting g_caminfo_convert[] = { { - CONFIGURE_TYPE_CTRL, - CONFIGURE_CATEGORY_CTRL_CAMERA, - MM_CAM_CAMERA_DEVICE, + CONFIGURE_TYPE_MAIN, + CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT, + MM_CAM_DISPLAY_SURFACE, MM_CAMCORDER_ATTR_NONE, - "InputIndex", + "Videosink", MM_CAMCONVERT_TYPE_INT_ARRAY, - &_mmcamcorder_enum_conv_vid_dev, + NULL, }, +}; + +static _MMCamcorderInfoConverting g_caminfo_convert[CAMINFO_CONVERT_NUM] = { { CONFIGURE_TYPE_CTRL, CONFIGURE_CATEGORY_CTRL_CAMERA, @@ -261,7 +268,7 @@ static _MMCamcorderInfoConverting g_caminfo_convert[] = { MM_CAMCONVERT_TYPE_INT_ARRAY, NULL, }, - { + { /* 5 */ CONFIGURE_TYPE_CTRL, CONFIGURE_CATEGORY_CTRL_CAMERA, MM_CAM_CAMERA_FORMAT, @@ -306,7 +313,7 @@ static _MMCamcorderInfoConverting g_caminfo_convert[] = { MM_CAMCONVERT_TYPE_INT_RANGE, NULL, }, - { + { /* 10 */ CONFIGURE_TYPE_CTRL, CONFIGURE_CATEGORY_CTRL_EFFECT, MM_CAM_FILTER_CONTRAST, @@ -351,7 +358,7 @@ static _MMCamcorderInfoConverting g_caminfo_convert[] = { MM_CAMCONVERT_TYPE_INT_ARRAY, &_mmcamcorder_enum_conv_whitebalance, }, - { + { /* 15 */ CONFIGURE_TYPE_CTRL, CONFIGURE_CATEGORY_CTRL_EFFECT, MM_CAM_FILTER_COLOR_TONE, @@ -396,7 +403,7 @@ static _MMCamcorderInfoConverting g_caminfo_convert[] = { MM_CAMCONVERT_TYPE_INT_ARRAY, &_mmcamcorder_enum_conv_focus_mode, }, - { + { /* 20 */ CONFIGURE_TYPE_CTRL, CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, MM_CAM_CAMERA_AF_SCAN_RANGE, @@ -441,7 +448,7 @@ static _MMCamcorderInfoConverting g_caminfo_convert[] = { MM_CAMCONVERT_TYPE_INT_ARRAY, NULL, }, - { + { /* 25 */ CONFIGURE_TYPE_CTRL, CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, MM_CAM_CAMERA_ISO, @@ -486,7 +493,7 @@ static _MMCamcorderInfoConverting g_caminfo_convert[] = { MM_CAMCONVERT_TYPE_INT_RANGE, NULL, }, - { + { /* 30 */ CONFIGURE_TYPE_CTRL, CONFIGURE_CATEGORY_CTRL_CAPTURE, MM_CAM_CAPTURE_COUNT, @@ -497,12 +504,21 @@ static _MMCamcorderInfoConverting g_caminfo_convert[] = { }, { CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_CAPTURE, + MM_CAM_CAMERA_HDR_CAPTURE, + MM_CAMCORDER_ATTR_NONE, + "SupportHDR", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_hdr_capture, + }, + { + CONFIGURE_TYPE_CTRL, CONFIGURE_CATEGORY_CTRL_DETECT, MM_CAM_DETECT_MODE, MM_CAMCORDER_ATTR_NONE, "DetectMode", MM_CAMCONVERT_TYPE_INT_ARRAY, - NULL, + &_mmcamcorder_enum_conv_detect_mode, }, { CONFIGURE_TYPE_CTRL, @@ -522,7 +538,7 @@ static _MMCamcorderInfoConverting g_caminfo_convert[] = { MM_CAMCONVERT_TYPE_INT_RANGE, NULL, }, - { + { /* 35 */ CONFIGURE_TYPE_CTRL, CONFIGURE_CATEGORY_CTRL_DETECT, MM_CAM_DETECT_SELECT_NUMBER, @@ -540,6 +556,42 @@ static _MMCamcorderInfoConverting g_caminfo_convert[] = { MM_CAMCONVERT_TYPE_INT_ARRAY, NULL, }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_FACE_ZOOM_MODE, + MM_CAMCORDER_ATTR_NONE, + "FaceZoomMode", + MM_CAMCONVERT_TYPE_INT_ARRAY, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_FACE_ZOOM_LEVEL, + MM_CAMCORDER_ATTR_NONE, + "FaceZoomLevel", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_CAMERA, + MM_CAM_RECOMMEND_CAMERA_WIDTH, + MM_CAM_RECOMMEND_CAMERA_HEIGHT, + "RecommendPreviewResolution", + MM_CAMCONVERT_TYPE_INT_PAIR_ARRAY, + NULL, + }, + { /* 40 */ + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_VIDEO_STABILIZATION, + MM_CAMCORDER_ATTR_NONE, + "VideoStabilization", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_video_stabilization, + } }; /*--------------------------------------------------------------------------- @@ -558,16 +610,19 @@ static int __mmcamcorder_get_valid_array(int * original_array, int original_cou | GLOBAL FUNCTION DEFINITIONS: | ---------------------------------------------------------------------------*/ //convert MSL value to sensor value -int _mmcamcorder_convert_msl_to_sensor( int attr_idx, int mslval ) +int _mmcamcorder_convert_msl_to_sensor(MMHandleType handle, int attr_idx, int mslval) { + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _MMCamcorderInfoConverting *info = NULL; int i =0; int size = sizeof(g_caminfo_convert) / sizeof(_MMCamcorderInfoConverting); + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + //_mmcam_dbg_log("attr_idx(%d), mslval(%d)", attr_idx, mslval); - info = g_caminfo_convert; - + info = hcamcorder->caminfo_convert; + for (i = 0; i < size; i++) { if (info[i].attr_idx == attr_idx) @@ -601,18 +656,21 @@ int _mmcamcorder_convert_msl_to_sensor( int attr_idx, int mslval ) } _mmcam_dbg_warn("There is no category to match. Just return the original value."); + return mslval; } //convert sensor value to MSL value -int _mmcamcorder_convert_sensor_to_msl(int attr_idx, int sensval) +int _mmcamcorder_convert_sensor_to_msl(MMHandleType handle, int attr_idx, int sensval) { + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderInfoConverting *info = NULL; int i = 0, j = 0; int size = sizeof(g_caminfo_convert) / sizeof(_MMCamcorderInfoConverting); - - _MMCamcorderInfoConverting *info = NULL; - info = g_caminfo_convert; + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + info = hcamcorder->caminfo_convert; for( i = 0 ; i < size ; i++ ) { @@ -697,15 +755,18 @@ __mmcamcorder_get_valid_array(int * original_array, int original_count, int ** v int _mmcamcorder_init_attr_from_configure(MMHandleType handle) { - _MMCamcorderInfoConverting *info = NULL; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderInfoConverting *info = NULL; int table_size = 0; int ret = MM_ERROR_NONE; + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + _mmcam_dbg_log(""); /* Initialize attribute related to camera control */ - info = g_caminfo_convert; + info = hcamcorder->caminfo_convert; table_size = sizeof(g_caminfo_convert) / sizeof(_MMCamcorderInfoConverting); ret = __mmcamcorder_set_info_to_attr( handle, info, table_size ); if( ret != MM_ERROR_NONE ) @@ -814,8 +875,8 @@ __mmcamcorder_set_info_to_attr( MMHandleType handle, _MMCamcorderInfoConverting info[i].main_key, info[i].sub_key1, iarray, iarray_size, idefault); */ - mmf_attrs_set_valid_type (attrs, info[i].attr_idx, MM_ATTRS_VALID_TYPE_INT_ARRAY); - mmf_attrs_set_valid_array (attrs, info[i].attr_idx, iarray, iarray_size); + mmf_attrs_set_valid_type(attrs, info[i].attr_idx, MM_ATTRS_VALID_TYPE_INT_ARRAY); + mmf_attrs_set_valid_array(attrs, info[i].attr_idx, iarray, iarray_size, idefault); } ret = mm_attrs_set_int(MMF_CAMCORDER_ATTRS(hcamcorder), info[i].attr_idx, idefault); @@ -841,7 +902,7 @@ __mmcamcorder_set_info_to_attr( MMHandleType handle, _MMCamcorderInfoConverting //_mmcam_dbg_log("INT Range. m:%d, s:%d, min=%d, max=%d", info[i].main_key, info[i].sub_key1, irange->min, irange->max); mmf_attrs_set_valid_type (attrs, info[i].attr_idx, MM_ATTRS_VALID_TYPE_INT_RANGE); - mmf_attrs_set_valid_range(attrs, info[i].attr_idx, irange->min, irange->max); + mmf_attrs_set_valid_range(attrs, info[i].attr_idx, irange->min, irange->max, irange->default_value); ret = mm_attrs_set_int(MMF_CAMCORDER_ATTRS(hcamcorder), info[i].attr_idx, irange->default_value); } @@ -883,10 +944,16 @@ __mmcamcorder_set_info_to_attr( MMHandleType handle, _MMCamcorderInfoConverting if( pair_array && pair_array->count > 0 ) { - mmf_attrs_set_valid_type (attrs, info[i].attr_idx, MM_ATTRS_VALID_TYPE_INT_ARRAY); - mmf_attrs_set_valid_array (attrs, info[i].attr_idx, pair_array->value[0], pair_array->count); - mmf_attrs_set_valid_type (attrs, info[i].attr_idx_pair, MM_ATTRS_VALID_TYPE_INT_ARRAY); - mmf_attrs_set_valid_array (attrs, info[i].attr_idx_pair, pair_array->value[1], pair_array->count); + mmf_attrs_set_valid_type(attrs, info[i].attr_idx, MM_ATTRS_VALID_TYPE_INT_ARRAY); + mmf_attrs_set_valid_array(attrs, info[i].attr_idx, + pair_array->value[0], + pair_array->count, + pair_array->default_value[0]); + mmf_attrs_set_valid_type(attrs, info[i].attr_idx_pair, MM_ATTRS_VALID_TYPE_INT_ARRAY); + mmf_attrs_set_valid_array(attrs, info[i].attr_idx_pair, + pair_array->value[1], + pair_array->count, + pair_array->default_value[1]); mm_attrs_set_int(MMF_CAMCORDER_ATTRS(hcamcorder), info[i].attr_idx, pair_array->default_value[0]); mm_attrs_set_int(MMF_CAMCORDER_ATTRS(hcamcorder), info[i].attr_idx_pair, pair_array->default_value[1]); @@ -933,22 +1000,81 @@ int _mmcamcorder_set_converted_value(MMHandleType handle, _MMCamcorderEnumConver int _mmcamcorder_init_convert_table(MMHandleType handle) { - mmf_return_val_if_fail(handle, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - - _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_whitebalance); - _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_colortone); - _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_iso); - _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_prgrm); - _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_focus_mode); - _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_focus_type); - _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_ae_type); -// _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_pcolor_mode); -// _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_flip); -// _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_pcolor); - _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_strobe_mode); - _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_wdr_ctrl); - _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_ahs); -// _mmcamcorder_set_converted_value(handle, &_mmcamcorder_enum_conv_picture_format); + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + int enum_conv_size = sizeof(_MMCamcorderEnumConvert); + int caminfo_conv_size = sizeof(g_caminfo_convert); + int caminfo_conv_length = sizeof(g_caminfo_convert) / sizeof(_MMCamcorderInfoConverting); + int i = 0; + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + /* copy default conv data into memory of handle */ + memcpy(&(hcamcorder->caminfo_convert), &g_caminfo_convert, caminfo_conv_size); + memcpy(&(hcamcorder->enum_conv[ENUM_CONVERT_WHITE_BALANCE]), &_mmcamcorder_enum_conv_whitebalance, enum_conv_size); + memcpy(&(hcamcorder->enum_conv[ENUM_CONVERT_COLOR_TONE]), &_mmcamcorder_enum_conv_colortone, enum_conv_size); + memcpy(&(hcamcorder->enum_conv[ENUM_CONVERT_ISO]), &_mmcamcorder_enum_conv_iso, enum_conv_size); + memcpy(&(hcamcorder->enum_conv[ENUM_CONVERT_PROGRAM_MODE]), &_mmcamcorder_enum_conv_prgrm, enum_conv_size); + memcpy(&(hcamcorder->enum_conv[ENUM_CONVERT_FOCUS_MODE]), &_mmcamcorder_enum_conv_focus_mode, enum_conv_size); + memcpy(&(hcamcorder->enum_conv[ENUM_CONVERT_AF_RANGE]), &_mmcamcorder_enum_conv_focus_type, enum_conv_size); + memcpy(&(hcamcorder->enum_conv[ENUM_CONVERT_EXPOSURE_MODE]), &_mmcamcorder_enum_conv_ae_type, enum_conv_size); + memcpy(&(hcamcorder->enum_conv[ENUM_CONVERT_STROBE_MODE]), &_mmcamcorder_enum_conv_strobe_mode, enum_conv_size); + memcpy(&(hcamcorder->enum_conv[ENUM_CONVERT_WDR]), &_mmcamcorder_enum_conv_wdr_ctrl, enum_conv_size); + memcpy(&(hcamcorder->enum_conv[ENUM_CONVERT_ANTI_HAND_SHAKE]), &_mmcamcorder_enum_conv_ahs, enum_conv_size); + memcpy(&(hcamcorder->enum_conv[ENUM_CONVERT_VIDEO_STABILIZATION]), &_mmcamcorder_enum_conv_video_stabilization, enum_conv_size); + + /* set ini info to conv data */ + _mmcamcorder_set_converted_value(handle, &(hcamcorder->enum_conv[ENUM_CONVERT_WHITE_BALANCE])); + _mmcamcorder_set_converted_value(handle, &(hcamcorder->enum_conv[ENUM_CONVERT_COLOR_TONE])); + _mmcamcorder_set_converted_value(handle, &(hcamcorder->enum_conv[ENUM_CONVERT_ISO])); + _mmcamcorder_set_converted_value(handle, &(hcamcorder->enum_conv[ENUM_CONVERT_PROGRAM_MODE])); + _mmcamcorder_set_converted_value(handle, &(hcamcorder->enum_conv[ENUM_CONVERT_FOCUS_MODE])); + _mmcamcorder_set_converted_value(handle, &(hcamcorder->enum_conv[ENUM_CONVERT_AF_RANGE])); + _mmcamcorder_set_converted_value(handle, &(hcamcorder->enum_conv[ENUM_CONVERT_EXPOSURE_MODE])); + _mmcamcorder_set_converted_value(handle, &(hcamcorder->enum_conv[ENUM_CONVERT_STROBE_MODE])); + _mmcamcorder_set_converted_value(handle, &(hcamcorder->enum_conv[ENUM_CONVERT_WDR])); + _mmcamcorder_set_converted_value(handle, &(hcamcorder->enum_conv[ENUM_CONVERT_ANTI_HAND_SHAKE])); + _mmcamcorder_set_converted_value(handle, &(hcamcorder->enum_conv[ENUM_CONVERT_VIDEO_STABILIZATION])); + + /* set modified conv data to handle */ + for (i = 0 ; i < caminfo_conv_length ; i++) { + if (hcamcorder->caminfo_convert[i].type == CONFIGURE_TYPE_CTRL) { + switch (hcamcorder->caminfo_convert[i].category) { + case CONFIGURE_CATEGORY_CTRL_STROBE: + if (!strcmp(hcamcorder->caminfo_convert[i].keyword, "StrobeMode")) { + hcamcorder->caminfo_convert[i].enum_convert = &(hcamcorder->enum_conv[ENUM_CONVERT_STROBE_MODE]); + } + break; + case CONFIGURE_CATEGORY_CTRL_EFFECT: + if (!strcmp(hcamcorder->caminfo_convert[i].keyword, "WhiteBalance")) { + hcamcorder->caminfo_convert[i].enum_convert = &(hcamcorder->enum_conv[ENUM_CONVERT_WHITE_BALANCE]); + } else if (!strcmp(hcamcorder->caminfo_convert[i].keyword, "ColorTone")) { + hcamcorder->caminfo_convert[i].enum_convert = &(hcamcorder->enum_conv[ENUM_CONVERT_COLOR_TONE]); + } else if (!strcmp(hcamcorder->caminfo_convert[i].keyword, "WDR")) { + hcamcorder->caminfo_convert[i].enum_convert = &(hcamcorder->enum_conv[ENUM_CONVERT_WDR]); + } + break; + case CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH: + if (!strcmp(hcamcorder->caminfo_convert[i].keyword, "FocusMode")) { + hcamcorder->caminfo_convert[i].enum_convert = &(hcamcorder->enum_conv[ENUM_CONVERT_FOCUS_MODE]); + } else if (!strcmp(hcamcorder->caminfo_convert[i].keyword, "AFType")) { + hcamcorder->caminfo_convert[i].enum_convert = &(hcamcorder->enum_conv[ENUM_CONVERT_AF_RANGE]); + } else if (!strcmp(hcamcorder->caminfo_convert[i].keyword, "AEType")) { + hcamcorder->caminfo_convert[i].enum_convert = &(hcamcorder->enum_conv[ENUM_CONVERT_EXPOSURE_MODE]); + } else if (!strcmp(hcamcorder->caminfo_convert[i].keyword, "ISO")) { + hcamcorder->caminfo_convert[i].enum_convert = &(hcamcorder->enum_conv[ENUM_CONVERT_ISO]); + } else if (!strcmp(hcamcorder->caminfo_convert[i].keyword, "ProgramMode")) { + hcamcorder->caminfo_convert[i].enum_convert = &(hcamcorder->enum_conv[ENUM_CONVERT_PROGRAM_MODE]); + } else if (!strcmp(hcamcorder->caminfo_convert[i].keyword, "AntiHandshake")) { + hcamcorder->caminfo_convert[i].enum_convert = &(hcamcorder->enum_conv[ENUM_CONVERT_ANTI_HAND_SHAKE]); + } else if (!strcmp(hcamcorder->caminfo_convert[i].keyword, "VideoStabilization")) { + hcamcorder->caminfo_convert[i].enum_convert = &(hcamcorder->enum_conv[ENUM_CONVERT_VIDEO_STABILIZATION]); + } + break; + default: + break; + } + } + } return MM_ERROR_NONE; } diff --git a/src/mm_camcorder_sound.c b/src/mm_camcorder_sound.c index c582349..28dc21f 100644 --- a/src/mm_camcorder_sound.c +++ b/src/mm_camcorder_sound.c @@ -24,6 +24,7 @@ =======================================================================================*/ #include #include +#include #include #include "mm_camcorder_internal.h" #include "mm_camcorder_sound.h" @@ -35,312 +36,464 @@ /*--------------------------------------------------------------------------------------- | LOCAL VARIABLE DEFINITIONS for internal | ---------------------------------------------------------------------------------------*/ -#define BLOCK_SIZE 2048 +#define SAMPLE_SOUND_NAME "camera-shutter" +#define SAMPLE_SOUND_RATE 44100 +#define DEFAULT_ACTIVE_DEVICE -1 + +enum { + SOUND_DEVICE_TYPE_SPEAKER, /* AVSYS_AUDIO_LVOL_DEV_TYPE_SPK */ + SOUND_DEVICE_TYPE_HEADSET, /* AVSYS_AUDIO_LVOL_DEV_TYPE_HEADSET */ + SOUND_DEVICE_TYPE_BTHEADSET, /* AVSYS_AUDIO_LVOL_DEV_TYPE_BTHEADSET */ + SOUND_DEVICE_TYPE_NUM /* AVSYS_AUDIO_LVOL_DEV_TYPE_MAX */ +}; /*--------------------------------------------------------------------------------------- | LOCAL FUNCTION PROTOTYPES: | ---------------------------------------------------------------------------------------*/ -static gboolean __prepare_buffer(SOUND_INFO *info, char *filename); -static gboolean __cleanup_buffer(SOUND_INFO *info); -static void *__sound_open_thread_func(void *data); -static void *__sound_write_thread_func(void *data); static void __solo_sound_callback(void *data); -static gboolean __prepare_buffer(SOUND_INFO *info, char *filename) + +static void __pulseaudio_context_state_cb(pa_context *pulse_context, void *user_data) { - mmf_return_val_if_fail(info, FALSE); - mmf_return_val_if_fail(filename, FALSE); + int state = 0; + SOUND_INFO *info = NULL; - info->infile = sf_open(filename, SFM_READ, &info->sfinfo); - if (!(info->infile)) { - _mmcam_dbg_err("failed to open file [%s]", filename); - return FALSE; - } + mmf_return_if_fail(user_data); - _mmcam_dbg_log("SOUND: frame = %lld", info->sfinfo.frames); - _mmcam_dbg_log("SOUND: sameplerate = %d", info->sfinfo.samplerate); - _mmcam_dbg_log("SOUND: channel = %d", info->sfinfo.channels); - _mmcam_dbg_log("SOUND: format = 0x%x", info->sfinfo.format); - - info->pcm_size = info->sfinfo.frames * info->sfinfo.channels * 2; - info->pcm_buf = (short *)malloc(info->pcm_size); - if (info->pcm_buf == NULL) { - _mmcam_dbg_err("pcm_buf malloc failed"); - sf_close(info->infile); - info->infile = NULL; - return FALSE; + info = (SOUND_INFO *)user_data; + + state = pa_context_get_state(pulse_context); + switch (state) { + case PA_CONTEXT_READY: + _mmcam_dbg_log("pulseaudio context READY"); + if (info->pulse_context == pulse_context) { + /* Signal */ + _mmcam_dbg_log("pulseaudio send signal"); + pa_threaded_mainloop_signal(info->pulse_mainloop, 0); + } + break; + case PA_CONTEXT_TERMINATED: + if (info->pulse_context == pulse_context) { + /* Signal */ + _mmcam_dbg_log("Context terminated : pulseaudio send signal"); + pa_threaded_mainloop_signal(info->pulse_mainloop, 0); + } + break; + case PA_CONTEXT_UNCONNECTED: + case PA_CONTEXT_CONNECTING: + case PA_CONTEXT_AUTHORIZING: + case PA_CONTEXT_SETTING_NAME: + case PA_CONTEXT_FAILED: + default: + _mmcam_dbg_log("pulseaudio context %p, state %d", + pulse_context, state); + break; } - sf_read_short(info->infile, info->pcm_buf, info->pcm_size); - return TRUE; + return; } - -static gboolean __cleanup_buffer(SOUND_INFO *info) +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE +static void __pulseaudio_stream_write_cb(pa_stream *stream, size_t length, void *user_data) { - mmf_return_val_if_fail(info, FALSE); + sf_count_t read_length; + short *data; + SOUND_INFO *info = NULL; - if (info->infile) { - sf_close(info->infile); - info->infile = NULL; - } + mmf_return_if_fail(user_data); + + info = (SOUND_INFO *)user_data; + + _mmcam_dbg_log("START"); - if (info->pcm_buf) { - free(info->pcm_buf); - info->pcm_buf = NULL; + data = pa_xmalloc(length); + + read_length = (sf_count_t)(length/pa_frame_size(&(info->sample_spec))); + + if ((sf_readf_short(info->infile, data, read_length)) != read_length) { + pa_xfree(data); + return; } - _mmcam_dbg_log("Done"); + pa_stream_write(stream, data, length, pa_xfree, 0, PA_SEEK_RELATIVE); - return TRUE; + info->sample_length -= length; + + if (info->sample_length <= 0) { + pa_stream_set_write_callback(info->sample_stream, NULL, NULL); + pa_stream_finish_upload(info->sample_stream); + + pa_threaded_mainloop_signal(info->pulse_mainloop, 0); + _mmcam_dbg_log("send signal DONE"); + } + + _mmcam_dbg_log("DONE read_length %d", read_length); } -static void *__sound_open_thread_func(void *data) +static void __pulseaudio_remove_sample_finish_cb(pa_context *pulse_context, int success, void *user_data) +{ + SOUND_INFO *info = NULL; + + mmf_return_if_fail(user_data); + + info = (SOUND_INFO *)user_data; + + _mmcam_dbg_log("START"); + + pa_threaded_mainloop_signal(info->pulse_mainloop, 0); + + _mmcam_dbg_log("DONE"); +} +#endif /* _MMCAMCORDER_UPLOAD_SAMPLE */ + +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE +gboolean _mmcamcorder_sound_init(MMHandleType handle, char *filename) +#else /* _MMCAMCORDER_UPLOAD_SAMPLE */ +gboolean _mmcamcorder_sound_init(MMHandleType handle) +#endif /* _MMCAMCORDER_UPLOAD_SAMPLE */ { int ret = 0; - system_audio_route_t route = SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY; + int sound_enable = TRUE; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); SOUND_INFO *info = NULL; - mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data); + mm_sound_device_in device_in; + mm_sound_device_out device_out; + pa_mainloop_api *api = NULL; - mmf_return_val_if_fail(hcamcorder, NULL); + mmf_return_val_if_fail(hcamcorder, FALSE); - MMTA_ACUM_ITEM_BEGIN(" __sound_open_thread_func", FALSE); + /* check sound play enable */ + ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL, + "capture-sound-enable", &sound_enable, + NULL); + _mmcam_dbg_log("Capture sound enable %d", sound_enable); + if (!sound_enable) { + return TRUE; + } info = &(hcamcorder->snd_info); - __ta__(" __prepare_buffer", - ret = __prepare_buffer(info, info->filename); - ); - if (ret == FALSE) { - goto EXIT_FUNC; + pthread_mutex_lock(&(info->open_mutex)); + + if (info->state > _MMCAMCORDER_SOUND_STATE_NONE) { + _mmcam_dbg_warn("already initialized [%d]", info->state); + pthread_mutex_unlock(&(info->open_mutex)); + return TRUE; } - __ta__(" mm_sound_pcm_play_open", - ret = mm_sound_pcm_play_open_ex(&(info->handle), info->sfinfo.samplerate, - (info->sfinfo.channels == 1) ? MMSOUND_PCM_MONO : MMSOUND_PCM_STEREO, - MMSOUND_PCM_S16_LE, VOLUME_TYPE_FIXED, ASM_EVENT_EXCLUSIVE_MMSOUND); - ); - if (ret < 0) { - /* error */ - _mmcam_dbg_err("mm_sound_pcm_play_open failed [%x]", ret); - __cleanup_buffer(info); - goto EXIT_FUNC; - } else { - /* success */ - info->state = _MMCAMCORDER_SOUND_STATE_PREPARE; - _mmcam_dbg_log("mm_sound_pcm_play_open succeeded. state [%d]", info->state); +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE + if (info->filename) { + free(info->filename); + info->filename = NULL; } - ret = mm_sound_route_get_system_policy(&route); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_err("mm_sound_route_get_system_policy failed [%x]", ret); - goto POLICY_ERROR; + info->filename = strdup(filename); + if (info->filename == NULL) { + _mmcam_dbg_err("strdup failed"); + return FALSE; } +#endif /* _MMCAMCORDER_UPLOAD_SAMPLE */ - _mmcam_dbg_log("current policy [%d]", route); + pthread_mutex_init(&(info->play_mutex), NULL); + pthread_cond_init(&(info->play_cond), NULL); - if (route != SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY) { - ret = mm_sound_route_set_system_policy(SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_err("mm_sound_route_set_system_policy failed [%x]", ret); - goto POLICY_ERROR; +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE + /* read sample */ + memset (&(info->sfinfo), 0, sizeof(SF_INFO)); + info->infile = sf_open(info->filename, SFM_READ, &(info->sfinfo)); + if (!(info->infile)) { + _mmcam_dbg_err("Failed to open sound file"); + goto SOUND_INIT_ERROR; + } +#endif /* _MMCAMCORDER_UPLOAD_SAMPLE */ + + if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON) { + int errorcode; + ASM_resource_t mm_resource = mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY | ASM_RESOURCE_HW_ENCODER; + + /* set EXCLUSIVE session as PLAYING to pause other session */ + if (!ASM_set_sound_state(hcamcorder->asm_handle_ex, ASM_EVENT_EXCLUSIVE_MMCAMCORDER, + ASM_STATE_PLAYING, mm_resource, &errorcode)) { + _mmcam_dbg_err("Set state to playing failed 0x%x", errorcode); + ret = MM_ERROR_POLICY_BLOCKED; + goto SOUND_INIT_ERROR; } - info->route_policy_backup = route; + _mmcam_dbg_log("EXCLUSIVE session PLAYING done."); + } else { + _mmcam_dbg_log("do not register session to pause another playing session"); } -EXIT_FUNC: - pthread_cond_signal(&(info->open_cond)); - pthread_mutex_unlock(&(info->open_mutex)); + /** + * Init Pulseaudio thread + */ + /* create pulseaudio mainloop */ + info->pulse_mainloop = pa_threaded_mainloop_new(); + ret = pa_threaded_mainloop_start(info->pulse_mainloop); + + /* lock pulseaudio thread */ + pa_threaded_mainloop_lock(info->pulse_mainloop); + /* get pulseaudio api */ + api = pa_threaded_mainloop_get_api(info->pulse_mainloop); + /* create pulseaudio context */ + info->pulse_context = pa_context_new(api, NULL); + /* set pulseaudio context callback */ + pa_context_set_state_callback(info->pulse_context, __pulseaudio_context_state_cb, info); + + if (pa_context_connect(info->pulse_context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) { + _mmcam_dbg_err("pa_context_connect error"); + } - _mmcam_dbg_log("Done"); + /* wait READY state of pulse context */ + while (TRUE) { + pa_context_state_t state = pa_context_get_state(info->pulse_context); - MMTA_ACUM_ITEM_END(" __sound_open_thread_func", FALSE); + _mmcam_dbg_log("pa context state is now %d", state); - return NULL; + if (!PA_CONTEXT_IS_GOOD (state)) { + _mmcam_dbg_log("connection failed"); + break; + } -POLICY_ERROR: - pthread_mutex_unlock(&(info->open_mutex)); - _mmcamcorder_sound_finalize((MMHandleType)hcamcorder); + if (state == PA_CONTEXT_READY) { + _mmcam_dbg_log("pa context READY"); + break; + } - return NULL; -} + /* Wait until the context is ready */ + _mmcam_dbg_log("waiting.................."); + pa_threaded_mainloop_wait(info->pulse_mainloop); + _mmcam_dbg_log("waiting DONE. check again..."); + } + /* unlock pulseaudio thread */ + pa_threaded_mainloop_unlock(info->pulse_mainloop); -static void *__sound_write_thread_func(void *data) -{ - int ret = 0; - int bytes_to_write = 0; - int remain_bytes = 0; - system_audio_route_t route = SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY; - char *buffer_to_write = NULL; - SOUND_INFO *info = NULL; - mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data); +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE + /** + * Upload sample + */ + if (pa_sndfile_read_sample_spec(info->infile, &(info->sample_spec)) < 0) { + _mmcam_dbg_err("Failed to determine sample specification from file"); + goto SOUND_INIT_ERROR; + } - mmf_return_val_if_fail(hcamcorder, NULL); + info->sample_spec.format = PA_SAMPLE_S16LE; - info = &(hcamcorder->snd_info); + if (pa_sndfile_read_channel_map(info->infile, &(info->channel_map)) < 0) { + pa_channel_map_init_extend(&(info->channel_map), info->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); - _mmcam_dbg_log("RUN sound write thread"); + if (info->sample_spec.channels > 2) { + _mmcam_dbg_warn("Failed to determine sample specification from file"); + } + } - pthread_mutex_lock(&(info->play_mutex)); + info->sample_length = (size_t)info->sfinfo.frames * pa_frame_size(&(info->sample_spec)); - do { - pthread_cond_wait(&(info->play_cond), &(info->play_mutex)); + pa_threaded_mainloop_lock(info->pulse_mainloop); - _mmcam_dbg_log("Signal received. Play sound."); + /* prepare uploading */ + info->sample_stream = pa_stream_new(info->pulse_context, SAMPLE_SOUND_NAME, &(info->sample_spec), NULL); + /* set stream write callback */ + pa_stream_set_write_callback(info->sample_stream, __pulseaudio_stream_write_cb, info); + /* upload sample (ASYNC) */ + pa_stream_connect_upload(info->sample_stream, info->sample_length); + /* wait for upload completion */ + pa_threaded_mainloop_wait(info->pulse_mainloop); - if (info->thread_run == FALSE) { - _mmcam_dbg_log("Exit thread command is detected"); - break; - } + pa_threaded_mainloop_unlock (info->pulse_mainloop); - ret = mm_sound_route_get_system_policy(&route); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_err("get_system_policy failed [%x]. skip sound play.", ret); - break; - } - - _mmcam_dbg_log("current policy [%d]", route); + /* close sndfile */ + sf_close(info->infile); + info->infile = NULL; +#endif /* _MMCAMCORDER_UPLOAD_SAMPLE */ - if (route != SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY) { - ret = mm_sound_route_set_system_policy(SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_err("set_system_policy failed. skip sound play."); - break; - } + if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON) { + /* backup current route */ + info->active_out_backup = DEFAULT_ACTIVE_DEVICE; - info->route_policy_backup = route; + __ta__(" mm_sound_get_active_device", + ret = mm_sound_get_active_device(&device_in, &device_out); + ); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("mm_sound_get_active_device failed [%x]. skip sound play.", ret); + goto SOUND_INIT_ERROR; } - buffer_to_write = (char *)info->pcm_buf; - remain_bytes = info->pcm_size; - bytes_to_write = 0; + _mmcam_dbg_log("current out [%x]", device_out); - while (remain_bytes) { - bytes_to_write = (remain_bytes >= BLOCK_SIZE) ? BLOCK_SIZE : remain_bytes; - ret = mm_sound_pcm_play_write(info->handle, buffer_to_write, bytes_to_write); - if (ret != bytes_to_write) { - _mmcam_dbg_err("pcm write error [%x]", ret); + if (device_out != MM_SOUND_DEVICE_OUT_SPEAKER) { + ret = mm_sound_set_active_route (MM_SOUND_ROUTE_OUT_SPEAKER); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("mm_sound_set_active_route failed [%x]. skip sound play.", ret); + goto SOUND_INIT_ERROR; } - remain_bytes -= bytes_to_write; - buffer_to_write += bytes_to_write; + info->active_out_backup = device_out; } - } while (TRUE); - - pthread_mutex_unlock(&(info->play_mutex)); - - _mmcam_dbg_log("END sound write thread"); - - return NULL; -} + } + info->state = _MMCAMCORDER_SOUND_STATE_INIT; -gboolean _mmcamcorder_sound_init(MMHandleType handle, char *filename) -{ - int ret = 0; - mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); - SOUND_INFO *info = NULL; - - mmf_return_val_if_fail(hcamcorder, FALSE); + _mmcam_dbg_log("init DONE"); - info = &(hcamcorder->snd_info); + pthread_mutex_unlock(&(info->open_mutex)); - pthread_mutex_lock(&(info->open_mutex)); + return TRUE; - if (info->state > _MMCAMCORDER_SOUND_STATE_NONE) { - _mmcam_dbg_warn("already initialized [%d]", info->state); - pthread_mutex_unlock(&(info->open_mutex)); - return FALSE; - } +SOUND_INIT_ERROR: +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE + /** + * Release allocated resources + */ if (info->filename) { free(info->filename); info->filename = NULL; } +#endif /* _MMCAMCORDER_UPLOAD_SAMPLE */ + + /* remove pulse mainloop */ + if (info->pulse_mainloop) { + /* remove pulse context */ + if (info->pulse_context) { +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE + /* remove uploaded sample */ + if (info->sample_stream) { + pa_threaded_mainloop_lock(info->pulse_mainloop); + + /* Remove sample (ASYNC) */ + pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info)); + + /* Wait for async operation */ + pa_threaded_mainloop_wait(info->pulse_mainloop); + } +#endif /* _MMCAMCORDER_UPLOAD_SAMPLE */ - info->filename = strdup(filename); - if (info->filename == NULL) { - _mmcam_dbg_err("strdup failed"); - ret = FALSE; - } else { - pthread_mutex_init(&(info->play_mutex), NULL); - pthread_cond_init(&(info->play_cond), NULL); - if (pthread_create(&(info->thread), NULL, __sound_write_thread_func, (void *)handle) == 0) { - info->thread_run = TRUE; - info->state = _MMCAMCORDER_SOUND_STATE_INIT; - info->route_policy_backup = -1; - _mmcam_dbg_log("write thread created"); - ret = TRUE; - } else { - _mmcam_dbg_err("failed to create write thread"); - free(info->filename); - info->filename = NULL; - ret = FALSE; + /* Make sure we don't get any further callbacks */ + pa_context_set_state_callback(info->pulse_context, NULL, NULL); + + pa_context_disconnect(info->pulse_context); + pa_context_unref(info->pulse_context); + info->pulse_context = NULL; } + + pa_threaded_mainloop_stop(info->pulse_mainloop); + pa_threaded_mainloop_free(info->pulse_mainloop); + info->pulse_mainloop = NULL; } + /* remove mutex and cond */ + pthread_mutex_destroy(&(info->play_mutex)); + pthread_cond_destroy(&(info->play_cond)); + pthread_mutex_unlock(&(info->open_mutex)); - return ret; + return FALSE; } -gboolean _mmcamcorder_sound_prepare(MMHandleType handle) +gboolean _mmcamcorder_sound_play(MMHandleType handle) { - int ret = FALSE; - pthread_t open_thread; + int ret = 0; + int sound_enable = TRUE; + int volume_type = AVSYS_AUDIO_VOLUME_TYPE_FIXED; + int device_type = SOUND_DEVICE_TYPE_SPEAKER; + int left_volume = 0, right_volume = 0; + float left_gain = 1.0f, right_gain = 1.0f; + int set_volume = 0; + int max_level = 0; + unsigned int volume_level; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); SOUND_INFO *info = NULL; + pa_operation *pulse_op = NULL; mmf_return_val_if_fail(hcamcorder, FALSE); + /* check sound play enable */ + ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL, + "capture-sound-enable", &sound_enable, + NULL); + _mmcam_dbg_log("Capture sound enable %d", sound_enable); + if (!sound_enable) { + return TRUE; + } + info = &(hcamcorder->snd_info); pthread_mutex_lock(&(info->open_mutex)); - if (info->state == _MMCAMCORDER_SOUND_STATE_INIT) { - if (pthread_create(&open_thread, NULL, __sound_open_thread_func, (void *)handle) == 0) { - _mmcam_dbg_log("open thread created"); - ret = TRUE; - } else { - _mmcam_dbg_err("failed to create open thread"); - ret = FALSE; - pthread_mutex_unlock(&(info->open_mutex)); - } - } else { - _mmcam_dbg_warn("Wrong state [%d]", info->state); - ret = FALSE; + if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) { + _mmcam_dbg_log("not initialized state:[%d]", info->state); pthread_mutex_unlock(&(info->open_mutex)); + return FALSE; } - return ret; -} + /* get volume level and set volume */ + if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_OFF) { + gboolean sound_status = hcamcorder->sub_context->info_image->sound_status; + mm_sound_device_in device_in = MM_SOUND_DEVICE_IN_NONE; + mm_sound_device_out device_out = MM_SOUND_DEVICE_OUT_NONE; + volume_type = AVSYS_AUDIO_VOLUME_TYPE_MEDIA; + avsys_audio_get_volume_max_ex(volume_type, &max_level); -gboolean _mmcamcorder_sound_play(MMHandleType handle) -{ - mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); - SOUND_INFO *info = NULL; + /* get sound path */ + __ta__(" mm_sound_get_active_device", + mm_sound_get_active_device(&device_in, &device_out); + ); - mmf_return_val_if_fail(hcamcorder, FALSE); + _mmcam_dbg_log("sound status %d, device out %x", sound_status, device_out); - info = &(hcamcorder->snd_info); + if (device_out == MM_SOUND_DEVICE_OUT_WIRED_ACCESSORY) { + device_type = SOUND_DEVICE_TYPE_HEADSET; + } else if (device_out == MM_SOUND_DEVICE_OUT_BT_A2DP) { + device_type = SOUND_DEVICE_TYPE_BTHEADSET; + } - pthread_mutex_lock(&(info->open_mutex)); + if (sound_status || device_out != MM_SOUND_DEVICE_OUT_SPEAKER) { + volume_level = hcamcorder->sub_context->info_image->volume_level; + _mmcam_dbg_log("current volume level %d", volume_level); + } else { + volume_level = 0; + _mmcam_dbg_log("current state is SILENT mode and SPEAKER output"); + } - if (info->state < _MMCAMCORDER_SOUND_STATE_PREPARE) { - _mmcam_dbg_log("not initialized state:[%d]", info->state); - pthread_mutex_unlock(&(info->open_mutex)); - return FALSE; + if (volume_level > (unsigned int)max_level) { + _mmcam_dbg_warn("invalid volume level. set max"); + volume_level = (unsigned int)max_level; + } + } else { + avsys_audio_get_volume_max_ex(volume_type, &max_level); + volume_level = (unsigned int)max_level; } + avsys_audio_get_volume_table(volume_type, device_type, (int)volume_level, &left_volume, &right_volume); + avsys_audio_get_volume_gain_table( + AVSYS_AUDIO_VOLUME_GAIN_IDX(AVSYS_AUDIO_VOLUME_GAIN_SHUTTER2), + device_type, &left_gain, &right_gain); + set_volume = left_volume * left_gain; + _mmcam_dbg_log("volume type %d, device type %d, volume level %d, left volume %d left gain %.2f set_volume %d", + volume_type, device_type, volume_level, left_volume, left_gain, set_volume); + + _mmcam_dbg_log("shutter sound policy %d, volume %d", + hcamcorder->shutter_sound_policy, set_volume); + _mmcam_dbg_log("Play start"); - pthread_mutex_lock(&(info->play_mutex)); - pthread_cond_signal(&(info->play_cond)); - pthread_mutex_unlock(&(info->play_mutex)); + __ta__(" pa_context_play_sample", + pulse_op = pa_context_play_sample(info->pulse_context, + SAMPLE_SOUND_NAME, + NULL, + set_volume, + NULL, + NULL); + ); + if (pulse_op) { + pa_operation_unref(pulse_op); + pulse_op = NULL; + } pthread_mutex_unlock(&(info->open_mutex)); @@ -354,80 +507,153 @@ gboolean _mmcamcorder_sound_finalize(MMHandleType handle) { mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); SOUND_INFO *info = NULL; + mm_sound_device_in device_in; + mm_sound_device_out device_out; + int ret = 0; mmf_return_val_if_fail(hcamcorder, FALSE); info = &(hcamcorder->snd_info); + _mmcam_dbg_err("START"); + pthread_mutex_lock(&(info->open_mutex)); if (info->state < _MMCAMCORDER_SOUND_STATE_INIT) { _mmcam_dbg_warn("not initialized"); pthread_mutex_unlock(&(info->open_mutex)); - return FALSE; + return TRUE; } - info->thread_run = 0; - pthread_cond_signal(&(info->play_cond)); + if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON) { + /** + * Restore route + */ + _mmcam_dbg_log("restore route"); + if (info->active_out_backup != DEFAULT_ACTIVE_DEVICE) { + ret = mm_sound_get_active_device(&device_in, &device_out); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("mm_sound_get_active_device failed [%x]. skip sound play.", ret); + } + + _mmcam_dbg_log("current out [%x]", device_out); - if (info->thread) { - _mmcam_dbg_log("wait for sound write thread join"); - pthread_join(info->thread, NULL); - _mmcam_dbg_log("join done"); + if (device_out != info->active_out_backup) { + ret = mm_sound_set_active_route (info->active_out_backup); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("mm_sound_set_active_route failed [%x]. skip sound play.", ret); + } + } + } } - if (info->state == _MMCAMCORDER_SOUND_STATE_PREPARE) { - _mmcam_dbg_log("restore route policy [%d]", info->route_policy_backup); +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE + /** + * Remove sample + */ + _mmcam_dbg_log("remove sample"); - if (info->route_policy_backup != -1) { - mm_sound_route_set_system_policy(info->route_policy_backup); - } + pa_threaded_mainloop_lock(info->pulse_mainloop); - mm_sound_pcm_play_close(info->handle); - __cleanup_buffer(info); - } + /* Remove sample (ASYNC) */ + pa_operation_unref(pa_context_remove_sample(info->pulse_context, SAMPLE_SOUND_NAME, __pulseaudio_remove_sample_finish_cb, info)); + + /* Wait for async operation */ + pa_threaded_mainloop_wait(info->pulse_mainloop); + pa_threaded_mainloop_unlock(info->pulse_mainloop); +#endif /* _MMCAMCORDER_UPLOAD_SAMPLE */ + + /** + * Release pulseaudio thread + */ + _mmcam_dbg_log("release pulseaudio thread"); + + pa_threaded_mainloop_lock(info->pulse_mainloop); + + pa_context_disconnect(info->pulse_context); + + /* Make sure we don't get any further callbacks */ + pa_context_set_state_callback(info->pulse_context, NULL, NULL); + + pa_context_unref(info->pulse_context); + info->pulse_context = NULL; + + pa_threaded_mainloop_unlock(info->pulse_mainloop); + + pa_threaded_mainloop_stop(info->pulse_mainloop); + pa_threaded_mainloop_free(info->pulse_mainloop); + info->pulse_mainloop = NULL; + +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE if (info->filename) { free(info->filename); info->filename = NULL; } +#endif /* _MMCAMCORDER_UPLOAD_SAMPLE */ info->state = _MMCAMCORDER_SOUND_STATE_NONE; - info->route_policy_backup = -1; + info->active_out_backup = DEFAULT_ACTIVE_DEVICE; + /* release mutex and cond */ + _mmcam_dbg_log("release play_mutex/cond"); pthread_mutex_destroy(&(info->play_mutex)); pthread_cond_destroy(&(info->play_cond)); + if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON) { + int errorcode = 0; + ASM_resource_t mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY | ASM_RESOURCE_HW_ENCODER; + + /* stop EXCLUSIVE session */ + if (!ASM_set_sound_state(hcamcorder->asm_handle_ex, ASM_EVENT_EXCLUSIVE_MMCAMCORDER, + ASM_STATE_STOP, mm_resource, &errorcode)) { + _mmcam_dbg_err("EXCLUSIVE Set state to STOP failed 0x%x", errorcode); + } else { + _mmcam_dbg_log("EXCLUSIVE session STOP done."); + } + } + pthread_mutex_unlock(&(info->open_mutex)); - _mmcam_dbg_log("Done"); + _mmcam_dbg_err("DONE"); return TRUE; } +gboolean _mmcamcorder_sound_capture_play_cb(gpointer data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data); + + mmf_return_val_if_fail(hcamcorder, FALSE); + + _mmcam_dbg_log("Capture sound PLAY in idle callback"); + + _mmcamcorder_sound_solo_play((MMHandleType)hcamcorder, _MMCAMCORDER_FILEPATH_CAPTURE_SND, FALSE); + + return FALSE; +} + + void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gboolean sync) { mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); int sound_handle = 0; - int ret = 0; + int ret = MM_ERROR_NONE; int sound_enable = TRUE; + int gain_type = VOLUME_GAIN_SHUTTER1; - mmf_return_if_fail( filepath ); + mmf_return_if_fail(filepath && hcamcorder); - _mmcam_dbg_log( "START" ); + _mmcam_dbg_log("START : %s", filepath); ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL, "capture-sound-enable", &sound_enable, NULL); - if (ret == MM_ERROR_NONE) { - if (sound_enable == FALSE) { - _mmcam_dbg_log("Capture sound DISABLED."); - return; - } - } else { - _mmcam_dbg_warn("capture-sound-enable get FAILED.[%x]", ret); + _mmcam_dbg_log("Capture sound enable %d", sound_enable); + if (!sound_enable) { + return; } ret = pthread_mutex_trylock(&(hcamcorder->sound_lock)); @@ -436,10 +662,40 @@ void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gbo return; } - MMTA_ACUM_ITEM_BEGIN("CAPTURE SOUND:mm_sound_play_loud_solo_sound", FALSE); + /* check filename to set gain_type */ + if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE_SND)) { + gain_type = VOLUME_GAIN_SHUTTER1; + } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_CAPTURE2_SND)) { + gain_type = VOLUME_GAIN_SHUTTER2; + } else if (!strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_START_SND) || + !strcmp(filepath, _MMCAMCORDER_FILEPATH_REC_STOP_SND)) { + gain_type = VOLUME_GAIN_CAMCORDING; + } + + _mmcam_dbg_log("gain type 0x%x", gain_type); + + if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_ON) { + __ta__("CAPTURE SOUND:mm_sound_play_loud_solo_sound", + ret = mm_sound_play_loud_solo_sound(filepath, VOLUME_TYPE_FIXED | gain_type, + __solo_sound_callback, (void*)hcamcorder, &sound_handle); + ); + } else { + gboolean sound_status = hcamcorder->sub_context->info_image->sound_status; + mm_sound_device_in device_in; + mm_sound_device_out device_out; + + /* get sound path */ + mm_sound_get_active_device(&device_in, &device_out); - ret = mm_sound_play_loud_solo_sound(filepath, VOLUME_TYPE_FIXED, __solo_sound_callback, - (void*)hcamcorder, &sound_handle); + _mmcam_dbg_log("sound status %d, device out %x", sound_status, device_out); + + if (sound_status || device_out != MM_SOUND_DEVICE_OUT_SPEAKER) { + __ta__("CAPTURE SOUND:mm_sound_play_sound", + ret = mm_sound_play_sound(filepath, VOLUME_TYPE_MEDIA | gain_type, + __solo_sound_callback, (void*)hcamcorder, &sound_handle); + ); + } + } if (ret != MM_ERROR_NONE) { _mmcam_dbg_err( "Capture sound play FAILED.[%x]", ret ); } else { @@ -453,6 +709,8 @@ void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gbo _mmcam_dbg_log("Wait for signal"); + MMTA_ACUM_ITEM_BEGIN("CAPTURE SOUND:wait sound play finish", FALSE); + if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) { _mmcam_dbg_log("signal received."); } else { @@ -461,11 +719,11 @@ void _mmcamcorder_sound_solo_play(MMHandleType handle, const char* filepath, gbo mm_sound_stop_sound(sound_handle); } } + + MMTA_ACUM_ITEM_END("CAPTURE SOUND:wait sound play finish", FALSE); } } - MMTA_ACUM_ITEM_END("CAPTURE SOUND:mm_sound_play_loud_solo_sound", FALSE); - pthread_mutex_unlock(&(hcamcorder->sound_lock)); _mmcam_dbg_log("DONE"); diff --git a/src/mm_camcorder_stillshot.c b/src/mm_camcorder_stillshot.c index f6ef4fe..84c433d 100644 --- a/src/mm_camcorder_stillshot.c +++ b/src/mm_camcorder_stillshot.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "mm_camcorder_internal.h" #include "mm_camcorder_stillshot.h" #include "mm_camcorder_exifinfo.h" @@ -42,6 +43,12 @@ /*--------------------------------------------------------------------------------------- | LOCAL VARIABLE DEFINITIONS for internal | ---------------------------------------------------------------------------------------*/ +#define THUMBNAIL_WIDTH 320 +#define THUMBNAIL_HEIGHT 240 +#define THUMBNAIL_DEFAULT_RATIO 1.34 +#define THUMBNAIL_JPEG_QUALITY 50 +#define TRY_LOCK_MAX_COUNT 100 +#define TRY_LOCK_TIME 50000 /* ms */ /*--------------------------------------------------------------------------------------- @@ -54,12 +61,13 @@ int _mmcamcorder_image_cmd_preview_start(MMHandleType handle); int _mmcamcorder_image_cmd_preview_stop(MMHandleType handle); static void __mmcamcorder_image_capture_cb(GstElement *element, GstBuffer *buffer1, GstBuffer *buffer2, GstBuffer *buffer3, gpointer u_data); -/* Functions for JPEG capture with Encode bin */ -int _mmcamcorder_image_cmd_capture_with_encbin(MMHandleType handle); -int _mmcamcorder_image_cmd_preview_start_with_encbin(MMHandleType handle); -int _mmcamcorder_image_cmd_preview_stop_with_encbin(MMHandleType handle); +/* Function for JPEG capture with Encode bin */ static gboolean __mmcamcorder_encodesink_handoff_callback(GstElement *fakesink, GstBuffer *buffer, GstPad *pad, gpointer u_data); +/* sound status changed callback */ +static void __sound_status_changed_cb(keynode_t* node, void *data); +static void __volume_level_changed_cb(void* user_data); + /*======================================================================================= | FUNCTION DEFINITIONS | =======================================================================================*/ @@ -76,97 +84,97 @@ int _mmcamcorder_add_stillshot_pipeline(MMHandleType handle) GstPad *srcpad = NULL; GstPad *sinkpad = NULL; - mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _MMCamcorderSubContext *sc = NULL; _MMCamcorderImageInfo *info = NULL; mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); sc = MMF_CAMCORDER_SUBCONTEXT(handle); - mmf_return_val_if_fail(sc && sc->info && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc && sc->info_image && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - info = sc->info; + info = sc->info_image; _mmcam_dbg_log(""); - //Create gstreamer element - //Check main pipeline + /* Check main pipeline */ if (!sc->element[_MMCAMCORDER_MAIN_PIPE].gst) { _mmcam_dbg_err( "Main Pipeline is not existed." ); - err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; - goto pipeline_creation_error; + return MM_ERROR_CAMCORDER_RESOURCE_CREATION; } - _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, - CONFIGURE_CATEGORY_MAIN_CAPTURE, - "UseEncodebin", - &sc->bencbin_capture); - - if (sc->bencbin_capture) { - _mmcam_dbg_log("Using Encodebin for capturing"); - __ta__(" _mmcamcorder_create_encodesink_bin", - err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder); - ); - if (err != MM_ERROR_NONE) { - return err; - } - - gst_bin_add_many(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), - sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, - NULL); + /* Create gstreamer element */ + _mmcam_dbg_log("Using Encodebin for capturing"); - /* Link each element */ - srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst, "src1"); - sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "image_sink0"); - _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, element_link_error) + __ta__(" _mmcamcorder_create_encodesink_bin", + err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_IMAGE); + ); + if (err != MM_ERROR_NONE) { + return err; + } - MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, - _MMCAMCORDER_HANDLER_STILLSHOT, "handoff", - G_CALLBACK(__mmcamcorder_encodesink_handoff_callback), - hcamcorder); - } else { - _mmcam_dbg_log("NOT using Encodebin for capturing"); + gst_bin_add_many(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), + sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, + NULL); - /*set video source element*/ - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "signal-still-capture", TRUE); + /* Link each element */ + srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst, "src1"); + sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "image_sink0"); + _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, element_link_error) - MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, - _MMCAMCORDER_HANDLER_STILLSHOT, "still-capture", - G_CALLBACK(__mmcamcorder_image_capture_cb), - hcamcorder); - } + MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, + _MMCAMCORDER_HANDLER_STILLSHOT, "handoff", + G_CALLBACK(__mmcamcorder_encodesink_handoff_callback), + hcamcorder); return MM_ERROR_NONE; element_link_error: - if (sc->bencbin_capture) { - _mmcam_dbg_err("Link encodebin failed!"); + _mmcam_dbg_err("Link encodebin failed!"); - if (sc->element[_MMCAMCORDER_ENCSINK_BIN].gst != NULL) { - int ret = MM_ERROR_NONE; + if (sc->element[_MMCAMCORDER_ENCSINK_BIN].gst != NULL) { + int ret = MM_ERROR_NONE; - __ta__( " EncodeBin Set NULL", - ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, GST_STATE_NULL); - ); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_err("Faile to change encode bin state[%d]", ret); - /* Can't return here. */ - /* return ret; */ - } + __ta__( " EncodeBin Set NULL", + ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, GST_STATE_NULL); + ); + _mmcam_dbg_log("encodebin _mmcamcorder_gst_set_state NULL ret[%d]", ret); - gst_bin_remove(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), - sc->element[_MMCAMCORDER_ENCSINK_BIN].gst); + gst_bin_remove(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), + sc->element[_MMCAMCORDER_ENCSINK_BIN].gst); - _mmcamcorder_remove_element_handle(handle, _MMCAMCORDER_ENCSINK_BIN, _MMCAMCORDER_ENCSINK_SINK); + _mmcamcorder_remove_element_handle(handle, _MMCAMCORDER_ENCSINK_BIN, _MMCAMCORDER_ENCSINK_SINK); - _mmcam_dbg_log("Encodebin removed"); - } + _mmcam_dbg_log("Encodebin removed"); } return MM_ERROR_CAMCORDER_GST_LINK; +} + -pipeline_creation_error: - return err; +int _mmcamcorder_connect_capture_signal(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + /*set video source element*/ + if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "signal-still-capture", TRUE); + + MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, + _MMCAMCORDER_HANDLER_STILLSHOT, "still-capture", + G_CALLBACK(__mmcamcorder_image_capture_cb), + hcamcorder); + return MM_ERROR_NONE; + } else { + _mmcam_dbg_err("videosrc element is not created yet"); + return MM_ERROR_CAMCORDER_NOT_INITIALIZED; + } } @@ -179,9 +187,9 @@ int _mmcamcorder_remove_stillshot_pipeline(MMHandleType handle) mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); sc = MMF_CAMCORDER_SUBCONTEXT(handle); - mmf_return_val_if_fail(sc && sc->info && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc && sc->info_image && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - info = sc->info; + info = sc->info_image; _mmcam_dbg_log(""); @@ -213,7 +221,7 @@ int _mmcamcorder_remove_stillshot_pipeline(MMHandleType handle) } -void _mmcamcorder_destroy_image_pipeline(MMHandleType handle) +void _mmcamcorder_destroy_video_capture_pipeline(MMHandleType handle) { GstPad *reqpad1 = NULL; GstPad *reqpad2 = NULL; @@ -225,7 +233,7 @@ void _mmcamcorder_destroy_image_pipeline(MMHandleType handle) sc = MMF_CAMCORDER_SUBCONTEXT(handle); mmf_return_if_fail(sc && sc->element); - + _mmcam_dbg_log(""); if (sc->element[_MMCAMCORDER_MAIN_PIPE].gst) { @@ -241,18 +249,8 @@ void _mmcamcorder_destroy_image_pipeline(MMHandleType handle) gst_object_unref(reqpad1); gst_object_unref(reqpad2); - if (sc->bencbin_capture) { - if (sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst) { - GstPad *reqpad0 = NULL; - reqpad0 = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "image"); - gst_element_release_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad0); - gst_object_unref(reqpad0); - } - } - gst_object_unref(sc->element[_MMCAMCORDER_MAIN_PIPE].gst); - /* Why is this commented? */ - /* sc->element[_MMCAMCORDER_MAIN_PIPE].gst = NULL; */ + /* NULL initialization will be done in _mmcamcorder_element_release_noti */ } } @@ -265,8 +263,8 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle) int height = 0; int fps = 0; int cap_format = MM_PIXEL_FORMAT_NV12; - int cap_jpeg_quality = 0; int image_encoder = MM_IMAGE_CODEC_JPEG; + int strobe_mode = MM_CAMCORDER_STROBE_MODE_OFF; unsigned int cap_fourcc = 0; char *err_name = NULL; @@ -281,16 +279,17 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle) _MMCamcorderImageInfo *info = NULL; _MMCamcorderSubContext *sc = NULL; type_element *VideosrcElement = NULL; + MMCamcorderStateType current_state = MM_CAMCORDER_STATE_NONE; mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); sc = MMF_CAMCORDER_SUBCONTEXT(handle); - mmf_return_val_if_fail(sc && sc->info && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc && sc->info_image && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); _mmcam_dbg_log(""); pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; - info = sc->info; + info = sc->info_image; _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, CONFIGURE_CATEGORY_MAIN_CAPTURE, @@ -311,27 +310,32 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle) MMTA_ACUM_ITEM_BEGIN("Real First Capture Start",false); + /* get current state */ + mm_camcorder_get_state(handle, ¤t_state); + /* set capture flag */ info->capturing = TRUE; - ret = mm_camcorder_get_attributes(handle, &err_name, - MMCAM_IMAGE_ENCODER_QUALITY, &cap_jpeg_quality, - MMCAM_IMAGE_ENCODER, &image_encoder, - MMCAM_CAMERA_WIDTH, &width, - MMCAM_CAMERA_HEIGHT, &height, - MMCAM_CAMERA_FPS, &fps, - MMCAM_CAPTURE_FORMAT, &cap_format, - MMCAM_CAPTURE_WIDTH, &info->width, - MMCAM_CAPTURE_HEIGHT, &info->height, - MMCAM_CAPTURE_COUNT, &info->count, - MMCAM_CAPTURE_INTERVAL, &info->interval, - NULL); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret); - SAFE_FREE (err_name); - goto cmd_error; - } - + mm_camcorder_get_attributes(handle, &err_name, + MMCAM_IMAGE_ENCODER, &image_encoder, + MMCAM_CAMERA_WIDTH, &width, + MMCAM_CAMERA_HEIGHT, &height, + MMCAM_CAMERA_FPS, &fps, + MMCAM_CAMERA_HDR_CAPTURE, &info->hdr_capture_mode, + MMCAM_CAPTURE_FORMAT, &cap_format, + MMCAM_CAPTURE_WIDTH, &info->width, + MMCAM_CAPTURE_HEIGHT, &info->height, + MMCAM_CAPTURE_COUNT, &info->count, + MMCAM_CAPTURE_INTERVAL, &info->interval, + MMCAM_STROBE_MODE, &strobe_mode, + NULL); + if (err_name) { + _mmcam_dbg_warn("get_attributes err %s", err_name); + free(err_name); + err_name = NULL; + } + + /* check capture count */ if (info->count < 1) { _mmcam_dbg_err("capture count[%d] is invalid", info->count); ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT; @@ -342,38 +346,54 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle) info->type = _MMCamcorder_MULTI_SHOT; info->next_shot_time = 0; info->multi_shot_stop = FALSE; + + /* sound init to pause other session */ + __ta__(" _mmcamcorder_sound_init", +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE + _mmcamcorder_sound_init(handle, _MMCAMCORDER_FILEPATH_CAPTURE2_SND); +#else /* _MMCAMCORDER_UPLOAD_SAMPLE */ + _mmcamcorder_sound_init(handle); +#endif /* _MMCAMCORDER_UPLOAD_SAMPLE */ + ); + } + + _mmcam_dbg_log("preview(%dx%d,fmt:%d), capture(%dx%d,fmt:%d), count(%d), hdr mode(%d)", + width, height, info->preview_format, + info->width, info->height, cap_format, + info->count, info->hdr_capture_mode); + + /* check state */ + if (current_state >= MM_CAMCORDER_STATE_RECORDING) { + if (info->type == _MMCamcorder_MULTI_SHOT || + info->hdr_capture_mode != MM_CAMCORDER_HDR_OFF || + info->preview_format != MM_PIXEL_FORMAT_ITLV_JPEG_UYVY) { + _mmcam_dbg_err("not support multi/HDR capture while recording or NOT ITLV format"); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto cmd_error; + } } info->capture_cur_count = 0; info->capture_send_count = 0; - _mmcam_dbg_log("videosource(%dx%d), capture(%dx%d), count(%d)", - width, height, info->width, info->height, info->count); - sc->internal_encode = FALSE; - if (!strcmp(videosrc_name, "avsysvideosrc") || !strcmp(videosrc_name, "camerasrc")) { + if (!sc->bencbin_capture) { /* Check encoding method */ if (cap_format == MM_PIXEL_FORMAT_ENCODED) { if (sc->SensorEncodedCapture && info->type == _MMCamcorder_SINGLE_SHOT) { cap_fourcc = _mmcamcorder_get_fourcc(cap_format, image_encoder, hcamcorder->use_zero_copy_format); _mmcam_dbg_log("Sensor JPEG Capture"); } else { - int raw_capture_format = MM_PIXEL_FORMAT_I420; - - ret = mm_camcorder_get_attributes(handle, &err_name, - MMCAM_RECOMMEND_PREVIEW_FORMAT_FOR_CAPTURE, &raw_capture_format, - NULL ); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_warn("Get Recommend capture format failed."); - SAFE_FREE(err_name); - goto cmd_error; + /* no need to encode internally if ITLV format */ + if (info->preview_format != MM_PIXEL_FORMAT_ITLV_JPEG_UYVY) { + sc->internal_encode = TRUE; } - cap_fourcc = _mmcamcorder_get_fourcc(raw_capture_format, image_encoder, hcamcorder->use_zero_copy_format); - sc->internal_encode = TRUE; + cap_fourcc = _mmcamcorder_get_fourcc(info->preview_format, image_encoder, hcamcorder->use_zero_copy_format); - _mmcam_dbg_log("MSL JPEG Capture"); + _mmcam_dbg_log("MSL JPEG Capture : capture fourcc %c%c%c%c", + cap_fourcc, cap_fourcc>>8, cap_fourcc>>16, cap_fourcc>>24); } } else { cap_fourcc = _mmcamcorder_get_fourcc(cap_format, MM_IMAGE_CODEC_INVALID, hcamcorder->use_zero_copy_format); @@ -383,13 +403,13 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle) } } - _mmcam_dbg_log("capture format (%d), jpeg quality (%d)", cap_format, cap_jpeg_quality); + _mmcam_dbg_log("capture format (%d)", cap_format); /* Note: width/height of capture is set in commit function of attribute or in create function of pipeline */ MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-fourcc", cap_fourcc); MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-interval", info->interval); MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-count", info->count); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-jpg-quality", cap_jpeg_quality); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hdr-capture", info->hdr_capture_mode); if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { _mmcam_dbg_err("Can't cast Video source into camera control."); @@ -402,6 +422,13 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle) int need_change = 0; int set_width = 0; int set_height = 0; + int cap_jpeg_quality = 0; + + if (current_state >= MM_CAMCORDER_STATE_RECORDING) { + _mmcam_dbg_err("could not capture in this target while recording"); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto cmd_error; + } if (UseCaptureMode) { if (width != MMFCAMCORDER_HIGHQUALITY_WIDTH || height != MMFCAMCORDER_HIGHQUALITY_HEIGHT) { @@ -413,6 +440,26 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle) } } + /* make pipeline state as READY */ + ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("failed to set state PAUSED %x", ret); + return ret; + } + + /* add encodesinkbin */ + ret = _mmcamcorder_add_stillshot_pipeline((MMHandleType)hcamcorder); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("failed to create encodesinkbin %x", ret); + return ret; + } + + /* set JPEG quality */ + mm_camcorder_get_attributes(handle, &err_name, + MMCAM_IMAGE_ENCODER_QUALITY, &cap_jpeg_quality, + NULL); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_IENC].gst, "quality", cap_jpeg_quality); + if (need_change) { _mmcam_dbg_log("Need to change resolution"); @@ -452,16 +499,40 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle) _mmcam_dbg_log("Change to target resolution(%d, %d)", set_width, set_height); } else { _mmcam_dbg_log("No need to change resolution. Open toggle now."); - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); + } + + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_SINK].gst,"signal-handoffs", TRUE); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); + + /* make pipeline state as PLAYING */ + ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_PLAYING); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("failed to set state PLAYING %x", ret); + return ret; } } /* Play capture sound here if single capture */ - if (info->type == _MMCamcorder_SINGLE_SHOT) { - _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_CAPTURE_SND, FALSE); + if ((info->type == _MMCamcorder_SINGLE_SHOT && + (info->preview_format != MM_PIXEL_FORMAT_ITLV_JPEG_UYVY || strobe_mode == MM_CAMCORDER_STROBE_MODE_OFF)) || + info->hdr_capture_mode) { + if (current_state < MM_CAMCORDER_STATE_RECORDING) { + __ta__(" _mmcamcorder_sound_solo_play", + _mmcamcorder_sound_solo_play((MMHandleType)hcamcorder, _MMCAMCORDER_FILEPATH_CAPTURE_SND, FALSE); + ); + } + + /* set flag */ + info->played_capture_sound = TRUE; + } else { + /* set flag */ + info->played_capture_sound = FALSE; } + return ret; + cmd_error: + info->capturing = FALSE; return ret; } @@ -475,11 +546,11 @@ int _mmcamcorder_image_cmd_preview_start(MMHandleType handle) int cap_width = 0; int cap_height = 0; int rotation = 0; - int input_index = 0; int set_width = 0; int set_height = 0; int set_rotate = 0; int current_framecount = 0; + int current_state = MM_CAMCORDER_STATE_NONE; gboolean fps_auto = FALSE; char *err_name = NULL; char *videosrc_name = NULL; @@ -497,12 +568,12 @@ int _mmcamcorder_image_cmd_preview_start(MMHandleType handle) mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); sc = MMF_CAMCORDER_SUBCONTEXT(handle); - mmf_return_val_if_fail(sc && sc->info && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc && sc->info_image && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); _mmcam_dbg_log(""); pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; - info = sc->info; + info = sc->info_image; MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE); @@ -517,29 +588,20 @@ int _mmcamcorder_image_cmd_preview_start(MMHandleType handle) sc->previous_slot_time = 0; /* Image info */ - info->capture_cur_count = 0; - info->capture_send_count = 0; info->next_shot_time = 0; info->multi_shot_stop = TRUE; info->capturing = FALSE; _mmcamcorder_vframe_stablize(handle); - if (!strcmp(videosrc_name, "avsysvideosrc") || !strcmp(videosrc_name, "camerasrc")) { - _mmcam_dbg_log("Capture Preview start : avsysvideosrc - No need to set new caps."); - - ret = mm_camcorder_get_attributes(handle, &err_name, - MMCAM_CAMERA_FPS_AUTO, &fps_auto, - NULL); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret); - SAFE_FREE (err_name); - goto cmd_error; - } + current_state = _mmcamcorder_get_state(handle); + _mmcam_dbg_log("current state [%d]", current_state); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "fps-auto", fps_auto); + if (!sc->bencbin_capture) { + _mmcam_dbg_log("Capture Preview start : avsysvideosrc - No need to set new caps."); - if (_mmcamcorder_get_state(handle) == MM_CAMCORDER_STATE_CAPTURING) { + /* just set capture stop command if current state is CAPTURING */ + if (current_state == MM_CAMCORDER_STATE_CAPTURING) { if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { _mmcam_dbg_err("Can't cast Video source into camera control."); return MM_ERROR_CAMCORDER_NOT_SUPPORTED; @@ -553,26 +615,39 @@ int _mmcamcorder_image_cmd_preview_start(MMHandleType handle) if (info->type == _MMCamcorder_SINGLE_SHOT) { MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); } + } else { + int focus_mode = 0; + + /* This case is starting of preview */ + ret = mm_camcorder_get_attributes(handle, &err_name, + MMCAM_CAMERA_FPS_AUTO, &fps_auto, + MMCAM_CAMERA_FOCUS_MODE, &focus_mode, + NULL); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret); + SAFE_FREE (err_name); + } + + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "fps-auto", fps_auto); + + /* set focus mode */ + mm_camcorder_set_attributes(handle, NULL, + MMCAM_CAMERA_FOCUS_MODE, focus_mode, + NULL); } } else { /* check if resolution need to rollback */ - ret = mm_camcorder_get_attributes(handle, &err_name, - MMCAM_CAMERA_DEVICE, &input_index, - MMCAM_CAMERA_WIDTH, &width, - MMCAM_CAMERA_HEIGHT, &height, - MMCAM_CAMERA_FPS, &fps, - MMCAM_CAMERA_FPS_AUTO, &fps_auto, - MMCAM_CAMERA_ROTATION, &rotation, - MMCAM_CAPTURE_WIDTH, &cap_width, - MMCAM_CAPTURE_HEIGHT, &cap_height, - NULL); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret); - SAFE_FREE (err_name); - goto cmd_error; - } + mm_camcorder_get_attributes(handle, &err_name, + MMCAM_CAMERA_WIDTH, &width, + MMCAM_CAMERA_HEIGHT, &height, + MMCAM_CAMERA_FPS, &fps, + MMCAM_CAMERA_FPS_AUTO, &fps_auto, + MMCAM_CAMERA_ROTATION, &rotation, + MMCAM_CAPTURE_WIDTH, &cap_width, + MMCAM_CAPTURE_HEIGHT, &cap_height, + NULL); - if (_mmcamcorder_get_state((MMHandleType)hcamcorder) == MM_CAMCORDER_STATE_CAPTURING) { + if (current_state == MM_CAMCORDER_STATE_CAPTURING) { switch (rotation) { case MM_VIDEO_INPUT_ROTATION_90: set_width = height; @@ -622,12 +697,26 @@ int _mmcamcorder_image_cmd_preview_start(MMHandleType handle) if (!strcmp(videosrc_name, "avsysvideosrc") || !strcmp(videosrc_name, "camerasrc")) { int try_count = 0; - __ta__( " Wait preview frame after capture", - while (current_framecount >= sc->kpi.video_framecount && - try_count++ < _MMCAMCORDER_CAPTURE_STOP_CHECK_COUNT) { - usleep(_MMCAMCORDER_CAPTURE_STOP_CHECK_INTERVAL); + if (info->preview_format != MM_PIXEL_FORMAT_ITLV_JPEG_UYVY) { + mmf_attrs_t *attr = (mmf_attrs_t *)MMF_CAMCORDER_ATTRS(handle); + + /* Set strobe mode - strobe mode can not be set to driver while captuing */ + if (attr) { + __ta__(" Set strobe mode after capture", + mmf_attribute_set_modified(&(attr->items[MM_CAM_STROBE_MODE])); + if (mmf_attrs_commit((MMHandleType) attr) == -1) { + _mmcam_dbg_warn("Failed to set strobe mode"); + } + ); + } + + __ta__(" Wait preview frame after capture", + while (current_framecount >= sc->kpi.video_framecount && + try_count++ < _MMCAMCORDER_CAPTURE_STOP_CHECK_COUNT) { + usleep(_MMCAMCORDER_CAPTURE_STOP_CHECK_INTERVAL); + } + ); } - ); if (info->type == _MMCamcorder_MULTI_SHOT) { MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); @@ -636,454 +725,111 @@ int _mmcamcorder_image_cmd_preview_start(MMHandleType handle) _mmcam_dbg_log("Wait Frame Done. count before[%d],after[%d], try_count[%d]", current_framecount, sc->kpi.video_framecount, try_count); } else { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE); ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY); MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); - - if (ret != MM_ERROR_NONE) { - goto cmd_error; - } - - ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); if (ret != MM_ERROR_NONE) { goto cmd_error; } - } - } else { - int cap_count = 0; - int sound_ret = FALSE; - - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); - - __ta__(" _MMCamcorder_CMD_PREVIEW_START:GST_STATE_PLAYING", - ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); - ); - if (ret != MM_ERROR_NONE) { - goto cmd_error; - } - - mm_camcorder_get_attributes(handle, NULL, MMCAM_CAPTURE_COUNT, &cap_count, NULL); - if (cap_count > 1) { - __ta__("_mmcamcorder_sound_init", - sound_ret = _mmcamcorder_sound_init(handle, _MMCAMCORDER_FILEPATH_CAPTURE2_SND); - ); - if (sound_ret) { - __ta__("_mmcamcorder_sound_prepare", - sound_ret = _mmcamcorder_sound_prepare(handle); - ); - _mmcam_dbg_log("sound prepare [%d]", sound_ret); - } - } - } - -cmd_error: - return ret; -} - - -int _mmcamcorder_image_cmd_preview_stop(MMHandleType handle) -{ - int ret = MM_ERROR_NONE; - - GstElement *pipeline = NULL; - - _MMCamcorderSubContext *sc = NULL; - - _mmcam_dbg_log(""); - - mmf_return_val_if_fail(handle, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - - sc = MMF_CAMCORDER_SUBCONTEXT(handle); - mmf_return_val_if_fail(sc && sc->info && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - - pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; - - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE); - ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); - - return ret; -} - - -int _mmcamcorder_image_cmd_capture_with_encbin(MMHandleType handle) -{ - int ret = MM_ERROR_NONE; - int UseCaptureMode = 0; - int width = 0; - int height = 0; - int fps = 0; - int cap_format = MM_PIXEL_FORMAT_ENCODED; - int cap_jpeg_quality = 0; - int image_encoder = MM_IMAGE_CODEC_JPEG; - unsigned int cap_fourcc = GST_MAKE_FOURCC('J','P','E','G'); - char *err_name = NULL; - char *videosrc_name = NULL; - - GstCaps *caps = NULL; - GstClock *clock = NULL; - GstElement *pipeline = NULL; - GstCameraControl *control = NULL; - - mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); - _MMCamcorderImageInfo *info = NULL; - _MMCamcorderSubContext *sc = NULL; - type_element *VideosrcElement = NULL; - - mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - - sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); - mmf_return_val_if_fail(sc && sc->info && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - - _mmcam_dbg_log(""); - - pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; - info = sc->info; - - _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, - CONFIGURE_CATEGORY_MAIN_CAPTURE, - "UseCaptureMode", - &UseCaptureMode); - - _mmcamcorder_conf_get_element(hcamcorder->conf_main, - CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, - "VideosrcElement", - &VideosrcElement); - - _mmcamcorder_conf_get_value_element_name(VideosrcElement, &videosrc_name); - - if (info->capturing) { - ret = MM_ERROR_CAMCORDER_DEVICE_BUSY; - goto cmd_error; - } - - MMTA_ACUM_ITEM_BEGIN("Real First Capture Start",false); - - info->capturing = TRUE; - - ret = mm_camcorder_get_attributes(handle, &err_name, - MMCAM_IMAGE_ENCODER_QUALITY, &cap_jpeg_quality, - MMCAM_IMAGE_ENCODER, &image_encoder, - MMCAM_CAMERA_WIDTH, &width, - MMCAM_CAMERA_HEIGHT, &height, - MMCAM_CAMERA_FPS, &fps, - MMCAM_CAPTURE_FORMAT, &cap_format, - MMCAM_CAPTURE_WIDTH, &info->width, - MMCAM_CAPTURE_HEIGHT, &info->height, - MMCAM_CAPTURE_COUNT, &info->count, - MMCAM_CAPTURE_INTERVAL, &info->interval, - NULL); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_err("Get attrs fail. (%s:%x)", err_name, ret); - SAFE_FREE (err_name); - goto cmd_error; - } - - if (info->count < 1) { - _mmcam_dbg_err("capture count[%d] is invalid", info->count); - ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT; - goto cmd_error; - } else if (info->count == 1) { - info->type = _MMCamcorder_SINGLE_SHOT; - } else { - info->type = _MMCamcorder_MULTI_SHOT; - info->capture_cur_count = 0; - info->capture_send_count = 0; - info->next_shot_time = 0; - info->multi_shot_stop = FALSE; - } - - _mmcam_dbg_log("videosource(%dx%d), capture(%dx%d), count(%d)", - width, height, info->width, info->height, info->count); - if (!strcmp(videosrc_name, "avsysvideosrc") || !strcmp(videosrc_name, "camerasrc")) { - cap_fourcc = _mmcamcorder_get_fourcc(cap_format, image_encoder, hcamcorder->use_zero_copy_format); - _mmcam_dbg_log("capture format (%d), jpeg quality (%d)", cap_format, cap_jpeg_quality); + /* remove handoff signal handler */ + _mmcamcorder_remove_all_handlers(handle, _MMCAMCORDER_HANDLER_STILLSHOT); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-fourcc", cap_fourcc); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-interval", info->interval); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-width", info->width); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-height", info->height); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-count", info->count); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-jpg-quality", cap_jpeg_quality); + /* remove encodesinkbin after capture */ + if (!sc->element[_MMCAMCORDER_ENCSINK_BIN].gst) { + _mmcam_dbg_log("ENCSINK_BIN is already removed"); + } else { + GstPad *reqpad0 = NULL; + GstPad *srcpad = NULL; + GstPad *sinkpad = NULL; - if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { - _mmcam_dbg_err("Can't cast Video source into camera control."); - return MM_ERROR_CAMCORDER_NOT_SUPPORTED; - } + /* release requested pad */ + reqpad0 = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "image"); + gst_element_release_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad0); + gst_object_unref(reqpad0); - control = GST_CAMERA_CONTROL( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst ); - gst_camera_control_set_capture_command( control, GST_CAMERA_CONTROL_CAPTURE_COMMAND_START ); - } else { - int need_change = 0; - int set_width = 0; - int set_height = 0; + /* Unlink each element */ + srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst, "src1"); + sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "image_sink0"); + _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad); - if (UseCaptureMode) { - if (width != MMFCAMCORDER_HIGHQUALITY_WIDTH || height != MMFCAMCORDER_HIGHQUALITY_HEIGHT) { - need_change = 1; - } - } else { - if (width != info->width || height != info->height) { - need_change = 1; - } - } + /* make state of encodesinkbin as NULL */ + _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, GST_STATE_NULL); - if (need_change) { - _mmcam_dbg_log("Need to change resolution"); + gst_bin_remove(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), + sc->element[_MMCAMCORDER_ENCSINK_BIN].gst); - if (UseCaptureMode) { - set_width = MMFCAMCORDER_HIGHQUALITY_WIDTH; - set_height = MMFCAMCORDER_HIGHQUALITY_HEIGHT; - } else { - set_width = info->width; - set_height = info->height; + _mmcamcorder_remove_element_handle(handle, _MMCAMCORDER_ENCSINK_BIN, _MMCAMCORDER_ENCSINK_SINK); } - caps = gst_caps_new_simple("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, sc->fourcc, - "width", G_TYPE_INT, set_width, - "height", G_TYPE_INT, set_height, - "framerate", GST_TYPE_FRACTION, fps, 1, - "rotate", G_TYPE_INT, 0, - NULL); - if (caps == NULL) { - _mmcam_dbg_err("failed to create caps"); - ret = MM_ERROR_CAMCORDER_LOW_MEMORY; + ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); + if (ret != MM_ERROR_NONE) { goto cmd_error; } - - info->resolution_change = TRUE; - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSRC_FILT].gst, "caps", caps); - gst_caps_unref(caps); - - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "req-negotiation",TRUE); - - /* FIXME: consider delay */ - clock = gst_pipeline_get_clock(GST_PIPELINE(pipeline)); - sc->stillshot_time = gst_clock_get_time(clock) - gst_element_get_base_time(GST_ELEMENT(pipeline)); - _mmcam_dbg_log("Change to target resolution(%d, %d)", info->width, info->height); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_SINK].gst,"signal-handoffs",TRUE); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); - - } else { - _mmcam_dbg_log("No need to change resolution. Open toggle now."); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_SINK].gst,"signal-handoffs",TRUE); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); } - } - - /* Play capture sound here if single capture */ - if (info->type == _MMCamcorder_SINGLE_SHOT) { - _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_CAPTURE_SND, FALSE); - } -cmd_error: - return ret; -} - - -int _mmcamcorder_image_cmd_preview_start_with_encbin(MMHandleType handle) -{ - int ret = MM_ERROR_NONE; - int width = 0; - int height = 0; - int fps = 0; - int cap_width = 0; - int cap_height = 0; - int rotation = 0; - int input_index = 0; - int set_width = 0; - int set_height = 0; - int set_rotate = 0; - int current_framecount = 0; - int current_state = MM_CAMCORDER_STATE_NONE; - gboolean fps_auto = FALSE; - char *err_name = NULL; - char *videosrc_name = NULL; - - GstState state = GST_STATE_NULL; - GstCaps *caps = NULL; - GstElement *pipeline = NULL; - GstCameraControl *control = NULL; - - mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); - _MMCamcorderImageInfo *info = NULL; - _MMCamcorderSubContext *sc = NULL; - type_element *VideosrcElement = NULL; - - mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - - sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); - mmf_return_val_if_fail(sc && sc->info && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - - _mmcam_dbg_log(""); - - info = sc->info; - pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; - - _mmcamcorder_conf_get_element(hcamcorder->conf_main, - CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, - "VideosrcElement", - &VideosrcElement); - - _mmcamcorder_conf_get_value_element_name(VideosrcElement, &videosrc_name); - - sc->display_interval = 0; - sc->previous_slot_time = 0; - - /* init image info */ - info->capture_cur_count = 0; - info->capture_send_count = 0; - info->next_shot_time = 0; - info->multi_shot_stop = TRUE; - info->capturing = FALSE; - - _mmcamcorder_vframe_stablize(handle); - - current_state = _mmcamcorder_get_state(handle); - _mmcam_dbg_log("current state [%d]", current_state); - - if (!strcmp(videosrc_name, "avsysvideosrc") || !strcmp(videosrc_name, "camerasrc")) { - _mmcam_dbg_log("Capture Preview start : %s - No need to set new caps.", videosrc_name); - - ret = mm_camcorder_get_attributes(handle, &err_name, - MMCAM_CAMERA_FPS_AUTO, &fps_auto, - NULL); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret); - SAFE_FREE (err_name); - goto cmd_error; + /* sound finalize */ + if (info->type == _MMCamcorder_MULTI_SHOT) { + __ta__(" _mmcamcorder_sound_finalize", + _mmcamcorder_sound_finalize(handle); + ); } + } else { + int cap_count = 0; + int sound_ret = FALSE; - /* set fps-auto to videosrc */ - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "fps-auto", fps_auto); - - if (current_state == MM_CAMCORDER_STATE_CAPTURING) { - if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { - _mmcam_dbg_err("Can't cast Video source into camera control."); - return MM_ERROR_CAMCORDER_NOT_SUPPORTED; - } - - current_framecount = sc->kpi.video_framecount; + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); - control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); - gst_camera_control_set_capture_command(control, GST_CAMERA_CONTROL_CAPTURE_COMMAND_STOP); - } - } else { - /* check if resolution need to roll back */ - ret = mm_camcorder_get_attributes(handle, &err_name, - MMCAM_CAMERA_DEVICE, &input_index, - MMCAM_CAMERA_WIDTH, &width, - MMCAM_CAMERA_HEIGHT, &height, - MMCAM_CAMERA_FPS, &fps, - MMCAM_CAMERA_FPS_AUTO, &fps_auto, - MMCAM_CAMERA_ROTATION, &rotation, - MMCAM_CAPTURE_WIDTH, &cap_width, - MMCAM_CAPTURE_HEIGHT, &cap_height, - NULL); + __ta__(" _MMCamcorder_CMD_PREVIEW_START:GST_STATE_PLAYING", + ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); + ); if (ret != MM_ERROR_NONE) { - _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret); - SAFE_FREE (err_name); goto cmd_error; } - if (current_state == MM_CAMCORDER_STATE_CAPTURING) { - switch (rotation) { - case MM_VIDEO_INPUT_ROTATION_90: - set_width = height; - set_height = width; - set_rotate = 90; - break; - case MM_VIDEO_INPUT_ROTATION_180: - set_width = width; - set_height = height; - set_rotate = 180; - break; - case MM_VIDEO_INPUT_ROTATION_270: - set_width = height; - set_height = width; - set_rotate = 270; - break; - case MM_VIDEO_INPUT_ROTATION_NONE: - default: - set_width = width; - set_height = height; - set_rotate = 0; - break; - } - - caps = gst_caps_new_simple("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, sc->fourcc, - "width", G_TYPE_INT, set_width, - "height", G_TYPE_INT,set_height, - "framerate", GST_TYPE_FRACTION, fps, 1, - "rotate", G_TYPE_INT, set_rotate, - NULL); - if (caps == NULL) { - _mmcam_dbg_err("failed to create caps"); - ret = MM_ERROR_CAMCORDER_LOW_MEMORY; - goto cmd_error; - } - - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_FILT].gst, "caps", caps); - gst_caps_unref(caps); - caps = NULL; - _mmcam_dbg_log("Rollback to original resolution(%d, %d)", width, height); - } - } + /* get sound status/volume level and register changed_cb */ + if (hcamcorder->shutter_sound_policy == VCONFKEY_CAMERA_SHUTTER_SOUND_POLICY_OFF && + info->sound_status == _SOUND_STATUS_INIT) { + _mmcam_dbg_log("get sound status/volume level and register vconf changed_cb"); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); + /* get sound status */ + __ta__(" GET:VCONFKEY_SETAPPL_SOUND_STATUS_BOOL", + vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &(info->sound_status)); + ); - gst_element_get_state(pipeline, &state, NULL, -1); + _mmcam_dbg_log("sound status %d", info->sound_status); - if (state == GST_STATE_PLAYING) { - if (!strcmp(videosrc_name, "avsysvideosrc") || !strcmp(videosrc_name, "camerasrc")) { - __ta__( " Wait preview frame after capture", - while (current_framecount == sc->kpi.video_framecount) { - usleep(_MMCAMCORDER_CAPTURE_STOP_CHECK_INTERVAL); - } + /* get volume level */ + __ta__(" mm_sound_volume_get_value", + mm_sound_volume_get_value(VOLUME_TYPE_MEDIA, &info->volume_level); ); - _mmcam_dbg_log("Wait Frame Done. count before[%d],after[%d]", - current_framecount, sc->kpi.video_framecount); - } else { -#if 1 - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE); - ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); -#else /* This code wasn't work. So rollback to previous code. Plz tell me why. It's weired. */ - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); - ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY); -#endif - if (ret != MM_ERROR_NONE) { - goto cmd_error; - } + _mmcam_dbg_log("volume level %d", info->volume_level); - ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); - if (ret != MM_ERROR_NONE) { - goto cmd_error; - } - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE); + /* register changed_cb */ + vconf_notify_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, __sound_status_changed_cb, hcamcorder); + mm_sound_volume_add_callback(VOLUME_TYPE_MEDIA, __volume_level_changed_cb, hcamcorder); } - } else { - __ta__(" _MMCamcorder_CMD_PREVIEW_START:GST_STATE_PLAYING", - ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); - ); - if (ret != MM_ERROR_NONE) { - goto cmd_error; + + mm_camcorder_get_attributes(handle, NULL, MMCAM_CAPTURE_COUNT, &cap_count, NULL); + if (cap_count > 1) { + __ta__("_mmcamcorder_sound_init", +#ifdef _MMCAMCORDER_UPLOAD_SAMPLE + sound_ret = _mmcamcorder_sound_init(handle, _MMCAMCORDER_FILEPATH_CAPTURE2_SND); +#else /* _MMCAMCORDER_UPLOAD_SAMPLE */ + sound_ret = _mmcamcorder_sound_init(handle); +#endif /* _MMCAMCORDER_UPLOAD_SAMPLE */ + ); } } cmd_error: - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_SINK].gst,"signal-handoffs",FALSE); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE); return ret; } -int _mmcamcorder_image_cmd_preview_stop_with_encbin(MMHandleType handle) +int _mmcamcorder_image_cmd_preview_stop(MMHandleType handle) { int ret = MM_ERROR_NONE; @@ -1096,26 +842,33 @@ int _mmcamcorder_image_cmd_preview_stop_with_encbin(MMHandleType handle) mmf_return_val_if_fail(handle, MM_ERROR_CAMCORDER_NOT_INITIALIZED); sc = MMF_CAMCORDER_SUBCONTEXT(handle); - mmf_return_val_if_fail(sc && sc->info && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; - /* set signal handler off */ - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_SINK].gst,"signal-handoffs",FALSE); - - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE); ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY); - if (ret != MM_ERROR_NONE) { - goto cmd_error; + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); + + /* deregister sound status callback */ + if (sc->info_image->sound_status != _SOUND_STATUS_INIT) { + _mmcam_dbg_log("deregister sound status callback"); + + __ta__(" vconf_ignore_key_changed", + vconf_ignore_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, __sound_status_changed_cb); + ); + __ta__(" mm_sound_volume_remove_callback", + mm_sound_volume_remove_callback(VOLUME_TYPE_MEDIA); + ); + + sc->info_image->sound_status = _SOUND_STATUS_INIT; } -cmd_error: return ret; } -int _mmcamcorder_image_command(MMHandleType handle, int command) +int _mmcamcorder_video_capture_command(MMHandleType handle, int command) { int ret = MM_ERROR_NONE; @@ -1127,34 +880,27 @@ int _mmcamcorder_image_command(MMHandleType handle, int command) sc = MMF_CAMCORDER_SUBCONTEXT(handle); mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - _mmcam_dbg_log("command=%d", command); + _mmcam_dbg_log("command %d", command); switch (command) { case _MMCamcorder_CMD_CAPTURE: - if (!sc->bencbin_capture) { - ret = _mmcamcorder_image_cmd_capture(handle); - } else { - ret = _mmcamcorder_image_cmd_capture_with_encbin(handle); - } - break; - case _MMCamcorder_CMD_CAPTURE_CANCEL: - /* TODO: Is this needed? */ + ret = _mmcamcorder_image_cmd_capture(handle); break; case _MMCamcorder_CMD_PREVIEW_START: - if (!sc->bencbin_capture) { - ret = _mmcamcorder_image_cmd_preview_start(handle); - } else { - ret = _mmcamcorder_image_cmd_preview_start_with_encbin(handle); - } + ret = _mmcamcorder_image_cmd_preview_start(handle); + /* I place this function last because it miscalculates a buffer that sents in GST_STATE_PAUSED */ _mmcamcorder_video_current_framerate_init(handle); break; case _MMCamcorder_CMD_PREVIEW_STOP: - if (!sc->bencbin_capture) { - ret = _mmcamcorder_image_cmd_preview_stop(handle); - } else { - ret = _mmcamcorder_image_cmd_preview_stop_with_encbin(handle); - } + ret = _mmcamcorder_image_cmd_preview_stop(handle); + break; + case _MMCamcorder_CMD_RECORD: + case _MMCamcorder_CMD_PAUSE: + case _MMCamcorder_CMD_CANCEL: + case _MMCamcorder_CMD_COMMIT: + /* video recording command */ + ret = _mmcamcorder_video_command(handle, command); break; default: ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT; @@ -1173,8 +919,6 @@ int _mmcamcorder_image_command(MMHandleType handle, int command) void __mmcamcorder_init_stillshot_info (MMHandleType handle) { - int type = _MMCamcorder_SINGLE_SHOT; - mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _MMCamcorderSubContext *sc = NULL; _MMCamcorderImageInfo *info = NULL; @@ -1182,30 +926,27 @@ void __mmcamcorder_init_stillshot_info (MMHandleType handle) mmf_return_if_fail(hcamcorder); sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); - mmf_return_if_fail(sc && sc->info); + mmf_return_if_fail(sc && sc->info_image); - info = sc->info; - type = info->type; + info = sc->info_image; - _mmcam_dbg_log("capture type[%d], capture send count[%d]", type, info->capture_send_count); + _mmcam_dbg_log("capture type[%d], capture send count[%d]", info->type, info->capture_send_count); - if (type ==_MMCamcorder_SINGLE_SHOT || info->capture_send_count == info->count) { + if (info->type ==_MMCamcorder_SINGLE_SHOT || info->capture_send_count == info->count) { info->capture_cur_count = 0; info->capture_send_count = 0; info->multi_shot_stop = TRUE; info->next_shot_time = 0; - info->type = _MMCamcorder_SINGLE_SHOT; /* capturing flag set to FALSE here */ info->capturing = FALSE; - MMTA_ACUM_ITEM_END("Real First Capture Start", FALSE); } return; } -gboolean __mmcamcorder_capture_save_exifinfo(MMHandleType handle, MMCamcorderCaptureDataType *original, MMCamcorderCaptureDataType *thumbnail) +int __mmcamcorder_capture_save_exifinfo(MMHandleType handle, MMCamcorderCaptureDataType *original, MMCamcorderCaptureDataType *thumbnail) { int ret = MM_ERROR_NONE; unsigned char *data = NULL; @@ -1219,120 +960,45 @@ gboolean __mmcamcorder_capture_save_exifinfo(MMHandleType handle, MMCamcorderCap if (!original || original->data == NULL || original->length == 0) { _mmcam_dbg_err("original=%p, data=%p, length=%d", original, original->data, original->length); - return FALSE; + return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; } else { /* original is input/output param. save original values to local var. */ data = original->data; datalen = original->length; } - /* exif 090227 */ - ret = mm_exif_create_exif_info(&(hcamcorder->exif_info)); - if (hcamcorder->exif_info == NULL || ret != MM_ERROR_NONE) { - _MMCamcorderMsgItem msg; - - msg.id = MM_MESSAGE_CAMCORDER_ERROR; - msg.param.code = ret; - _mmcamcroder_send_message(handle, &msg); - - _mmcam_dbg_err("Failed to create exif_info [%x]", ret); - return FALSE; - } - - /* add basic exif info */ - _mmcam_dbg_log("add basic exif info"); - __ta__(" __mmcamcorder_set_exif_basic_info", - ret = __mmcamcorder_set_exif_basic_info(handle); - ); - if (ret != MM_ERROR_NONE) { - _MMCamcorderMsgItem msg; - - msg.id = MM_MESSAGE_CAMCORDER_ERROR; - msg.param.code = ret; - _mmcamcroder_send_message(handle, &msg); - - _mmcam_dbg_err("Failed to set_exif_basic_info [%x]", ret); - } - - if (thumbnail != NULL) { - int bthumbnail = TRUE; - - /* check whether thumbnail should be included */ - mm_camcorder_get_attributes(handle, NULL, "capture-thumbnail", &bthumbnail, NULL); - - if (thumbnail->data && thumbnail->length >0 && bthumbnail) { + if (thumbnail) { + if (thumbnail->data && thumbnail->length > 0) { _mmcam_dbg_log("thumbnail is added!thumbnail->data=%p thumbnail->width=%d ,thumbnail->height=%d", thumbnail->data, thumbnail->width, thumbnail->height); /* add thumbnail exif info */ - __ta__(" mm_exif_add_thumbnail_info", - ret = mm_exif_add_thumbnail_info(hcamcorder->exif_info, thumbnail->data,thumbnail->width, thumbnail->height, thumbnail->length); + __ta__(" mm_exif_add_thumbnail_info", + ret = mm_exif_add_thumbnail_info(hcamcorder->exif_info, + thumbnail->data, + thumbnail->width, + thumbnail->height, + thumbnail->length); ); - if (ret != MM_ERROR_NONE) { - _MMCamcorderMsgItem msg; - - msg.id = MM_MESSAGE_CAMCORDER_ERROR; - msg.param.code = ret; - _mmcamcroder_send_message(handle, &msg); - - _mmcam_dbg_err("Failed to set_exif_thumbnail [%x]",ret); - } } else { - _mmcam_dbg_err("Skip adding thumbnail (data=%p, length=%d, capture-thumbnail=%d)", - thumbnail->data, thumbnail->length , bthumbnail); + _mmcam_dbg_err("Skip adding thumbnail (data=%p, length=%d)", + thumbnail->data, thumbnail->length); } } - /* write jpeg with exif */ - ret = mm_exif_write_exif_jpeg_to_memory(&original->data, &original->length ,hcamcorder->exif_info, data, datalen); - - if (ret != MM_ERROR_NONE) { - _MMCamcorderMsgItem msg; - - msg.id = MM_MESSAGE_CAMCORDER_ERROR; - msg.param.code = ret; - _mmcamcroder_send_message(handle, &msg); - - _mmcam_dbg_err("mm_exif_write_exif_jpeg_to_memory error! [%x]",ret); - } - - /* destroy exif info */ - mm_exif_destory_exif_info(hcamcorder->exif_info); - hcamcorder->exif_info = NULL; - - _mmcam_dbg_log("END"); - - if (ret != MM_ERROR_NONE) { - return FALSE; - } else { - return TRUE; + if (ret == MM_ERROR_NONE) { + /* write jpeg with exif */ + __ta__(" mm_exif_write_exif_jpeg_to_memory", + ret = mm_exif_write_exif_jpeg_to_memory(&original->data, &original->length ,hcamcorder->exif_info, data, datalen); + ); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("mm_exif_write_exif_jpeg_to_memory error! [0x%x]",ret); + } } -} + _mmcam_dbg_log("END ret 0x%x", ret); -gboolean __mmcamcorder_capture_send_msg(MMHandleType handle, int type, int count) -{ - mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); - _MMCamcorderImageInfo *info = NULL; - _MMCamcorderSubContext *sc = NULL; - _MMCamcorderMsgItem msg; - - mmf_return_val_if_fail(hcamcorder, FALSE); - - sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); - mmf_return_val_if_fail(sc && sc->info, FALSE); - - info = sc->info; - - _mmcam_dbg_log("type [%d], capture count [%d]", type, count); - - msg.id = MM_MESSAGE_CAMCORDER_CAPTURED; - msg.param.code = count; - - _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); - - _mmcam_dbg_log("END"); - return TRUE; + return ret; } @@ -1361,9 +1027,9 @@ void __mmcamcorder_get_capture_data_from_buffer(MMCamcorderCaptureDataType *capt gst_structure_get_int(structure, "height", &capture_data->height); capture_data->length = GST_BUFFER_SIZE(buffer); - _mmcam_dbg_err("buffer data[%p],size[%dx%d],length[%d],format[%d]", - capture_data->data, capture_data->width, capture_data->height, - capture_data->length, capture_data->format); + _mmcam_dbg_warn("buffer data[%p],size[%dx%d],length[%d],format[%d]", + capture_data->data, capture_data->width, capture_data->height, + capture_data->length, capture_data->format); gst_caps_unref(caps); caps = NULL; @@ -1378,42 +1044,25 @@ GET_FAILED: } -gboolean __mmcamcorder_set_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType *dest, MMCamcorderCaptureDataType *thumbnail) +int __mmcamcorder_set_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType *dest, MMCamcorderCaptureDataType *thumbnail) { - int tag_enable = 0; - int provide_exif = FALSE; - mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _MMCamcorderSubContext *sc = NULL; - mmf_return_val_if_fail(hcamcorder, FALSE); - mmf_return_val_if_fail(dest, FALSE); + mmf_return_val_if_fail(hcamcorder && dest, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); - mmf_return_val_if_fail(sc, FALSE); + mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED); _mmcam_dbg_log(""); - mm_camcorder_get_attributes(handle, NULL, MMCAM_TAG_ENABLE, &tag_enable, NULL); - MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "provide-exif", &provide_exif); - - _mmcam_dbg_log("tag enable[%d], provide exif[%d]", tag_enable, provide_exif); - /* if tag enable and doesn't provide exif, we make it */ - if (tag_enable && !provide_exif) { - _mmcam_dbg_log("Add exif information if existed(thumbnail[%p])", thumbnail); - if (thumbnail && thumbnail->data) { - if (!__mmcamcorder_capture_save_exifinfo(handle, dest, thumbnail)) { - return FALSE; - } - } else { - if (!__mmcamcorder_capture_save_exifinfo(handle, dest, NULL)) { - return FALSE; - } - } + _mmcam_dbg_log("Add exif information if existed(thumbnail[%p])", thumbnail); + if (thumbnail && thumbnail->data) { + return __mmcamcorder_capture_save_exifinfo(handle, dest, thumbnail); + } else { + return __mmcamcorder_capture_save_exifinfo(handle, dest, NULL); } - - return TRUE; } @@ -1433,13 +1082,17 @@ void __mmcamcorder_release_jpeg_data(MMHandleType handle, MMCamcorderCaptureData _mmcam_dbg_log(""); + __ta__( " Get:MMCAM_TAG_ENABLE and \"provide-exif\"", mm_camcorder_get_attributes(handle, NULL, MMCAM_TAG_ENABLE, &tag_enable, NULL); - MMCAMCORDER_G_OBJECT_GET (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "provide-exif", &provide_exif); + MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "provide-exif", &provide_exif); + ); /* if dest->data is allocated in MSL, release it */ if (tag_enable && !provide_exif) { if (dest->data) { + __ta__( " Free data", free(dest->data); + ); dest->length = 0; dest->data = NULL; _mmcam_dbg_log("Jpeg is released!"); @@ -1458,12 +1111,17 @@ static void __mmcamcorder_image_capture_cb(GstElement *element, GstBuffer *buffe int pixtype = MM_PIXEL_FORMAT_INVALID; int pixtype_sub = MM_PIXEL_FORMAT_INVALID; int codectype = MM_IMAGE_CODEC_JPEG; - int type = _MMCamcorder_SINGLE_SHOT; int attr_index = 0; int count = 0; - int stop_cont_shot = 0; - gboolean send_msg = FALSE; + int stop_cont_shot = FALSE; + int tag_enable = FALSE; + int provide_exif = FALSE; + int capture_quality = 0; + int try_lock_count = 0; + gboolean send_captured_message = FALSE; + unsigned char *exif_raw_data = NULL; + MMCamcorderStateType current_state = MM_CAMCORDER_STATE_NONE; mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); _MMCamcorderImageInfo *info = NULL; _MMCamcorderSubContext *sc = NULL; @@ -1472,46 +1130,94 @@ static void __mmcamcorder_image_capture_cb(GstElement *element, GstBuffer *buffe MMCamcorderCaptureDataType scrnail = {0,}; mmf_attrs_t *attrs = NULL; - mmf_attribute_t *item = NULL; - - void *encoded_data = NULL; - char *err_attr_name = NULL; + mmf_attribute_t *item_screennail = NULL; + mmf_attribute_t *item_exif_raw_data = NULL; mmf_return_if_fail(hcamcorder); sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); - mmf_return_if_fail(sc && sc->info); + mmf_return_if_fail(sc && sc->info_image); - info = sc->info; + info = sc->info_image; - _mmcam_dbg_err("START"); + /* get current state */ + current_state = _mmcamcorder_get_state((MMHandleType)hcamcorder); + + _mmcam_dbg_err("START - current state %d", current_state); MMTA_ACUM_ITEM_BEGIN(" MSL capture callback", FALSE); /* check capture state */ if (info->type == _MMCamcorder_MULTI_SHOT && info->capture_send_count > 0) { mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL, "capture-break-cont-shot", &stop_cont_shot, NULL); - if (stop_cont_shot == TRUE) { - _mmcam_dbg_warn("capture stop command already come. skip this..."); - MMTA_ACUM_ITEM_END( " MSL capture callback", FALSE ); - goto error; - } } - if (!info->capturing) { - _mmcam_dbg_err("It's Not capturing now."); - goto error; + if (!info->capturing || stop_cont_shot) { + _mmcam_dbg_warn("stop command[%d] or not capturing state[%d]. skip this...", + stop_cont_shot, info->capturing); + + MMTA_ACUM_ITEM_END(" MSL capture callback", FALSE); + + /*free GstBuffer*/ + if (buffer1) { + gst_buffer_unref(buffer1); + } + if (buffer2) { + gst_buffer_unref(buffer2); + } + if (buffer3) { + gst_buffer_unref(buffer3); + } + + return; } - /* play capture sound here if multi capture */ - if (info->type == _MMCamcorder_MULTI_SHOT) { - _mmcamcorder_sound_play((MMHandleType)hcamcorder); + /* check command lock to block capture callback if capture start API is not returned + wait for 2 seconds at worst case */ + try_lock_count = 0; + do { + _mmcam_dbg_log("Try command LOCK"); + if (_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_log("command LOCK OK"); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + break; + } + + if (try_lock_count++ < TRY_LOCK_MAX_COUNT) { + _mmcam_dbg_warn("command LOCK Failed, retry...[count %d]", try_lock_count); + usleep(TRY_LOCK_TIME); + } else { + _mmcam_dbg_err("failed to lock command LOCK"); + break; + } + } while (TRUE); + + if (current_state < MM_CAMCORDER_STATE_RECORDING) { + /* play capture sound here if multi capture + or preview format is ITLV(because of AF and flash control in plugin) */ + if (info->type == _MMCamcorder_MULTI_SHOT) { + __ta__(" _mmcamcorder_sound_play", + _mmcamcorder_sound_play((MMHandleType)hcamcorder); + ); + } else if (!info->played_capture_sound) { + __ta__(" _mmcamcorder_sound_solo_play", + _mmcamcorder_sound_solo_play((MMHandleType)hcamcorder, _MMCAMCORDER_FILEPATH_CAPTURE_SND, FALSE); + ); + } } + /* init capture data */ + memset((void *)&dest, 0x0, sizeof(MMCamcorderCaptureDataType)); + memset((void *)&thumb, 0x0, sizeof(MMCamcorderCaptureDataType)); + memset((void *)&scrnail, 0x0, sizeof(MMCamcorderCaptureDataType)); + /* Prepare main, thumbnail buffer */ pixtype = _mmcamcorder_get_pixel_format(buffer1); if (pixtype == MM_PIXEL_FORMAT_INVALID) { _mmcam_dbg_err("Unsupported pixel type"); + + MMCAM_SEND_MESSAGE(hcamcorder, MM_MESSAGE_CAMCORDER_ERROR, MM_ERROR_CAMCORDER_INTERNAL); + goto error; } @@ -1520,47 +1226,114 @@ static void __mmcamcorder_image_capture_cb(GstElement *element, GstBuffer *buffe __mmcamcorder_get_capture_data_from_buffer(&dest, pixtype, buffer1); } else { _mmcam_dbg_err("buffer1 has wrong pointer. (buffer1=%p)",buffer1); + MMCAM_SEND_MESSAGE(hcamcorder, MM_MESSAGE_CAMCORDER_ERROR, MM_ERROR_CAMCORDER_INTERNAL); goto error; } /* Encode JPEG */ if (sc->internal_encode) { - int capture_quality = 0; - ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_attr_name, - MMCAM_IMAGE_ENCODER_QUALITY, &capture_quality, - NULL); - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_err("Get attribute failed[%s][%x]", err_attr_name, ret); - SAFE_FREE(err_attr_name); - goto error; - } - - __ta__(" _mmcamcorder_encode_jpeg", +#ifdef _MMCAMCORDER_MAKE_THUMBNAIL_INTERNAL_ENCODE + int thumb_width = 0; + int thumb_height = 0; + int thumb_length = 0; + unsigned char *thumb_raw_data = NULL; +#endif /* _MMCAMCORDER_MAKE_THUMBNAIL_INTERNAL_ENCODE */ + + mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL, + MMCAM_IMAGE_ENCODER_QUALITY, &capture_quality, + NULL); + _mmcam_dbg_log("Start Internal Encode - capture_quality %d", capture_quality); + + __ta__(" _mmcamcorder_encode_jpeg:MAIN", ret = _mmcamcorder_encode_jpeg(GST_BUFFER_DATA(buffer1), dest.width, dest.height, pixtype, dest.length, capture_quality, &(dest.data), &(dest.length)); ); - if (ret == FALSE) { + if (!ret) { + _mmcam_dbg_err("_mmcamcorder_encode_jpeg failed"); + + MMCAM_SEND_MESSAGE(hcamcorder, MM_MESSAGE_CAMCORDER_ERROR, MM_ERROR_CAMCORDER_INTERNAL); + goto error; } - encoded_data = dest.data; + /* set format */ dest.format = MM_PIXEL_FORMAT_ENCODED; - } - /* Thumbnail image buffer */ - if (buffer2 && GST_BUFFER_DATA(buffer2) && (GST_BUFFER_SIZE(buffer2) !=0)) { - pixtype_sub = _mmcamcorder_get_pixel_format(buffer2); - _mmcam_dbg_log("Thumnail (buffer2=%p)",buffer2); + _mmcam_dbg_log("Done Internal Encode - data %p, length %d", dest.data, dest.length); + +#ifdef _MMCAMCORDER_MAKE_THUMBNAIL_INTERNAL_ENCODE + /* make thumbnail image */ + _mmcam_dbg_log("Make thumbnail image"); + + if (dest.width > THUMBNAIL_WIDTH) { + float img_ratio = (float)dest.width / (float)dest.height; + + _mmcam_dbg_log("image ratio %f , default ratio %f", img_ratio, THUMBNAIL_DEFAULT_RATIO); + + if (img_ratio > THUMBNAIL_DEFAULT_RATIO) { + thumb_height = THUMBNAIL_HEIGHT; + thumb_width = (thumb_height * dest.width) / dest.height; + } else { + thumb_width = THUMBNAIL_WIDTH; + thumb_height = (thumb_width * dest.height) / dest.width; + } + + _mmcam_dbg_log("need to resize : thumbnail size %dx%d", thumb_width, thumb_height); + + if (!_mmcamcorder_resize_frame(GST_BUFFER_DATA(buffer1), dest.width, dest.height, GST_BUFFER_SIZE(buffer1), pixtype, + &thumb_raw_data, &thumb_width, &thumb_height, &thumb_length)) { + thumb_raw_data = NULL; + _mmcam_dbg_warn("_mmcamcorder_resize_frame failed. skip thumbnail making..."); + } + } else { + thumb_width = dest.width; + thumb_height = dest.height; + + _mmcam_dbg_log("NO need to resize : thumbnail size %dx%d", thumb_width, thumb_height); + + thumb_raw_data = GST_BUFFER_DATA(buffer1); + } + + if (thumb_raw_data) { + __ta__(" _mmcamcorder_encode_jpeg:THUMBNAIL", + ret = _mmcamcorder_encode_jpeg(thumb_raw_data, thumb_width, thumb_height, + pixtype, thumb_length, THUMBNAIL_JPEG_QUALITY, &(thumb.data), &(thumb.length)); + ); + if (ret) { + _mmcam_dbg_log("encode THUMBNAIL done - data %p, length %d", thumb.data, thumb.length); + + thumb.width = thumb_width; + thumb.height = thumb_height; + thumb.format = MM_PIXEL_FORMAT_ENCODED; + } else { + _mmcam_dbg_warn("failed to encode THUMBNAIL"); + } - __mmcamcorder_get_capture_data_from_buffer(&thumb, pixtype_sub, buffer2); + if (thumb_raw_data != GST_BUFFER_DATA(buffer1)) { + free(thumb_raw_data); + thumb_raw_data = NULL; + _mmcam_dbg_log("release thumb_raw_data"); + } + } else { + _mmcam_dbg_warn("thumb_raw_data is NULL"); + } +#endif /* _MMCAMCORDER_MAKE_THUMBNAIL_INTERNAL_ENCODE */ } else { - _mmcam_dbg_log("buffer2 has wrong pointer. Not Error. (buffer2=%p)",buffer2); + /* Thumbnail image buffer */ + if (buffer2 && GST_BUFFER_DATA(buffer2) && (GST_BUFFER_SIZE(buffer2) !=0)) { + _mmcam_dbg_log("Thumnail (buffer2=%p)",buffer2); + + pixtype_sub = _mmcamcorder_get_pixel_format(buffer2); + __mmcamcorder_get_capture_data_from_buffer(&thumb, pixtype_sub, buffer2); + } else { + _mmcam_dbg_log("buffer2 has wrong pointer. Not Error. (buffer2=%p)",buffer2); + } } /* Screennail image buffer */ attrs = (mmf_attrs_t*)MMF_CAMCORDER_ATTRS(hcamcorder); - mm_attrs_get_index((MMHandleType)attrs, "captured-screennail", &attr_index); - item = &attrs->items[attr_index]; + mm_attrs_get_index((MMHandleType)attrs, MMCAM_CAPTURED_SCREENNAIL, &attr_index); + item_screennail = &attrs->items[attr_index]; if (buffer3 && GST_BUFFER_DATA(buffer3) && GST_BUFFER_SIZE(buffer3) != 0) { _mmcam_dbg_log("Screennail (buffer3=%p,size=%d)", buffer3, GST_BUFFER_SIZE(buffer3)); @@ -1569,28 +1342,67 @@ static void __mmcamcorder_image_capture_cb(GstElement *element, GstBuffer *buffe __mmcamcorder_get_capture_data_from_buffer(&scrnail, pixtype_sub, buffer3); /* Set screennail attribute for application */ - mmf_attribute_set_data(item, &scrnail, sizeof(scrnail)); + ret = mmf_attribute_set_data(item_screennail, &scrnail, sizeof(scrnail)); + _mmcam_dbg_log("Screennail set attribute data %p, size %d, ret %x", &scrnail, sizeof(scrnail), ret); } else { - mmf_attribute_set_data(item, NULL, 0); - _mmcam_dbg_log("buffer3 has wrong pointer. Not Error. (buffer3=%p)",buffer3); + mmf_attribute_set_data(item_screennail, NULL, 0); } - mmf_attrs_commit_err((MMHandleType)attrs, &err_attr_name); + /* commit screennail data */ + mmf_attribute_commit(item_screennail); + + /* create EXIF info */ + __ta__(" mm_exif_create_exif_info", + ret = mm_exif_create_exif_info(&(hcamcorder->exif_info)); + ); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Failed to create exif_info [%x], but keep going...", ret); + } else { + /* add basic exif info */ + _mmcam_dbg_log("add basic exif info"); + __ta__(" __mmcamcorder_set_exif_basic_info", + ret = __mmcamcorder_set_exif_basic_info((MMHandleType)hcamcorder, dest.width, dest.height); + ); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_warn("Failed set_exif_basic_info [%x], but keep going...", ret); + ret = MM_ERROR_NONE; + } + } - /* Set extra data for jpeg */ - if (dest.format == MM_PIXEL_FORMAT_ENCODED) { - int err = 0; - char *err_attr_name = NULL; + /* get attribute item for EXIF data */ + mm_attrs_get_index((MMHandleType)attrs, MMCAM_CAPTURED_EXIF_RAW_DATA, &attr_index); + item_exif_raw_data = &attrs->items[attr_index]; - err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_attr_name, - MMCAM_IMAGE_ENCODER, &codectype, - NULL); - if (err != MM_ERROR_NONE) { - _mmcam_dbg_warn("Getting codectype failed. (%s:%x)", err_attr_name, err); - SAFE_FREE (err_attr_name); - goto error; + /* set EXIF data to attribute */ + if (hcamcorder->exif_info && hcamcorder->exif_info->data) { + exif_raw_data = (unsigned char *)malloc(hcamcorder->exif_info->size); + if (exif_raw_data) { + memcpy(exif_raw_data, hcamcorder->exif_info->data, hcamcorder->exif_info->size); + mmf_attribute_set_data(item_exif_raw_data, exif_raw_data, hcamcorder->exif_info->size); + _mmcam_dbg_log("set EXIF raw data %p, size %d", exif_raw_data, hcamcorder->exif_info->size); + } else { + _mmcam_dbg_warn("failed to alloc for EXIF, size %d", hcamcorder->exif_info->size); } + } else { + _mmcam_dbg_warn("failed to create EXIF. set EXIF as NULL"); + mmf_attribute_set_data(item_exif_raw_data, NULL, 0); + } + + /* commit EXIF data */ + mmf_attribute_commit(item_exif_raw_data); + + /* get tag-enable and provide-exif */ + mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL, MMCAM_TAG_ENABLE, &tag_enable, NULL); + MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "provide-exif", &provide_exif); + + /* Set extra data for JPEG if tag enabled and doesn't provide EXIF */ + if (dest.format == MM_PIXEL_FORMAT_ENCODED && + tag_enable && !provide_exif) { + mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL, + MMCAM_IMAGE_ENCODER, &codectype, + NULL); + _mmcam_dbg_log("codectype %d", codectype); switch (codectype) { case MM_IMAGE_CODEC_JPEG: @@ -1599,13 +1411,17 @@ static void __mmcamcorder_image_capture_cb(GstElement *element, GstBuffer *buffe __ta__( " __mmcamcorder_set_jpeg_data", ret = __mmcamcorder_set_jpeg_data((MMHandleType)hcamcorder, &dest, &thumb); ); - if (!ret) { + if (ret != MM_ERROR_NONE) { _mmcam_dbg_err("Error on setting extra data to jpeg"); + MMCAM_SEND_MESSAGE(hcamcorder, MM_MESSAGE_CAMCORDER_ERROR, ret); goto error; } break; default: _mmcam_dbg_err("The codectype is not supported. (%d)", codectype); + + MMCAM_SEND_MESSAGE(hcamcorder, MM_MESSAGE_CAMCORDER_ERROR, MM_ERROR_CAMCORDER_INTERNAL); + goto error; } } @@ -1625,41 +1441,60 @@ static void __mmcamcorder_image_capture_cb(GstElement *element, GstBuffer *buffe _mmcam_dbg_log("APPLICATION CALLBACK END"); } else { _mmcam_dbg_err("Capture callback is NULL."); + + MMCAM_SEND_MESSAGE(hcamcorder, MM_MESSAGE_CAMCORDER_ERROR, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + goto err_release_exif; } - /* Set send msg flag and capture count */ - send_msg = TRUE; - type = info->type; + /* Set capture count */ count = ++(info->capture_send_count); + send_captured_message = TRUE; err_release_exif: _MMCAMCORDER_UNLOCK_VCAPTURE_CALLBACK(hcamcorder); + /* init screennail and EXIF raw data */ + __ta__(" init attributes:scrnl and EXIF", + mmf_attribute_set_data(item_screennail, NULL, 0); + mmf_attribute_commit(item_screennail); + if (exif_raw_data) { + free(exif_raw_data); + exif_raw_data = NULL; + + mmf_attribute_set_data(item_exif_raw_data, NULL, 0); + mmf_attribute_commit(item_exif_raw_data); + } + ); + /* Release jpeg data */ if (pixtype == MM_PIXEL_FORMAT_ENCODED) { - __ta__( " __mmcamcorder_release_jpeg_data", + __ta__(" __mmcamcorder_release_jpeg_data", __mmcamcorder_release_jpeg_data((MMHandleType)hcamcorder, &dest); ); } error: /* Check end condition and set proper value */ - __mmcamcorder_init_stillshot_info((MMHandleType)hcamcorder); - - /* send captured message if no problem */ - if (send_msg) { - __mmcamcorder_capture_send_msg((MMHandleType)hcamcorder, type, count); + if (info->hdr_capture_mode != MM_CAMCORDER_HDR_ON_AND_ORIGINAL || + (info->hdr_capture_mode == MM_CAMCORDER_HDR_ON_AND_ORIGINAL && count == 2)) { + __mmcamcorder_init_stillshot_info((MMHandleType)hcamcorder); } /* release internal allocated data */ - if (encoded_data) { - if (dest.data == encoded_data) { + if (sc->internal_encode) { + if (dest.data) { + free(dest.data); dest.data = NULL; + dest.length = 0; + _mmcam_dbg_log("release internal encoded data MAIN"); + } + if (thumb.data) { + free(thumb.data); + thumb.data = NULL; + thumb.length = 0; + _mmcam_dbg_log("release internal encoded data THUMB"); } - - free(encoded_data); - encoded_data = NULL; } /*free GstBuffer*/ @@ -1673,6 +1508,33 @@ error: gst_buffer_unref(buffer3); } + /* destroy exif info */ + __ta__(" mm_exif_destory_exif_info", + mm_exif_destory_exif_info(hcamcorder->exif_info); + ); + hcamcorder->exif_info = NULL; + + /* send captured message */ + if (send_captured_message) { + MMTA_ACUM_ITEM_BEGIN(" CAPTURED MESSAGE DELAY", FALSE); + + if (info->hdr_capture_mode != MM_CAMCORDER_HDR_ON_AND_ORIGINAL) { + MMCamcorderStateType current_state = MM_CAMCORDER_STATE_NONE; + + mm_camcorder_get_state((MMHandleType)hcamcorder, ¤t_state); + + /* Send CAPTURED message and count - capture success */ + if (current_state >= MM_CAMCORDER_STATE_RECORDING) { + MMCAM_SEND_MESSAGE(hcamcorder, MM_MESSAGE_CAMCORDER_VIDEO_SNAPSHOT_CAPTURED, count); + } else { + MMCAM_SEND_MESSAGE(hcamcorder, MM_MESSAGE_CAMCORDER_CAPTURED, count); + } + } else if (info->hdr_capture_mode == MM_CAMCORDER_HDR_ON_AND_ORIGINAL && count == 2) { + /* send captured message only once in HDR and Original Capture mode */ + MMCAM_SEND_MESSAGE(hcamcorder, MM_MESSAGE_CAMCORDER_CAPTURED, 1); + } + } + MMTA_ACUM_ITEM_END( " MSL capture callback", FALSE ); _mmcam_dbg_err("END"); @@ -1730,7 +1592,7 @@ int _mmcamcorder_set_resize_property(MMHandleType handle, int capture_width, int } -int __mmcamcorder_set_exif_basic_info(MMHandleType handle) +int __mmcamcorder_set_exif_basic_info(MMHandleType handle, int image_width, int image_height) { int ret = MM_ERROR_NONE; int value; @@ -1742,7 +1604,9 @@ int __mmcamcorder_set_exif_basic_info(MMHandleType handle) double f_longitude = INVALID_GPS_VALUE; double f_altitude = INVALID_GPS_VALUE; char *str_value = NULL; +#ifdef WRITE_EXIF_MAKER_INFO /* FIXME */ char *maker = NULL; +#endif char *user_comment = NULL; char *err_name = NULL; ExifData *ed = NULL; @@ -1752,7 +1616,7 @@ int __mmcamcorder_set_exif_basic_info(MMHandleType handle) static ExifLong elong[10]; GstCameraControl *control = NULL; - GstCameraControlExifInfo avsys_exif_info = {0,}; + GstCameraControlExifInfo avsys_exif_info; mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); _MMCamcorderSubContext *sc = NULL; @@ -1764,17 +1628,22 @@ int __mmcamcorder_set_exif_basic_info(MMHandleType handle) sc = MMF_CAMCORDER_SUBCONTEXT(handle); mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + CLEAR(avsys_exif_info); + if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { - _mmcam_dbg_err("Can't cast Video source into camera control. Just return true."); - return MM_ERROR_NONE; + _mmcam_dbg_err("Can't cast Video source into camera control. Skip camera control values..."); + } else { + control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); + /* get device information */ + __ta__(" gst_camera_control_get_exif_info", + gst_camera_control_get_exif_info(control, &avsys_exif_info); + ); } - control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); - /* get device information */ - gst_camera_control_get_exif_info(control, &avsys_exif_info); - /* get ExifData from exif info */ + __ta__(" mm_exif_get_exif_from_info", ed = mm_exif_get_exif_from_info(hcamcorder->exif_info); + ); if (ed == NULL || ed->ifd == NULL) { _mmcam_dbg_err("get exif data error!!(%p, %p)", ed, (ed ? ed->ifd : NULL)); return MM_ERROR_INVALID_HANDLE; @@ -1793,7 +1662,7 @@ int __mmcamcorder_set_exif_basic_info(MMHandleType handle) } /*1. EXIF_TAG_IMAGE_WIDTH */ /*EXIF_TAG_PIXEL_X_DIMENSION*/ - mm_camcorder_get_attributes(handle, NULL, MMCAM_CAPTURE_WIDTH, &value, NULL); + value = image_width; exif_set_long((unsigned char *)&elong[cntl], exif_data_get_byte_order(ed), value); ret = mm_exif_set_add_entry(ed, EXIF_IFD_0, EXIF_TAG_IMAGE_WIDTH, @@ -1810,7 +1679,7 @@ int __mmcamcorder_set_exif_basic_info(MMHandleType handle) _mmcam_dbg_log("width[%d]", value); /*2. EXIF_TAG_IMAGE_LENGTH*/ /*EXIF_TAG_PIXEL_Y_DIMENSION*/ - mm_camcorder_get_attributes(handle, NULL, MMCAM_CAPTURE_HEIGHT, &value, NULL); + value = image_height; exif_set_long((unsigned char *)&elong[cntl], exif_data_get_byte_order (ed), value); ret = mm_exif_set_add_entry(ed, EXIF_IFD_0, EXIF_TAG_IMAGE_LENGTH, @@ -1880,6 +1749,7 @@ int __mmcamcorder_set_exif_basic_info(MMHandleType handle) free(b); } +#ifdef WRITE_EXIF_MAKER_INFO /* FIXME */ /*5. EXIF_TAG_MAKE */ maker = strdup(MM_MAKER_NAME); if (maker) { @@ -1912,7 +1782,7 @@ int __mmcamcorder_set_exif_basic_info(MMHandleType handle) } else { _mmcam_dbg_warn("failed to get model name"); } - +#endif /*6. EXIF_TAG_IMAGE_DESCRIPTION */ mm_camcorder_get_attributes(handle, NULL, MMCAM_TAG_IMAGE_DESCRIPTION, &str_value, &str_val_len, NULL); _mmcam_dbg_log("desctiption [%s]", str_value); @@ -1932,7 +1802,7 @@ int __mmcamcorder_set_exif_basic_info(MMHandleType handle) /*7. EXIF_TAG_SOFTWARE*/ /* - { + if (control != NULL) { char software[50] = {0,}; unsigned int len = 0; @@ -1946,10 +1816,9 @@ int __mmcamcorder_set_exif_basic_info(MMHandleType handle) } */ - /*8. EXIF_TAG_ORIENTATION */ + /*8. EXIF_TAG_ORIENTATION */ mm_camcorder_get_attributes(handle, NULL, MMCAM_TAG_ORIENTATION, &value, NULL); - - _mmcam_dbg_log("orientation [%d]",value); + _mmcam_dbg_log("get orientation [%d]",value); if (value == 0) { value = MM_EXIF_ORIENTATION; } @@ -1980,20 +1849,24 @@ int __mmcamcorder_set_exif_basic_info(MMHandleType handle) } /*9. EXIF_TAG_COLOR_SPACE */ - exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed), avsys_exif_info.colorspace); - ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_COLOR_SPACE, - EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); - if (ret != MM_ERROR_NONE) { - EXIF_SET_ERR(ret, EXIF_TAG_COLOR_SPACE); + if (control != NULL) { + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed), avsys_exif_info.colorspace); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_COLOR_SPACE, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_COLOR_SPACE); + } } /*10. EXIF_TAG_COMPONENTS_CONFIGURATION */ - config = avsys_exif_info.component_configuration; - _mmcam_dbg_log("EXIF_TAG_COMPONENTS_CONFIGURATION [%4x] ",config); - ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_COMPONENTS_CONFIGURATION, - EXIF_FORMAT_UNDEFINED, 4, (unsigned char *)&config); - if (ret != MM_ERROR_NONE) { - EXIF_SET_ERR(ret, EXIF_TAG_COMPONENTS_CONFIGURATION); + if (control != NULL) { + config = avsys_exif_info.component_configuration; + _mmcam_dbg_log("EXIF_TAG_COMPONENTS_CONFIGURATION [%4x] ",config); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_COMPONENTS_CONFIGURATION, + EXIF_FORMAT_UNDEFINED, 4, (unsigned char *)&config); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_COMPONENTS_CONFIGURATION); + } } /*11. EXIF_TAG_COMPRESSED_BITS_PER_PIXEL */ @@ -2001,6 +1874,7 @@ int __mmcamcorder_set_exif_basic_info(MMHandleType handle) /*12. EXIF_TAG_DATE_TIME_ORIGINAL */ /*13. EXIF_TAG_DATE_TIME_DIGITIZED*/ + /*14. EXIF_TAG_EXPOSURE_TIME*/ if (avsys_exif_info.exposure_time_numerator && avsys_exif_info.exposure_time_denominator) { unsigned char *b = NULL; @@ -2212,23 +2086,27 @@ int __mmcamcorder_set_exif_basic_info(MMHandleType handle) /* defualt : none */ /*24. EXIF_TAG_METERING_MODE */ - exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed),avsys_exif_info.metering_mode); - _mmcam_dbg_log("EXIF_TAG_METERING_MODE [%d]", avsys_exif_info.metering_mode); - ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_METERING_MODE, - EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); - if (ret != MM_ERROR_NONE) { - EXIF_SET_ERR(ret, EXIF_TAG_METERING_MODE); + if (control != NULL) { + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed),avsys_exif_info.metering_mode); + _mmcam_dbg_log("EXIF_TAG_METERING_MODE [%d]", avsys_exif_info.metering_mode); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_METERING_MODE, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_METERING_MODE); + } } /*25. EXIF_TAG_LIGHT_SOURCE*/ /*26. EXIF_TAG_FLASH*/ - exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order (ed),avsys_exif_info.flash); - _mmcam_dbg_log("EXIF_TAG_FLASH [%d]", avsys_exif_info.flash); - ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_FLASH, - EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); - if (ret != MM_ERROR_NONE) { - EXIF_SET_ERR(ret, EXIF_TAG_FLASH); + if (control != NULL) { + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order (ed),avsys_exif_info.flash); + _mmcam_dbg_log("EXIF_TAG_FLASH [%d]", avsys_exif_info.flash); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_FLASH, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_FLASH); + } } /*27. EXIF_TAG_FOCAL_LENGTH*/ @@ -2813,3 +2691,45 @@ exit: return ret; } + + +static void __sound_status_changed_cb(keynode_t* node, void *data) +{ + mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)data; + _MMCamcorderImageInfo *info = NULL; + + mmf_return_if_fail(hcamcorder && hcamcorder->sub_context && hcamcorder->sub_context->info_image); + + _mmcam_dbg_log("START"); + + info = hcamcorder->sub_context->info_image; + + __ta__(" GET_IN_CB:VCONFKEY_SETAPPL_SOUND_STATUS_BOOL", + vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &(info->sound_status)); + ); + + _mmcam_dbg_log("DONE : sound status %d", info->sound_status); + + return; +} + + +static void __volume_level_changed_cb(void *data) +{ + mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)data; + _MMCamcorderImageInfo *info = NULL; + + mmf_return_if_fail(hcamcorder && hcamcorder->sub_context && hcamcorder->sub_context->info_image); + + _mmcam_dbg_log("START"); + + info = hcamcorder->sub_context->info_image; + + __ta__(" GET_IN_CB:mm_sound_volume_get_value", + mm_sound_volume_get_value(VOLUME_TYPE_MEDIA, &info->volume_level); + ); + + _mmcam_dbg_log("DONE : volume level %d", info->volume_level); + + return; +} diff --git a/src/mm_camcorder_util.c b/src/mm_camcorder_util.c index 688cc31..ec32843 100644 --- a/src/mm_camcorder_util.c +++ b/src/mm_camcorder_util.c @@ -19,11 +19,9 @@ * */ -/*=========================================================================================== -| | -| INCLUDE FILES | -| | -========================================================================================== */ +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ #include #include #include @@ -31,15 +29,17 @@ #include "mm_camcorder_internal.h" #include "mm_camcorder_util.h" +#include -/*--------------------------------------------------------------------------- -| GLOBAL VARIABLE DEFINITIONS for internal | ----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS for internal | +-----------------------------------------------------------------------*/ + +/*----------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS for internal | +-----------------------------------------------------------------------*/ +#define TIME_STRING_MAX_LEN 64 -/*--------------------------------------------------------------------------- -| LOCAL VARIABLE DEFINITIONS for internal | ----------------------------------------------------------------------------*/ -#define TIME_STRING_MAX_LEN 64 #define FPUTC_CHECK(x_char, x_file)\ {\ if (fputc(x_char, x_file) == EOF) \ @@ -86,35 +86,51 @@ gint32 _mmcamcorder_double_to_fix(gdouble d_number) } // find top level tag only, do not use this function for finding sub level tags -gint _mmcamcorder_find_tag(FILE *f, guint32 tag_fourcc) +gint _mmcamcorder_find_tag(FILE *f, guint32 tag_fourcc, gboolean do_rewind) { guchar buf[8]; - rewind(f); + if (do_rewind) { + rewind(f); + } - while(fread(&buf, sizeof(guchar), 8, f)>0) - { - gulong buf_size = 0; - guint32 buf_fourcc = MMCAM_FOURCC(buf[4], buf[5],buf[6],buf[7]); + while (fread(&buf, sizeof(guchar), 8, f)>0) { + unsigned long long buf_size = 0; + unsigned int buf_fourcc = MMCAM_FOURCC(buf[4], buf[5], buf[6], buf[7]); - if(tag_fourcc == buf_fourcc) - { + if (tag_fourcc == buf_fourcc) { _mmcam_dbg_log("find tag : %c%c%c%c", MMCAM_FOURCC_ARGS(tag_fourcc)); - return 1; - } - else - { - _mmcam_dbg_log("skip [%c%c%c%c] tag", MMCAM_FOURCC_ARGS(buf_fourcc)); - buf_size = _mmcamcorder_get_container_size(buf); - if(fseek(f, buf_size-8, SEEK_CUR) != 0) - { - _mmcam_dbg_err("fseek() fail"); - return 0; - } + return TRUE; + } else { + _mmcam_dbg_log("skip [%c%c%c%c] tag", MMCAM_FOURCC_ARGS(buf_fourcc)); + + buf_size = (unsigned long long)_mmcamcorder_get_container_size(buf); + buf_size = buf_size - 8; /* include tag */ + + do { + if (buf_size > _MMCAMCORDER_MAX_INT) { + _mmcam_dbg_log("seek %d", _MMCAMCORDER_MAX_INT); + if (fseek(f, _MMCAMCORDER_MAX_INT, SEEK_CUR) != 0) { + _mmcam_dbg_err("fseek() fail"); + return FALSE; + } + + buf_size -= _MMCAMCORDER_MAX_INT; + } else { + _mmcam_dbg_log("seek %d", buf_size); + if (fseek(f, buf_size, SEEK_CUR) != 0) { + _mmcam_dbg_err("fseek() fail"); + return FALSE; + } + break; + } + } while (TRUE); } } + _mmcam_dbg_log("cannot find tag : %c%c%c%c", MMCAM_FOURCC_ARGS(tag_fourcc)); - return 0; + + return FALSE; } gboolean _mmcamcorder_update_size(FILE *f, gint64 prev_pos, gint64 curr_pos) @@ -241,21 +257,72 @@ gboolean _mmcamcorder_write_udta(FILE *f, _MMCamcorderLocationInfo info) } -gulong _mmcamcorder_get_container_size(const guchar *size) +guint64 _mmcamcorder_get_container_size(const guchar *size) { - gulong result = 0; - gulong temp = 0; + 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]; + result = result | size[3]; + + _mmcam_dbg_log("result : %lld", (unsigned long long)result); + return result; } +gboolean _mmcamcorder_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_CAMCORDER_TAG_ORT_0R_VR_0C_VT:/* 90 degree */ + a = 0; + b = 0x00010000; + c = 0xffff0000; + d = 0; + break; + case MM_CAMCORDER_TAG_ORT_0R_VB_0C_VR:/* 180 degree */ + a = 0xffff0000; + d = 0xffff0000; + break; + case MM_CAMCORDER_TAG_ORT_0R_VL_0C_VB:/* 270 degree */ + a = 0; + b = 0xffff0000; + c = 0x00010000; + d = 0; + break; + case MM_CAMCORDER_TAG_ORT_0R_VT_0C_VL:/* 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); + + _mmcam_dbg_log("orientation : %d, write data 0x%x 0x%x 0x%x 0x%x", + orientation, a, b, c, d); + + return TRUE; +} + + int _mmcamcorder_get_freespace(const gchar *path, guint64 *free_space) { struct statfs fs; @@ -547,6 +614,7 @@ void _mmcamcorder_remove_all_handlers(MMHandleType handle, _MMCamcorderHandlerC _mmcam_dbg_log("LEAVE"); } + void _mmcamcorder_element_release_noti(gpointer data, GObject *where_the_object_was) { int i=0; @@ -554,10 +622,8 @@ void _mmcamcorder_element_release_noti(gpointer data, GObject *where_the_object_ mmf_return_if_fail(sc); mmf_return_if_fail(sc->element); - for(i=0;i< _MMCamcorder_PIPELINE_ELEMENT_NUM; i++) - { - if(sc->element[i].gst && (G_OBJECT(sc->element[i].gst) == where_the_object_was)) - { + for (i = 0 ; i < _MMCamcorder_PIPELINE_ELEMENT_NUM ; i++) { + if (sc->element[i].gst && (G_OBJECT(sc->element[i].gst) == where_the_object_was)) { _mmcam_dbg_log("The element[%d][%p] is finalized", sc->element[i].id, sc->element[i].gst); sc->element[i].gst = NULL; sc->element[i].id = _MMCAMCORDER_NONE; @@ -570,33 +636,54 @@ void _mmcamcorder_element_release_noti(gpointer data, GObject *where_the_object_ gboolean _mmcamcroder_msg_callback(void *data) { - _MMCamcorderMsgItem * item = (_MMCamcorderMsgItem*)data; - mmf_camcorder_t *hcamcorder= NULL; - mmf_return_val_if_fail( item, FALSE ); - + _MMCamcorderMsgItem *item = (_MMCamcorderMsgItem*)data; + mmf_camcorder_t *hcamcorder = NULL; + mmf_return_val_if_fail(item, FALSE); + hcamcorder = MMF_CAMCORDER(item->handle); - mmf_return_val_if_fail( hcamcorder, FALSE ); + mmf_return_val_if_fail(hcamcorder, FALSE); -// _mmcam_dbg_log("msg id:%x, msg_cb:%p, msg_data:%p, item:%p", item->id, hcamcorder->msg_cb, hcamcorder->msg_data, item); + /*_mmcam_dbg_log("msg id:%x, msg_cb:%p, msg_data:%p, item:%p", item->id, hcamcorder->msg_cb, hcamcorder->msg_data, item);*/ - _MMCAMCORDER_LOCK_MESSAGE_CALLBACK( hcamcorder ); + _MMCAMCORDER_LOCK_MESSAGE_CALLBACK(hcamcorder); + + /* check delay of CAPTURED message */ + if (item->id == MM_MESSAGE_CAMCORDER_CAPTURED) { + MMTA_ACUM_ITEM_END(" CAPTURED MESSAGE DELAY", FALSE); + } if ((hcamcorder) && (hcamcorder->msg_cb)) { hcamcorder->msg_cb(item->id, (MMMessageParamType*)(&(item->param)), hcamcorder->msg_cb_param); } - _MMCAMCORDER_UNLOCK_MESSAGE_CALLBACK( hcamcorder ); + _MMCAMCORDER_UNLOCK_MESSAGE_CALLBACK(hcamcorder); _MMCAMCORDER_LOCK((MMHandleType)hcamcorder); - - if (hcamcorder->msg_data) + + if (hcamcorder->msg_data) { hcamcorder->msg_data = g_list_remove(hcamcorder->msg_data, item); + } + + /* release allocated memory */ + if (item->id == MM_MESSAGE_CAMCORDER_FACE_DETECT_INFO) { + MMCamFaceDetectInfo *cam_fd_info = (MMCamFaceDetectInfo *)item->param.data; + if (cam_fd_info) { + SAFE_FREE(cam_fd_info->face_info); + free(cam_fd_info); + cam_fd_info = NULL; + } - SAFE_FREE(item); + item->param.data = NULL; + item->param.size = 0; + } + + free(item); + item = NULL; _MMCAMCORDER_UNLOCK((MMHandleType)hcamcorder); - return FALSE; //For not being called again + /* For not being called again */ + return FALSE; } @@ -630,6 +717,8 @@ _mmcamcroder_send_message(MMHandleType handle, _MMCamcorderMsgItem *data) case MM_MESSAGE_CAMCORDER_ERROR: case MM_MESSAGE_CAMCORDER_FOCUS_CHANGED: case MM_MESSAGE_CAMCORDER_CAPTURED: + case MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED: + case MM_MESSAGE_CAMCORDER_AUDIO_CAPTURED: case MM_MESSAGE_READY_TO_RESUME: default: data->param.union_type = MM_MSG_UNION_CODE; @@ -696,6 +785,12 @@ _mmcamcroder_remove_message_all(MMHandleType handle) hcamcorder->msg_data = NULL; } + /* remove idle function for playing capture sound */ + do { + ret = g_idle_remove_by_data(hcamcorder); + _mmcam_dbg_log("remove idle function for playing capture sound. ret[%d]", ret); + } while (ret); + _MMCAMCORDER_UNLOCK(handle); return; @@ -837,9 +932,16 @@ unsigned int _mmcamcorder_get_fourcc(int pixtype, int codectype, int use_zero_co 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: - _mmcam_dbg_log("Not proper pixel type. Set default."); - fourcc = GST_MAKE_FOURCC ('S', '4', '2', '0'); + _mmcam_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; } @@ -895,6 +997,10 @@ int _mmcamcorder_get_pixtype(unsigned int fourcc) 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: _mmcam_dbg_log("Not supported fourcc type(%x)", fourcc); pixtype = MM_PIXEL_FORMAT_INVALID; @@ -979,12 +1085,87 @@ _mmcamcorder_link_elements( GList *element_list ) } +gboolean _mmcamcorder_resize_frame(unsigned char *src_data, int src_width, int src_height, int src_length, int src_format, + unsigned char **dst_data, int *dst_width, int *dst_height, int *dst_length) +{ + int ret = TRUE; + int mm_ret = MM_ERROR_NONE; + int input_format = MM_UTIL_IMG_FMT_YUV420; + unsigned char *dst_tmp_data = NULL; + + if (!src_data || !dst_data || !dst_width || !dst_height || !dst_length) { + _mmcam_dbg_err("something is NULL %p,%p,%p,%p,%p", + src_data, dst_data, dst_width, dst_height, dst_length); + return FALSE; + } + + /* set input format for mm-util */ + switch (src_format) { + case MM_PIXEL_FORMAT_I420: + input_format = MM_UTIL_IMG_FMT_I420; + break; + case MM_PIXEL_FORMAT_YV12: + input_format = MM_UTIL_IMG_FMT_YUV420; + break; + case MM_PIXEL_FORMAT_NV12: + input_format = MM_UTIL_IMG_FMT_NV12; + break; + case MM_PIXEL_FORMAT_YUYV: + input_format = MM_UTIL_IMG_FMT_YUYV; + break; + case MM_PIXEL_FORMAT_UYVY: + input_format = MM_UTIL_IMG_FMT_UYVY; + break; + default: + _mmcam_dbg_err("NOT supported format", src_format); + return FALSE; + } + + _mmcam_dbg_log("src size %dx%d -> dst size %dx%d", + src_width, src_height, *dst_width, *dst_height); + + /* get length of resized image */ + __ta__(" mm_util_get_image_size 2", + mm_ret = mm_util_get_image_size(input_format, *dst_width, *dst_height, dst_length); + ); + if (mm_ret != MM_ERROR_NONE) { + GST_ERROR("mm_util_get_image_size failed 0x%x", ret); + return FALSE; + } + + _mmcam_dbg_log("dst_length : %d", *dst_length); + + dst_tmp_data = (unsigned char *)malloc(*dst_length); + if (dst_tmp_data == NULL) { + _mmcam_dbg_err("failed to alloc dst_thumb_size(size %d)", *dst_length); + return FALSE; + } + + __ta__(" mm_util_resize_image", + mm_ret = mm_util_resize_image(src_data, src_width, src_height, input_format, + dst_tmp_data, dst_width, dst_height); + ); + if (mm_ret != MM_ERROR_NONE) { + GST_ERROR("mm_util_resize_image failed 0x%x", ret); + free(dst_tmp_data); + return FALSE; + } + + *dst_data = dst_tmp_data; + + _mmcam_dbg_log("resize done %p, %dx%d", *dst_data, *dst_width, *dst_height); + + return TRUE; +} + + gboolean _mmcamcorder_encode_jpeg(void *src_data, unsigned int src_width, unsigned int src_height, int src_format, unsigned int src_length, unsigned int jpeg_quality, void **result_data, unsigned int *result_length) { int ret = 0; int i = 0; + int enc_type = JPEG_ENCODER_SOFTWARE; guint32 src_fourcc = 0; gboolean do_encode = FALSE; jpegenc_parameter enc_param; @@ -1006,8 +1187,30 @@ gboolean _mmcamcorder_encode_jpeg(void *src_data, unsigned int src_width, unsign src_fourcc = _mmcamcorder_get_fourcc(src_format, 0, FALSE); camsrcjpegenc_get_src_fmt(src_fourcc, &(enc_param.src_fmt)); - if (enc_param.src_fmt != COLOR_FORMAT_NOT_SUPPORT && - enc_info.sw_support == TRUE) { + if (enc_param.src_fmt == COLOR_FORMAT_NOT_SUPPORT) { + _mmcam_dbg_err("Not Supported FOURCC(format:%d)", src_format); + return FALSE; + } + + /* check H/W encoder */ + if (enc_info.hw_support) { + _mmcam_dbg_log("check H/W encoder supported format list"); + /* Check supported format */ + for (i = 0 ; i < enc_info.hw_enc.input_fmt_num ; i++) { + if (enc_param.src_fmt == enc_info.hw_enc.input_fmt_list[i]) { + do_encode = TRUE; + break; + } + } + + if (do_encode) { + enc_type = JPEG_ENCODER_HARDWARE; + } + } + + /* check S/W encoder */ + if (!do_encode && enc_info.sw_support) { + _mmcam_dbg_log("check S/W encoder supported format list"); /* Check supported format */ for (i = 0 ; i < enc_info.sw_enc.input_fmt_num ; i++) { if (enc_param.src_fmt == enc_info.sw_enc.input_fmt_list[i]) { @@ -1017,36 +1220,41 @@ gboolean _mmcamcorder_encode_jpeg(void *src_data, unsigned int src_width, unsign } if (do_encode) { - enc_param.src_data = src_data; - enc_param.width = src_width; - enc_param.height = src_height; - enc_param.src_len = src_length; - enc_param.jpeg_mode = JPEG_MODE_BASELINE; - enc_param.jpeg_quality = jpeg_quality; - - __ta__(" camsrcjpegenc_encode", - ret = camsrcjpegenc_encode(&enc_info, JPEG_ENCODER_SOFTWARE, &enc_param ); - ); - if (ret == CAMSRC_JPEGENC_ERROR_NONE) { - *result_data = enc_param.result_data; - *result_length = enc_param.result_len; - - _mmcam_dbg_log("JPEG encode length(%d)", *result_length); - - return TRUE; - } else { - _mmcam_dbg_err("camsrcjpegenc_encode failed(%x)", ret); - return FALSE; - } + enc_type = JPEG_ENCODER_SOFTWARE; + } + } + + if (do_encode) { + enc_param.src_data = src_data; + enc_param.width = src_width; + enc_param.height = src_height; + enc_param.src_len = src_length; + enc_param.jpeg_mode = JPEG_MODE_BASELINE; + enc_param.jpeg_quality = jpeg_quality; + + _mmcam_dbg_log("%ux%u, size %u, quality %u, type %d", + src_width, src_height, src_length, + jpeg_quality, enc_type); + + __ta__(" camsrcjpegenc_encode", + ret = camsrcjpegenc_encode(&enc_info, enc_type, &enc_param ); + ); + if (ret == CAMSRC_JPEGENC_ERROR_NONE) { + *result_data = enc_param.result_data; + *result_length = enc_param.result_len; + + _mmcam_dbg_log("JPEG encode length(%d)", *result_length); + + return TRUE; } else { - _mmcam_dbg_err("S/W JPEG codec does NOT support format [%d]", src_format); + _mmcam_dbg_err("camsrcjpegenc_encode failed(%x)", ret); return FALSE; } - } else { - _mmcam_dbg_err("Not Supported FOURCC(format:%d) or There is NO S/W encoder(%d)", - src_format, enc_info.sw_support); - return FALSE; } + + _mmcam_dbg_err("No encoder supports %d format", src_format); + + return FALSE; } diff --git a/src/mm_camcorder_videorec.c b/src/mm_camcorder_videorec.c index 631f389..e728bef 100644 --- a/src/mm_camcorder_videorec.c +++ b/src/mm_camcorder_videorec.c @@ -22,6 +22,7 @@ /*======================================================================================= | INCLUDE FILES | =======================================================================================*/ +#include #include "mm_camcorder_internal.h" #include "mm_camcorder_videorec.h" @@ -29,14 +30,16 @@ | GLOBAL VARIABLE DEFINITIONS for internal | ---------------------------------------------------------------------------------------*/ #define _MMCAMCORDER_LOCATION_INFO // for add gps information +#define MAX_ERROR_MESSAGE_LEN 128 /*--------------------------------------------------------------------------------------- | LOCAL VARIABLE DEFINITIONS for internal | ---------------------------------------------------------------------------------------*/ -#define _MMCAMCORDER_MINIMUM_FRAME 10 +#define _MMCAMCORDER_MINIMUM_FRAME 3 #define _MMCAMCORDER_RETRIAL_COUNT 10 #define _MMCAMCORDER_FRAME_WAIT_TIME 200000 /* ms */ #define _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL 5 +#define _OFFSET_COMPOSITION_MATRIX 40L /*--------------------------------------------------------------------------------------- | LOCAL FUNCTION PROTOTYPES: | @@ -45,7 +48,7 @@ static gboolean __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstBuffer *buffer, gpointer u_data); static gboolean __mmcamcorder_video_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data); static gboolean __mmcamcorder_audioque_dataprobe(GstPad *pad, GstBuffer *buffer, gpointer u_data); -static gboolean __mmcamcorder_video_dataprobe_slow(GstPad *pad, GstBuffer *buffer, gpointer u_data); +static gboolean __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstBuffer *buffer, gpointer u_data); static gboolean __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstBuffer *buffer, gpointer u_data); static gboolean __mmcamcorder_add_locationinfo(MMHandleType handle, int fileformat); static gboolean __mmcamcorder_add_locationinfo_mp4(MMHandleType handle); @@ -60,6 +63,7 @@ static gboolean __mmcamcorder_eventprobe_monitor(GstPad *pad, GstEvent *event, g int _mmcamcorder_add_recorder_pipeline(MMHandleType handle) { int err = MM_ERROR_NONE; + int audio_disable = FALSE; char* gst_element_rsink_name = NULL; GstPad *srcpad = NULL; @@ -91,7 +95,20 @@ int _mmcamcorder_add_recorder_pipeline(MMHandleType handle) goto pipeline_creation_error; } - if (sc->is_slow == FALSE) { + /* get audio disable */ + mm_camcorder_get_attributes(handle, NULL, + MMCAM_AUDIO_DISABLE, &audio_disable, + NULL); + + if (sc->is_modified_rate || audio_disable) { + sc->audio_disable = TRUE; + } else { + sc->audio_disable = FALSE; + } + _mmcam_dbg_log("AUDIO DISABLE : %d (is_modified_rate %d, audio_disable %d)", + sc->audio_disable, sc->is_modified_rate, audio_disable); + + if (sc->audio_disable == FALSE) { /* Sub pipeline */ __ta__(" __mmcamcorder_create_audiosrc_bin", err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder); @@ -105,7 +122,7 @@ int _mmcamcorder_add_recorder_pipeline(MMHandleType handle) } __ta__(" _mmcamcorder_create_encodesink_bin", - err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder); + err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder, MM_CAMCORDER_ENCBIN_PROFILE_VIDEO); ); if (err != MM_ERROR_NONE) { return err; @@ -119,7 +136,7 @@ int _mmcamcorder_add_recorder_pipeline(MMHandleType handle) sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0"); _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error); - if (sc->is_slow == FALSE) { + if (sc->audio_disable == FALSE) { srcpad = gst_element_get_static_pad (sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, "src"); sinkpad = gst_element_get_static_pad (sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, "audio_sink0"); _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error); @@ -137,7 +154,7 @@ int _mmcamcorder_add_recorder_pipeline(MMHandleType handle) /* set data probe function for audio */ - if (sc->is_slow == FALSE) { + if (sc->audio_disable == FALSE) { sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "sink"); MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC, __mmcamcorder_audioque_dataprobe, hcamcorder); @@ -168,10 +185,10 @@ int _mmcamcorder_add_recorder_pipeline(MMHandleType handle) srcpad = NULL; } - if (sc->is_slow) { + if (sc->audio_disable) { sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "sink"); MMCAMCORDER_ADD_BUFFER_PROBE(sinkpad, _MMCAMCORDER_HANDLER_VIDEOREC, - __mmcamcorder_video_dataprobe_slow, hcamcorder); + __mmcamcorder_video_dataprobe_audio_disable, hcamcorder); gst_object_unref(sinkpad); sinkpad = NULL; } @@ -331,15 +348,16 @@ int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle) _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC); - ret = _mmcamcorder_remove_encoder_pipeline(handle); + /* remove audio pipeline first */ + ret = _mmcamcorder_remove_audio_pipeline(handle); if (ret != MM_ERROR_NONE) { - _mmcam_dbg_err("Fail to remove encoder pipeline"); + _mmcam_dbg_err("Fail to remove audio pipeline"); return ret; } - ret = _mmcamcorder_remove_audio_pipeline(handle); + ret = _mmcamcorder_remove_encoder_pipeline(handle); if (ret != MM_ERROR_NONE) { - _mmcam_dbg_err("Fail to remove audio pipeline"); + _mmcam_dbg_err("Fail to remove encoder pipeline"); return ret; } @@ -387,11 +405,11 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) int size = 0; int fileformat = 0; int ret = MM_ERROR_NONE; + double motion_rate = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE; char *temp_filename = NULL; char *err_name = NULL; gint fps = 0; - gint slow_fps = 0; GstElement *pipeline = NULL; GstPad *pad = NULL; @@ -403,10 +421,10 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) sc = MMF_CAMCORDER_SUBCONTEXT(handle); mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - mmf_return_val_if_fail(sc->info, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED); mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - info = sc->info; + info = sc->info_video; _mmcam_dbg_log("Command(%d)", command); @@ -416,6 +434,7 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) case _MMCamcorder_CMD_RECORD: { if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) { + guint imax_size = 0; guint imax_time = 0; /* Play record start sound */ @@ -424,6 +443,12 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) /* Recording */ _mmcam_dbg_log("Record Start"); + /* set hybrid mode when ITLV format */ + if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ITLV_JPEG_UYVY) { + _mmcam_dbg_log("flush cache TRUE"); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "flush-cache", TRUE); + } + ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED); if (ret != MM_ERROR_NONE) { goto _ERR_CAMCORDER_VIDEO_COMMAND; @@ -444,9 +469,10 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) ret = mm_camcorder_get_attributes(handle, &err_name, MMCAM_CAMERA_FPS, &fps, - "camera-slow-motion-fps", &slow_fps, + MMCAM_CAMERA_RECORDING_MOTION_RATE, &motion_rate, MMCAM_FILE_FORMAT, &fileformat, MMCAM_TARGET_FILENAME, &temp_filename, &size, + MMCAM_TARGET_MAX_SIZE, &imax_size, MMCAM_TARGET_TIME_LIMIT, &imax_time, MMCAM_FILE_FORMAT, &(info->fileformat), NULL); @@ -456,6 +482,13 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) goto _ERR_CAMCORDER_VIDEO_COMMAND; } + /* 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 */ @@ -463,10 +496,13 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */ } - if (sc->is_slow) { - info->multiple_fps = fps/slow_fps; - _mmcam_dbg_log("high speed recording fps:%d,slow_fps:%d,multiple_fps:%d", - fps, slow_fps, info->multiple_fps); + if (sc->is_modified_rate) { + info->record_timestamp_ratio = (_MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE/motion_rate); + _mmcam_dbg_log("high speed recording fps:%d, slow_rate:%f, timestamp_ratio:%f", + fps, motion_rate, info->record_timestamp_ratio); + } else { + info->record_timestamp_ratio = _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE; + _mmcam_dbg_log("normal recording"); } MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", TRUE); @@ -568,7 +604,7 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) } for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) { - if (sc->is_slow) { + if (sc->audio_disable) { /* check only video frame */ if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) { break; @@ -610,18 +646,13 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) return MM_ERROR_CAMCORDER_CMD_IS_RUNNING; } - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE); - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", FALSE); - - if (sc->now_continuous_af) { - sc->now_continuous_af = FALSE; - _mmcam_dbg_log("Set now_continuous_af as FALSE when CANCEL recording"); - } + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", FALSE); __ta__(" _MMCamcorder_CMD_CANCEL:GST_STATE_READY", ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY); ); - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); if (ret != MM_ERROR_NONE) { goto _ERR_CAMCORDER_VIDEO_COMMAND; } @@ -647,13 +678,17 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) info->audio_frame_count = 0; info->filesize =0; + /* set flush cache as FALSE */ + if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ITLV_JPEG_UYVY) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "flush-cache", FALSE); + } + __ta__(" _MMCamcorder_CMD_CANCEL:GST_STATE_PLAYING", ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); ); if (ret != MM_ERROR_NONE) { goto _ERR_CAMCORDER_VIDEO_COMMAND; } - break; } case _MMCamcorder_CMD_COMMIT: @@ -669,7 +704,7 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) } for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) { - if (sc->is_slow) { + if (sc->audio_disable) { /* check only video frame */ if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) { break; @@ -705,11 +740,6 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", FALSE); - if (sc->now_continuous_af) { - sc->now_continuous_af = FALSE; - _mmcam_dbg_log("Set now_continuous_af as FALSE when COMMIT recording"); - } - if (sc->error_occurs) { GstPad *video= NULL; GstPad *audio = NULL; @@ -729,7 +759,7 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) _mmcam_dbg_err("Sending EOS video encoder src pad : %d", ret); gst_object_unref(video); - if (!sc->is_slow) { + if (sc->audio_disable == FALSE) { audio = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "src"); gst_pad_push_event (audio, gst_event_new_flush_start()); gst_pad_push_event (audio, gst_event_new_flush_stop()); @@ -766,50 +796,17 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) /* Wait EOS */ _mmcam_dbg_log("Start to wait EOS"); ret =_mmcamcorder_get_eos_message(handle); - if (ret != MM_ERROR_NONE) { - goto _ERR_CAMCORDER_VIDEO_COMMAND; - } - } - break; - case _MMCamcorder_CMD_PREVIEW_START: - { - int fps_auto = 0; - _mmcamcorder_vframe_stablize((MMHandleType)hcamcorder); - - /* sc */ - sc->display_interval = 0; - sc->previous_slot_time = 0; - - mm_camcorder_get_attributes(handle, NULL, MMCAM_CAMERA_FPS_AUTO, &fps_auto, NULL); - - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "fps-auto", fps_auto); - - __ta__(" _MMCamcorder_CMD_PREVIEW_START:GST_STATE_PLAYING", - ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); - ); - if (ret != MM_ERROR_NONE) { - goto _ERR_CAMCORDER_VIDEO_COMMAND; + /* set flush cache as FALSE */ + if (sc->info_image->preview_format == MM_PIXEL_FORMAT_ITLV_JPEG_UYVY) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "flush-cache", FALSE); } - /* I place this function last because it miscalculates a buffer that sents in GST_STATE_PAUSED */ - _mmcamcorder_video_current_framerate_init(handle); - } - break; - case _MMCamcorder_CMD_PREVIEW_STOP: - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE); - ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_READY); - MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); if (ret != MM_ERROR_NONE) { + info->b_commiting = FALSE; goto _ERR_CAMCORDER_VIDEO_COMMAND; } - - if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) { - int op_status = 0; - MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "operation-status", &op_status); - _mmcam_dbg_err("Current Videosrc status[0x%x]", op_status); - } - + } break; default: ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT; @@ -833,9 +830,6 @@ int _mmcamcorder_video_handle_eos(MMHandleType handle) { int ret = MM_ERROR_NONE; int enabletag = 0; - int camcorder_rotate = MM_VIDEO_INPUT_ROTATION_NONE; - int camera_rotate = MM_VIDEO_INPUT_ROTATION_NONE; - int display_rotate = MM_DISPLAY_ROTATION_NONE; guint64 file_size = 0; GstPad *pad = NULL; @@ -851,9 +845,9 @@ int _mmcamcorder_video_handle_eos(MMHandleType handle) sc = MMF_CAMCORDER_SUBCONTEXT(handle); mmf_return_val_if_fail(sc, FALSE); - mmf_return_val_if_fail(sc->info, FALSE); + mmf_return_val_if_fail(sc->info_video, FALSE); - info = sc->info; + info = sc->info_video; _mmcam_dbg_err(""); @@ -865,15 +859,19 @@ int _mmcamcorder_video_handle_eos(MMHandleType handle) MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE); + mm_camcorder_get_attributes(handle, NULL, + MMCAM_TAG_ENABLE, &enabletag, + NULL); + _mmcam_dbg_log("Set state of pipeline as PAUSED"); __ta__(" _MMCamcorder_CMD_COMMIT:GST_STATE_PAUSED", ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED); ); if (ret != MM_ERROR_NONE) { - _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:GST_STATE_PAUSED failed. error[%x]", ret); + _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:GST_STATE_READY or PAUSED failed. error[%x]", ret); } - MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); __ta__(" _MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline", ret = _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder); @@ -893,31 +891,35 @@ int _mmcamcorder_video_handle_eos(MMHandleType handle) } } - /* Recovering camera-rotation and display-rotation when start recording */ - if (camcorder_rotate != camera_rotate && - camera_rotate < MM_VIDEO_INPUT_ROTATION_FLIP_HORZ) { - _mmcamcorder_set_videosrc_rotation(handle, camera_rotate); - _mmcamcorder_set_display_rotation(handle, display_rotate); - _mmcam_dbg_log("## Recovering camcorder rotation is done. camcorder_rotate=%d, camera_rotate=%d, display_rotate=%d", - camcorder_rotate,camera_rotate,display_rotate); - } else { - _mmcam_dbg_log("## No need to recover camcorder rotation. camcorder_rotate=%d, camera_rotate=%d, display_rotate=%d", - camcorder_rotate,camera_rotate,display_rotate); - - /* Flush EOS event to avoid pending pipeline */ - pad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "sink"); - gst_pad_push_event(pad, gst_event_new_flush_start()); - gst_pad_push_event(pad, gst_event_new_flush_stop()); - gst_object_unref(pad); - pad = NULL; - - pad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "src"); - gst_pad_push_event(pad, gst_event_new_flush_start()); - gst_pad_push_event(pad, gst_event_new_flush_stop()); - gst_object_unref(pad); - pad = NULL; + /* Check file size */ + if (info->max_size > 0) { + _mmcamcorder_get_file_size(info->filename, &file_size); + _mmcam_dbg_log("MAX size %lld byte - created filesize %lld byte", + info->max_size, file_size); + + if (file_size > info->max_size) { + _MMCamcorderMsgItem message; + _mmcam_dbg_err("File size is greater than max size !!"); + message.id = MM_MESSAGE_CAMCORDER_ERROR; + message.param.code = MM_ERROR_CAMCORDER_FILE_SIZE_OVER; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &message); + } } + /* Flush EOS event to avoid pending pipeline */ + _mmcam_dbg_log("Flush EOS event"); + pad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "sink"); + gst_pad_push_event(pad, gst_event_new_flush_start()); + gst_pad_push_event(pad, gst_event_new_flush_stop()); + gst_object_unref(pad); + pad = NULL; + + pad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "src"); + gst_pad_push_event(pad, gst_event_new_flush_start()); + gst_pad_push_event(pad, gst_event_new_flush_stop()); + gst_object_unref(pad); + pad = NULL; + _mmcam_dbg_log("Set state as PLAYING"); __ta__(" _MMCamcorder_CMD_COMMIT:GST_STATE_PLAYING", ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); @@ -941,7 +943,7 @@ int _mmcamcorder_video_handle_eos(MMHandleType handle) } /* Send recording report to application */ - msg.id = MM_MESSAGE_CAMCORDER_CAPTURED; + msg.id = MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED; report = (MMCamRecordingReport *)malloc(sizeof(MMCamRecordingReport)); if (!report) { _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename); @@ -974,6 +976,7 @@ int _mmcamcorder_video_handle_eos(MMHandleType handle) return TRUE; } + /** * This function is record video data probing function. * If this function is linked with certain pad by gst_pad_add_buffer_probe(), @@ -1022,14 +1025,14 @@ static gboolean __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstBuffer *buff { mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); _MMCamcorderSubContext *sc = NULL; - _MMCamcorderVideoInfo * info = NULL; + _MMCamcorderVideoInfo *info = NULL; mmf_return_val_if_fail(hcamcorder, TRUE); mmf_return_val_if_fail(buffer, FALSE); sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); - mmf_return_val_if_fail(sc && sc->info, TRUE); - info = sc->info; + mmf_return_val_if_fail(sc && sc->info_video, TRUE); + info = sc->info_video; /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/ @@ -1072,8 +1075,8 @@ static gboolean __mmcamcorder_video_dataprobe_record(GstPad *pad, GstBuffer *buf mmf_return_val_if_fail(buffer, FALSE); sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); - mmf_return_val_if_fail(sc && sc->info, TRUE); - info = sc->info; + mmf_return_val_if_fail(sc && sc->info_video, TRUE); + info = sc->info_video; /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/ if (sc->ferror_send) { @@ -1091,17 +1094,6 @@ static gboolean __mmcamcorder_video_dataprobe_record(GstPad *pad, GstBuffer *buf buffer_size = GST_BUFFER_SIZE(buffer); - if (sc->now_continuous_af) { - _mmcam_dbg_log("Start continuous AF when START recording"); - __ta__(" _MMCamcorder_CMD_RECORD:START CAF", - ret = _mmcamcorder_adjust_auto_focus((MMHandleType)hcamcorder); - ); - sc->now_continuous_af = FALSE; - if (ret != MM_ERROR_NONE) { - _mmcam_dbg_warn("Failed continuous AF when START recording"); - } - } - /* get trailer size */ if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) { MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size); @@ -1139,8 +1131,13 @@ static gboolean __mmcamcorder_video_dataprobe_record(GstPad *pad, GstBuffer *buf default: /* succeeded to get free space */ /* check free space for recording */ /* get queued buffer size */ - MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size); - MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size); + if (sc->element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) { + MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "current-level-bytes", &aq_size); + } + if (sc->element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) { + MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "current-level-bytes", &vq_size); + } + queued_buffer = aq_size + vq_size; /* check free space */ @@ -1164,17 +1161,43 @@ static gboolean __mmcamcorder_video_dataprobe_record(GstPad *pad, GstBuffer *buf } } + /* check max size of recorded file */ + if (info->max_size > 0 && + info->max_size < info->filesize + buffer_size + trailer_size + _MMCAMCORDER_MMS_MARGIN_SPACE) { + GstState pipeline_state = GST_STATE_VOID_PENDING; + GstElement *pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; + _mmcam_dbg_warn("Max size!!! Recording is paused."); + _mmcam_dbg_warn("Max size : [%" G_GUINT64_FORMAT "], current file size : [%" G_GUINT64_FORMAT "]," \ + " buffer size : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]", + info->max_size, info->filesize, buffer_size, trailer_size); + + if (!sc->isMaxsizePausing) { + gst_element_get_state(pipeline, &pipeline_state, NULL, -1) ; + if (pipeline_state == GST_STATE_PLAYING) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE); + sc->isMaxsizePausing = TRUE; + } + + msg.id = MM_MESSAGE_CAMCORDER_MAX_SIZE; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + } + + return FALSE; + } + info->filesize += (guint64)buffer_size; + _mmcam_dbg_log("filesize %lld Byte, ", info->filesize); + return TRUE; } -static gboolean __mmcamcorder_video_dataprobe_slow(GstPad *pad, GstBuffer *buffer, gpointer u_data) +static gboolean __mmcamcorder_video_dataprobe_audio_disable(GstPad *pad, GstBuffer *buffer, gpointer u_data) { - guint min_fps = 15; guint64 trailer_size = 0; - static guint count = 0; + guint64 rec_pipe_time = 0; + unsigned int remained_time = 0; GstClockTime b_time; @@ -1188,28 +1211,65 @@ static gboolean __mmcamcorder_video_dataprobe_slow(GstPad *pad, GstBuffer *buffe sc = MMF_CAMCORDER_SUBCONTEXT(u_data); mmf_return_val_if_fail(sc, TRUE); - mmf_return_val_if_fail(sc->info, TRUE); + mmf_return_val_if_fail(sc->info_video, TRUE); + + info = sc->info_video; - info = sc->info; - count %= min_fps; b_time = GST_BUFFER_TIMESTAMP(buffer); - if (!count) { - if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) { - MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size); - } else { - trailer_size = 0; + rec_pipe_time = GST_TIME_AS_MSECONDS(b_time); + + if (info->fileformat == MM_FILE_FORMAT_3GP || info->fileformat == MM_FILE_FORMAT_MP4) { + MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, "expected-trailer-size", &trailer_size); + } else { + trailer_size = 0; + } + + /* check max time */ + if (info->max_time > 0 && rec_pipe_time > info->max_time) { + _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \ + rec_pipe_time, info->max_time); + + if (!sc->isMaxtimePausing) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE); + + sc->isMaxtimePausing = TRUE; + + msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS; + msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time; + msg.param.recording_status.filesize = (unsigned long long)((info->filesize + trailer_size) >> 10); + msg.param.recording_status.remained_time = 0; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + + msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); } - msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS; - msg.param.recording_status.elapsed = (unsigned int)GST_TIME_AS_MSECONDS(b_time); - msg.param.recording_status.filesize = (unsigned int)((info->filesize + trailer_size) >> 10); - _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + return FALSE; } - count++; + /* calculate remained time can be recorded */ + if (info->max_time > 0 && info->max_time < (remained_time + rec_pipe_time)) { + remained_time = info->max_time - rec_pipe_time; + } else if (info->max_size > 0) { + long double max_size = (long double)info->max_size; + long double current_size = (long double)(info->filesize + trailer_size); - GST_BUFFER_TIMESTAMP(buffer) = b_time * (info->multiple_fps); + remained_time = (unsigned int)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time; + } + + msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS; + msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time; + msg.param.recording_status.filesize = (unsigned long long)((info->filesize + trailer_size) >> 10); + msg.param.recording_status.remained_time = remained_time; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + + _mmcam_dbg_log("time [%" GST_TIME_FORMAT "], size [%d]", + GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize); + + if (info->record_timestamp_ratio != _MMCAMCORDER_DEFAULT_RECORDING_MOTION_RATE) { + GST_BUFFER_TIMESTAMP(buffer) = b_time * (info->record_timestamp_ratio); + } return TRUE; } @@ -1224,16 +1284,17 @@ static gboolean __mmcamcorder_audioque_dataprobe(GstPad *pad, GstBuffer *buffer, GstElement *pipeline = NULL; mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); _MMCamcorderVideoInfo *info = NULL; + unsigned int remained_time = 0; mmf_return_val_if_fail(buffer, FALSE); mmf_return_val_if_fail(hcamcorder, TRUE); sc = MMF_CAMCORDER_SUBCONTEXT(u_data); mmf_return_val_if_fail(sc, TRUE); - mmf_return_val_if_fail(sc->info, TRUE); + mmf_return_val_if_fail(sc->info_video, TRUE); mmf_return_val_if_fail(sc->element, TRUE); - info = sc->info; + info = sc->info_video; pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_TIMESTAMP(buffer))) { @@ -1249,6 +1310,16 @@ static gboolean __mmcamcorder_audioque_dataprobe(GstPad *pad, GstBuffer *buffer, trailer_size = 0; } + /* calculate remained time can be recorded */ + if (info->max_time > 0 && info->max_time < (remained_time + rec_pipe_time)) { + remained_time = info->max_time - rec_pipe_time; + } else if (info->max_size > 0) { + long double max_size = (long double)info->max_size; + long double current_size = (long double)(info->filesize + trailer_size); + + remained_time = (unsigned long long)((long double)rec_pipe_time * (max_size/current_size)) - rec_pipe_time; + } + if (info->max_time > 0 && rec_pipe_time > info->max_time) { _mmcam_dbg_warn("Current time : [%" G_GUINT64_FORMAT "], Maximum time : [%" G_GUINT64_FORMAT "]", \ rec_pipe_time, info->max_time); @@ -1259,8 +1330,9 @@ static gboolean __mmcamcorder_audioque_dataprobe(GstPad *pad, GstBuffer *buffer, sc->isMaxtimePausing = TRUE; msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS; - msg.param.recording_status.elapsed = (unsigned int)rec_pipe_time; - msg.param.recording_status.filesize = (unsigned int)((info->filesize + trailer_size) >> 10); + msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time; + msg.param.recording_status.filesize = (unsigned long long)((info->filesize + trailer_size) >> 10); + msg.param.recording_status.remained_time = 0; _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT; @@ -1270,14 +1342,15 @@ static gboolean __mmcamcorder_audioque_dataprobe(GstPad *pad, GstBuffer *buffer, return FALSE; } - /*_mmcam_dbg_log("_mmcamcorder_audioque_dataprobe :: time [%" GST_TIME_FORMAT "], size [%d]", - GST_TIME_ARGS(rec_pipe_time), (info->filesize + trailer_size) >> 10);*/ - msg.id = MM_MESSAGE_CAMCORDER_RECORDING_STATUS; - msg.param.recording_status.elapsed = (unsigned int)rec_pipe_time; - msg.param.recording_status.filesize = (unsigned int)((info->filesize + trailer_size) >> 10); + msg.param.recording_status.elapsed = (unsigned long long)rec_pipe_time; + msg.param.recording_status.filesize = (unsigned long long)((info->filesize + trailer_size) >> 10); + msg.param.recording_status.remained_time = remained_time; _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + _mmcam_dbg_log("audio data probe :: time [%" GST_TIME_FORMAT "], size [%lld KB]", + GST_TIME_ARGS(rec_pipe_time), msg.param.recording_status.filesize); + return TRUE; } @@ -1372,7 +1445,9 @@ static gboolean __mmcamcorder_add_locationinfo_mp4(MMHandleType handle) gdouble latitude = 0; gdouble altitude = 0; int err = 0; + int orientation = 0; char *err_name = NULL; + char err_msg[MAX_ERROR_MESSAGE_LEN] = {'\0',}; _MMCamcorderLocationInfo location_info = {0,}; _MMCamcorderVideoInfo *info = NULL; @@ -1383,28 +1458,28 @@ static gboolean __mmcamcorder_add_locationinfo_mp4(MMHandleType handle) sc = MMF_CAMCORDER_SUBCONTEXT(handle); mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED); - mmf_return_val_if_fail(sc->info, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc->info_video, MM_ERROR_CAMCORDER_NOT_INITIALIZED); _mmcam_dbg_log(""); - info = sc->info; + info = sc->info_video; f = fopen(info->filename, "rb+"); if (f == NULL) { + strerror_r(errno, err_msg, MAX_ERROR_MESSAGE_LEN); + _mmcam_dbg_err("file open failed [%s]", err_msg); return FALSE; } - err = mm_camcorder_get_attributes(handle, &err_name, - MMCAM_TAG_LATITUDE, &latitude, - MMCAM_TAG_LONGITUDE, &longitude, - MMCAM_TAG_ALTITUDE, &altitude, - NULL); - if (err != MM_ERROR_NONE) { + mm_camcorder_get_attributes(handle, &err_name, + MMCAM_TAG_LATITUDE, &latitude, + MMCAM_TAG_LONGITUDE, &longitude, + MMCAM_TAG_ALTITUDE, &altitude, + MMCAM_TAG_ORIENTATION, &orientation, + NULL); + if (err_name) { _mmcam_dbg_warn("Get tag attrs fail. (%s:%x)", err_name, err); SAFE_FREE (err_name); - fclose(f); - f = NULL; - return FALSE; } location_info.longitude = _mmcamcorder_double_to_fix(longitude); @@ -1414,7 +1489,9 @@ static gboolean __mmcamcorder_add_locationinfo_mp4(MMHandleType handle) /* find udta container. if, there are udta container, write loci box after that else, make udta container and write loci box. */ - if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('u','d','t','a'))) { + if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('u','d','t','a'), TRUE)) { + size_t nread = 0; + _mmcam_dbg_log("find udta container"); /* read size */ @@ -1427,7 +1504,10 @@ static gboolean __mmcamcorder_add_locationinfo_mp4(MMHandleType handle) goto ftell_fail; } - fread(&buf, sizeof(char), sizeof(buf), f); + nread = fread(&buf, sizeof(char), sizeof(buf), f); + + _mmcam_dbg_log("recorded file fread %d", nread); + udta_size = _mmcamcorder_get_container_size(buf); /* goto end of udta and write 'loci' box */ @@ -1462,9 +1542,11 @@ static gboolean __mmcamcorder_add_locationinfo_mp4(MMHandleType handle) update moov container size. */ if((current_pos = ftell(f))<0) goto ftell_fail; - - if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m','o','o','v'))) { - _mmcam_dbg_log("find moov container"); + + if (_mmcamcorder_find_tag(f, MMCAM_FOURCC('m','o','o','v'), TRUE)) { + gint64 internal_pos = ftell(f); + + _mmcam_dbg_log("found moov container"); if (fseek(f, -8L, SEEK_CUR) !=0) { goto fail; } @@ -1477,6 +1559,26 @@ static gboolean __mmcamcorder_add_locationinfo_mp4(MMHandleType handle) if (!_mmcamcorder_update_size(f, moov_pos, current_pos)) { goto fail; } + + /* add orientation info */ + fseek(f, internal_pos, SEEK_SET); + if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','r','a','k'), FALSE)) { + _mmcam_dbg_err("failed to find [trak] tag"); + goto fail; + } + + if (!_mmcamcorder_find_tag(f, MMCAM_FOURCC('t','k','h','d'), FALSE)) { + _mmcam_dbg_err("failed to find [tkhd] tag"); + goto fail; + } + + _mmcam_dbg_log("found [tkhd] tag"); + + /* seek to start position of composition matrix */ + fseek(f, _OFFSET_COMPOSITION_MATRIX, SEEK_CUR); + + /* update composition matrix for orientation */ + _mmcamcorder_update_composition_matrix(f, orientation); } else { _mmcam_dbg_err("No 'moov' container"); goto fail; diff --git a/test/Makefile.am b/test/Makefile.am old mode 100755 new mode 100644 index 0c18a31..c6859b0 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -9,6 +9,7 @@ mm_camcorder_testsuite_CFLAGS = -I$(srcdir)/../src/include \ $(MMTA_CFLAGS)\ $(MM_SOUND_CFLAGS) + ############################################ #mm_camcorder_testsuite_CFLAGS += -DAPPSRC_TEST ############################################ diff --git a/test/mm_camcorder_testsuite.c b/test/mm_camcorder_testsuite.c index 57e7eb6..39e3f05 100644 --- a/test/mm_camcorder_testsuite.c +++ b/test/mm_camcorder_testsuite.c @@ -32,61 +32,60 @@ when who what, where, why */ -/*=========================================================================================== -| | -| INCLUDE FILES | -| | -========================================================================================== */ +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ #include #include #include #include #include -#include -#include -#include +#include "../src/include/mm_camcorder.h" +#include "../src/include/mm_camcorder_internal.h" +#include "../src/include/mm_camcorder_util.h" #include #include -/*--------------------------------------------------------------------------- -| GLOBAL VARIABLE DEFINITIONS: | ----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS: | +-----------------------------------------------------------------------*/ #define EXPORT_API __attribute__((__visibility__("default"))) #define PACKAGE "mm_camcorder_testsuite" -GMainLoop *g_loop; +GMainLoop *g_loop; GIOChannel *stdin_channel; int resolution_set; -int g_current_state; +int g_current_state; int src_w, src_h; GstCaps *filtercaps; -bool isMultishot; +bool isMultishot; MMCamPreset cam_info; int mmcamcorder_state; int mmcamcorder_print_state; int multishot_num; -static int audio_stream_cb_cnt, video_stream_cb_cnt; +static int audio_stream_cb_cnt; +static int video_stream_cb_cnt; static GTimer *timer = NULL; -/*--------------------------------------------------------------------------- -| GLOBAL CONSTANT DEFINITIONS: | ----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------- +| GLOBAL CONSTANT DEFINITIONS: | +-----------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------- -| IMPORTED VARIABLE DECLARATIONS: | ----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------- +| IMPORTED VARIABLE DECLARATIONS: | +-----------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------- -| IMPORTED FUNCTION DECLARATIONS: | ----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------- +| IMPORTED FUNCTION DECLARATIONS: | +-----------------------------------------------------------------------*/ -/*--------------------------------------------------------------------------- -| LOCAL #defines: | ----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------- +| LOCAL #defines: | +-----------------------------------------------------------------------*/ #define test_ffmux_mp4 // FULLHD(1080P) @@ -140,7 +139,7 @@ static GTimer *timer = NULL; #define IMAGE_ENC_QUALITY 85 // quality of jpeg #define IMAGE_CAPTURE_COUNT_STILL 1 // the number of still-shot #define IMAGE_CAPTURE_COUNT_MULTI 3 // default the number of multi-shot -#define IMAGE_CAPTURE_COUNT_INTERVAL 500 // mili seconds +#define IMAGE_CAPTURE_COUNT_INTERVAL 100 // mili seconds #define MAX_FILE_SIZE_FOR_MMS (250 * 1024) @@ -150,8 +149,11 @@ static GTimer *timer = NULL; #define EXT_AMR "amr" #define EXT_MKV "mkv" -#define STILL_CAPTURE_FILE_PATH_NAME "/root/StillshotCapture" -#define MULTI_CAPTURE_FILE_PATH_NAME "/root/MultishotCapture" +#define STILL_CAPTURE_FILE_PATH_NAME "/opt/media/StillshotCapture" +#define MULTI_CAPTURE_FILE_PATH_NAME "/opt/media/MultishotCapture" +#define IMAGE_CAPTURE_THUMBNAIL_PATH "/opt/media/thumbnail.jpg" +#define IMAGE_CAPTURE_SCREENNAIL_PATH "/opt/media/screennail.yuv" +#define IMAGE_CAPTURE_EXIF_PATH "/opt/media/exif.raw" #define TARGET_FILENAME_PATH "/opt/media/" #define TARGET_FILENAME_VIDEO "/opt/media/test_rec_video.3gp" #define TARGET_FILENAME_AUDIO "/opt/media/test_rec_audio.amr" @@ -162,8 +164,9 @@ static GTimer *timer = NULL; #define AUDIO_SOURCE_FORMAT MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE #define AUDIO_SOURCE_CHANNEL_AAC 2 #define AUDIO_SOURCE_CHANNEL_AMR 1 +#define VIDEO_ENCODE_BITRATE 40000000 /* bps */ -#define DEFAULT_CAM_DEVICE MM_VIDEO_DEVICE_CAMERA1 +#define DEFAULT_CAM_DEVICE MM_VIDEO_DEVICE_CAMERA1 /* * D E B U G M E S S A G E @@ -216,7 +219,7 @@ do { \ GTimeVal previous; -GTimeVal current; +GTimeVal current; GTimeVal result; //temp @@ -224,24 +227,23 @@ GTimeVal result; * Enumerations for command */ #define SENSOR_WHITEBALANCE_NUM 10 -#define SENSOR_COLOR_TONE_NUM 27 -#define SENSOR_FLIP_NUM 3 +#define SENSOR_COLOR_TONE_NUM 37 +#define SENSOR_FLIP_NUM 3 #define SENSOR_PROGRAM_MODE_NUM 15 -#define SENSOR_FOCUS_NUM 5 -#define SENSOR_INPUT_ROTATION 6 -#define SENSOR_AF_SCAN_NUM 4 -#define SENSOR_ISO_NUM 8 -#define SENSOR_EXPOSURE_NUM 9 -#define SENSOR_IMAGE_FORMAT 9 +#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: | ----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------- +| LOCAL CONSTANT DEFINITIONS: | +-----------------------------------------------------------------------*/ enum { - MODE_IMAGE, /* capture mode */ - MODE_VIDEO, /* recording mode */ + MODE_VIDEO_CAPTURE, /* recording and image capture mode */ MODE_AUDIO, /* audio recording*/ MODE_NUM, }; @@ -253,22 +255,22 @@ enum MENU_STATE_NUM, }; -/*--------------------------------------------------------------------------- -| LOCAL DATA TYPE DEFINITIONS: | ----------------------------------------------------------------------------*/ +/*----------------------------------------------------------------------- +| LOCAL DATA TYPE DEFINITIONS: | +-----------------------------------------------------------------------*/ typedef struct _cam_handle { MMHandleType camcorder; - int mode; /* image(capture)/video(recording) mode */ - bool isMultishot; - int stillshot_count; /* total stillshot count */ - int multishot_count; /* total multishot count */ - char *stillshot_filename; /* stored filename of stillshot */ - char *multishot_filename; /* stored filename of multishot */ - int menu_state; - int fps; - bool isMute; - unsigned int elapsed_time; + 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 */ + char *stillshot_filename; /* stored filename of stillshot */ + char *multishot_filename; /* stored filename of multishot */ + int menu_state; + int fps; + bool isMute; + unsigned long long elapsed_time; } cam_handle_t; typedef struct _cam_xypair @@ -316,14 +318,18 @@ char *ct[SENSOR_COLOR_TONE_NUM] = { "PURPLE", "EMBOSS", "OUTLINE", - "SOLARIZATION_1", - "SOLARIZATION_2", - "SOLARIZATION_3", - "SOLARIZATION_4", - "SKETCH_1", - "SKETCH_2", - "SKETCH_3", - "SKETCH_4", + "SOLARIZATION", + "SKETCH", + "WASHED", + "VINTAGE_WARM", + "VINTAGE_COLD", + "POSTERIZATION", + "CARTOON", + "SELECTVE_COLOR_RED", + "SELECTVE_COLOR_GREEN", + "SELECTVE_COLOR_BLUE", + "SELECTVE_COLOR_YELLOW", + "SELECTVE_COLOR_RED_YELLOW", }; char *flip[SENSOR_FLIP_NUM] = { @@ -356,6 +362,7 @@ char *focus_mode[SENSOR_FOCUS_NUM] = { "Auto", "Manual", "Touch Auto", + "Continuous Auto", }; char *camera_rotation[SENSOR_INPUT_ROTATION] = { @@ -363,8 +370,6 @@ char *camera_rotation[SENSOR_INPUT_ROTATION] = { "90", "180", "270", - "Flip Horizontal", - "Flip Vertical", }; char *af_scan[SENSOR_AF_SCAN_NUM] = { @@ -409,6 +414,17 @@ char *image_fmt[SENSOR_IMAGE_FORMAT] = { "YV12", }; +char *face_zoom_mode[] = { + "Face Zoom OFF", + "Face Zoom ON", +}; + +char *display_mode[] = { + "Default", + "Primary Video ON and Secondary Video Full Screen", + "Primary Video OFF and Secondary Video Full Screen", +}; + char *output_mode[] = { "Letter Box mode", "Original Size mode", @@ -422,8 +438,6 @@ char *rotate_mode[] = { "90", "180", "270", - "Flip Horizontal", - "Flip Vertical", }; char* strobe_mode[] = { @@ -448,6 +462,12 @@ char *wdr_mode[] = { "WDR AUTO", }; +char *hdr_mode[] = { + "HDR OFF", + "HDR ON", + "HDR ON and Original", +}; + char *ahs_mode[] = { "Anti-handshake OFF", "Anti-handshake ON", @@ -455,17 +475,16 @@ char *ahs_mode[] = { "Anti-handshake MOVIE", }; +char *vs_mode[] = { + "Video-stabilization OFF", + "Video-stabilization ON", +}; + char *visible_mode[] = { "Display OFF", "Display ON", }; -char *camcorder_rotate_val[] = { - "0", - "90", - "180", - "270", -}; /*--------------------------------------------------------------------------- | LOCAL FUNCTION PROTOTYPES: | @@ -504,47 +523,76 @@ cam_utils_convert_YUYV_to_UYVY(unsigned char* dst, unsigned char* src, gint leng } } +#ifdef USE_AUDIO_STREAM_CB static int camcordertest_audio_stream_cb(MMCamcorderAudioStreamDataType *stream, void *user_param) { - if ( (int)(stream->timestamp)/1000 == audio_stream_cb_cnt ) { - audio_stream_cb_cnt++; - printf("audio_stream cb is called ( data:%p, format:%d, channel:%d, volume_dB:%f, length:%d, timestamp:%d)\n", stream->data, stream->format, stream->channel, stream->volume_dB, stream->length, stream->timestamp); - } + audio_stream_cb_cnt++; + printf("audio_stream cb is called (stream:%p, data:%p, format:%d, channel:%d, volume_dB:%f, length:%d, timestamp:%d)\n", + stream, stream->data, stream->format, stream->channel, stream->volume_dB, stream->length, stream->timestamp); + return TRUE; } +#endif /* USE_AUDIO_STREAM_CB */ static int camcordertest_video_stream_cb(MMCamcorderVideoStreamDataType *stream, void *user_param) { - if ( (int)(stream->timestamp)/1000 == video_stream_cb_cnt ) { - video_stream_cb_cnt++; - printf("video_stream cb is called ( data:%p, format:%d, length:%d, width:%d, height:%d, timestamp:%d)\n", stream->data, stream->format, stream->length, stream->width, stream->height, stream->timestamp); - } + video_stream_cb_cnt++; + + printf("VIDEO STREAM CALLBACK total length :%u, size %dx%d\n", stream->length_total, stream->width, stream->height); + return TRUE; } +static void _file_write(char *path, void *data, int size) +{ + FILE *fp = NULL; + + if (!path || !data || size <= 0) { + printf("ERROR %p %p %d\n", path, data, size); + return; + } + + fp = fopen(path, "w"); + if (fp == NULL) { + printf("open error! [%s], errno %d\n", path, errno); + return; + } else { + printf("open success [%s]\n", path); + if (fwrite(data, size, 1, fp) != 1) { + printf("write error! errno %d\n", errno); + } else { + printf("write success [%s]\n", path); + } + + fclose(fp); + fp = NULL; + } +} + + static int camcordertest_video_capture_cb(MMCamcorderCaptureDataType *main, MMCamcorderCaptureDataType *thumb, void *data) { int nret = 0; int scrnl_size = 0; + int exif_size = 0; char m_filename[CAPTURE_FILENAME_LEN]; - FILE *fp = NULL; MMCamcorderCaptureDataType *scrnl = NULL; - - debug_msg_t("hcamcorder->isMultishot=%d =>1: MULTI, 0: STILL",hcamcorder->isMultishot); + unsigned char *exif_data = NULL; if (main == NULL) { warn_msg_t("Capture callback : Main image buffer is NULL!!!"); return FALSE; } - if (hcamcorder->isMultishot == TRUE) { - snprintf(m_filename, CAPTURE_FILENAME_LEN, "%s%03d.jpg", hcamcorder->multishot_filename,hcamcorder->multishot_count++); + if (hcamcorder->isMultishot) { + snprintf(m_filename, CAPTURE_FILENAME_LEN, "%s%03d.jpg", hcamcorder->multishot_filename, hcamcorder->multishot_count++); } else { - snprintf(m_filename, CAPTURE_FILENAME_LEN, "%s%03d.jpg", hcamcorder->stillshot_filename,hcamcorder->stillshot_count++); + snprintf(m_filename, CAPTURE_FILENAME_LEN, "%s%03d.jpg", hcamcorder->stillshot_filename, hcamcorder->stillshot_count++); } - debug_msg_t("filename : %s", m_filename); + debug_msg_t("hcamcorder->isMultishot=%d =>1: MULTI, 0: STILL, filename : %s", + hcamcorder->isMultishot, m_filename); if (main->format != MM_PIXEL_FORMAT_ENCODED) { unsigned int dst_size = 0; @@ -553,71 +601,24 @@ camcordertest_video_capture_cb(MMCamcorderCaptureDataType *main, MMCamcorderCapt nret = _mmcamcorder_encode_jpeg(main->data, main->width, main->height, main->format, main->length, 90, &dst, &dst_size); if (nret) { - fp = fopen(m_filename, "w+"); - if (fp == NULL) { - printf("FileOPEN error!!\n"); - warn_msg_t("FileOPEN error!!"); - return FALSE; - } else { - printf("open success\n"); - if (fwrite(dst, dst_size, 1, fp) != 1) { - printf("File write error!!\n"); - warn_msg_t("File write error!!"); - fclose(fp); - return FALSE; - } - printf("write success\n"); - } - fclose(fp); - fp = NULL; + _file_write(m_filename, dst, dst_size); } else { printf("Failed to encode YUV(%d) -> JPEG. \n", main->format); } free(dst); dst = NULL; - } else { + } else if (!hcamcorder->isMultishot) { + printf("MM_PIXEL_FORMAT_ENCODED main->data=%p main->length=%d, main->width=%d, main->heigtht=%d \n", main->data, main->length, main->width, main->height); /* main image */ - fp = fopen(m_filename, "w+"); - if (fp == NULL) { - printf("FileOPEN error!!\n"); - warn_msg_t("FileOPEN error!!"); - return FALSE; - } else { - printf("open success\n"); - if (fwrite(main->data, main->length, 1, fp) != 1) { - printf("File write error!!\n"); - warn_msg_t("File write error!!"); - fclose(fp); - return FALSE; - } - printf("write success\n"); - } - fclose(fp); - fp = NULL; + _file_write(m_filename, main->data, main->length); /* thumbnail */ if (thumb != NULL) { - fp = fopen("./thumbnail.jpg", "w+"); - if (fp == NULL) { - printf("FileOPEN error!!\n"); - warn_msg_t("FileOPEN error!!"); - return FALSE; - } else { - printf("open success\n"); - if (fwrite(thumb->data, thumb->length, 1, fp) != 1) { - printf("File write error!!\n"); - warn_msg_t("File write error!!"); - fclose(fp); - return FALSE; - } - printf("write success\n"); - } - fclose(fp); - fp = NULL; + _file_write(IMAGE_CAPTURE_THUMBNAIL_PATH, thumb->data, thumb->length); } /* screennail */ @@ -625,30 +626,18 @@ camcordertest_video_capture_cb(MMCamcorderCaptureDataType *main, MMCamcorderCapt "captured-screennail", &scrnl, &scrnl_size, NULL); if (scrnl != NULL) { - fp = fopen("./screennail.yuv", "w+"); - if (fp == NULL) { - printf("FileOPEN error!!\n"); - warn_msg_t("FileOPEN error!!"); - return FALSE; - } else { - printf("open success\n"); - - if (fwrite(scrnl->data, scrnl->length, 1, fp) != 1) { - printf("File write error!!\n"); - warn_msg_t("File write error!!"); - fclose(fp); - fp = NULL; - return FALSE; - } - - fclose(fp); - fp = NULL; - - printf("write success\n"); - } + _file_write(IMAGE_CAPTURE_SCREENNAIL_PATH, scrnl->data, scrnl->length); } else { printf( "Screennail buffer is NULL.\n" ); } + + /* EXIF data */ + mm_camcorder_get_attributes(hcamcorder->camcorder, NULL, + "captured-exif-raw-data", &exif_data, &exif_size, + NULL); + if (exif_data) { + _file_write(IMAGE_CAPTURE_EXIF_PATH, exif_data, exif_size); + } } return TRUE; @@ -658,16 +647,8 @@ static gboolean test_idle_capture_start() { int err; - if (!hcamcorder->isMultishot) - { - camcordertest_set_attr_int("capture-format", MM_PIXEL_FORMAT_ENCODED); - camcordertest_set_attr_int(MMCAM_IMAGE_ENCODER, MM_IMAGE_CODEC_JPEG); - } - else - { -// camcordertest_set_attr_int("capture-format", MM_PIXEL_FORMAT_I420); - camcordertest_set_attr_int("capture-format", MM_PIXEL_FORMAT_YUYV); - } + camcordertest_set_attr_int(MMCAM_CAPTURE_FORMAT, MM_PIXEL_FORMAT_ENCODED); + camcordertest_set_attr_int(MMCAM_IMAGE_ENCODER, MM_IMAGE_CODEC_JPEG); g_timer_reset(timer); err = mm_camcorder_capture_start(hcamcorder->camcorder); @@ -686,32 +667,29 @@ int camcordertest_set_attr_int(char * attr_subcategory, int value) char * err_attr_name = NULL; int err; - if (hcamcorder) - { - if (hcamcorder->camcorder) - { + if (hcamcorder) { + if (hcamcorder->camcorder) { debug_msg_t("camcordertest_set_attr_int(%s, %d)", attr_subcategory, value); err = mm_camcorder_set_attributes(hcamcorder->camcorder, &err_attr_name, - attr_subcategory, value, - NULL); - if (err < 0) - { + attr_subcategory, value, + NULL); + if (err != MM_ERROR_NONE) { err_msg_t("camcordertest_set_attr_int : Error(%s:%x)!!!!!!!", err_attr_name, err); - SAFE_FREE (err_attr_name); + SAFE_FREE(err_attr_name); return FALSE; } //success return TRUE; } - + debug_msg_t("camcordertest_set_attr_int(!hcamcorder->camcorde)"); } debug_msg_t("camcordertest_set_attr_int(!hcamcorder)"); - return FALSE; + return FALSE; } int camcordertest_set_attr_xypair(cam_xypair_t pair) @@ -756,24 +734,21 @@ int camcordertest_get_attr_valid_intarray(char * attr_name, int ** array, int *c { if (hcamcorder->camcorder) { - debug_msg_t("camcordertest_get_attr_valid_intarray((%s),(%p, %p))", attr_name, array, count); + debug_msg_t("camcordertest_get_attr_valid_intarray(%s)", attr_name); err = mm_camcorder_get_attribute_info(hcamcorder->camcorder, attr_name, &info); - - if (err < 0) - { - err_msg_t("camcordertest_get_attr_valid_intarray : Error(%x)!!", err); + if (err != MM_ERROR_NONE) { + err_msg_t("camcordertest_get_attr_valid_intarray : Error(%x)!!", err); return FALSE; - } - else - { - if (info.type == MM_CAM_ATTRS_TYPE_INT) - if (info.validity_type == MM_CAM_ATTRS_VALID_TYPE_INT_ARRAY) - { + } else { + if (info.type == MM_CAM_ATTRS_TYPE_INT) { + if (info.validity_type == MM_CAM_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("camcordertest_get_attr_valid_intarray : Type mismatched!!"); return FALSE; @@ -797,24 +772,21 @@ int camcordertest_get_attr_valid_intrange(char * attr_name, int *min, int *max) { if (hcamcorder->camcorder) { - debug_msg_t("camcordertest_get_attr_valid_intarray((%s),(%p, %p))", attr_name, min, max); + debug_msg_t("camcordertest_get_attr_valid_intrange(%s)", attr_name); err = mm_camcorder_get_attribute_info(hcamcorder->camcorder, attr_name, &info); - - if (err < 0) - { + if (err != MM_ERROR_NONE) { err_msg_t("camcordertest_get_attr_valid_intarray : Error(%x)!!", err); return FALSE; - } - else - { - if (info.type == MM_CAM_ATTRS_TYPE_INT) - if (info.validity_type == MM_CAM_ATTRS_VALID_TYPE_INT_RANGE) - { + } else { + if (info.type == MM_CAM_ATTRS_TYPE_INT) { + if (info.validity_type == MM_CAM_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("camcordertest_get_attr_valid_intarray : Type mismatched!!"); return FALSE; @@ -841,49 +813,33 @@ static void print_menu() switch(hcamcorder->menu_state) { case MENU_STATE_MAIN: - if (hcamcorder->mode == MODE_IMAGE) - { - g_print("\n\t=======================================\n"); - if ( cam_info.videodev_type == MM_VIDEO_DEVICE_CAMERA1 ) - g_print("\t Image Capture (Front camera)\n"); - else if( cam_info.videodev_type == MM_VIDEO_DEVICE_CAMERA0 ) - g_print("\t Image Capture (Rear camera)\n"); - g_print("\t=======================================\n"); - g_print("\t '1' Take a photo\n"); - g_print("\t '2' Setting\n"); - g_print("\t '3' Print FPS\n"); - g_print("\t 'b' back\n"); - g_print("\t=======================================\n"); - } - else if (hcamcorder->mode == MODE_VIDEO) - { + if (hcamcorder->mode == MODE_VIDEO_CAPTURE) { g_print("\n\t=======================================\n"); if ( cam_info.videodev_type == MM_VIDEO_DEVICE_CAMERA1 ) - g_print("\t Video Recording (Front camera)\n"); + g_print("\t Video Capture (Front camera)\n"); else if( cam_info.videodev_type == MM_VIDEO_DEVICE_CAMERA0 ) - g_print("\t Video Recording (Rear camera)\n"); + g_print("\t Video Capture (Rear camera)\n"); g_print("\t=======================================\n"); if(mmcamcorder_print_state <= MM_CAMCORDER_STATE_PREPARE) { - g_print("\t '1' Start Recording\n"); - g_print("\t '2' Setting\n"); - g_print("\t '3' Print FPS\n"); + g_print("\t '1' Take a photo\n"); + g_print("\t '2' Start Recording\n"); + g_print("\t '3' Setting\n"); + g_print("\t '4' Print FPS\n"); g_print("\t 'b' back\n"); - } - else if(mmcamcorder_print_state == MM_CAMCORDER_STATE_RECORDING) { + } else if(mmcamcorder_print_state == MM_CAMCORDER_STATE_RECORDING) { g_print("\t 'p' Pause Recording\n"); g_print("\t 'c' Cancel\n"); g_print("\t 's' Save\n"); - } - else if(mmcamcorder_print_state == MM_CAMCORDER_STATE_PAUSED) { + g_print("\t 'n' Capture video snapshot\n"); + } else if(mmcamcorder_print_state == MM_CAMCORDER_STATE_PAUSED) { g_print("\t 'r' Resume Recording\n"); g_print("\t 'c' Cancel\n"); g_print("\t 's' Save\n"); + g_print("\t 'n' Capture video snapshot\n"); } g_print("\t=======================================\n"); - } - else if (hcamcorder->mode == MODE_AUDIO) - { + } else if (hcamcorder->mode == MODE_AUDIO) { g_print("\n\t=======================================\n"); g_print("\t Audio Recording\n"); g_print("\t=======================================\n"); @@ -906,85 +862,50 @@ static void print_menu() break; case MENU_STATE_SETTING: - if (hcamcorder->mode == MODE_IMAGE) { - g_print("\n\t=======================================\n"); - g_print("\t Image Capture > Setting\n"); - g_print("\t=======================================\n"); - g_print("\t >>>>>>>>>>>>>>>>>>>>>>>>>>>> [Camera] \n"); - g_print("\t '1' Capture resolution \n"); - g_print("\t '2' Digital zoom level \n"); - g_print("\t '3' Optical zoom level \n"); - g_print("\t '4' AF mode \n"); - g_print("\t '5' AF scan range \n"); - g_print("\t '6' Exposure mode \n"); - g_print("\t '7' Exposure value \n"); - g_print("\t '8' F number \n"); - g_print("\t '9' Shutter speed \n"); - g_print("\t 'i' ISO \n"); - g_print("\t 'r' Rotate camera input \n"); - g_print("\t 'j' Jpeg quality \n"); - g_print("\t 'p' Picture format \n"); - g_print("\t >>>>>>>>>>>>>>>>>>>> [Display/Filter]\n"); - g_print("\t 'v' Visible \n"); - g_print("\t 'o' Output mode \n"); - g_print("\t 'y' Rotate display \n"); - g_print("\t 'g' Brightness \n"); - g_print("\t 'c' Contrast \n"); - g_print("\t 's' Saturation \n"); - g_print("\t 'h' Hue \n"); - g_print("\t 'a' Sharpness \n"); - g_print("\t 'w' White balance \n"); - g_print("\t 't' Color tone \n"); - g_print("\t 'd' WDR \n"); - g_print("\t 'e' EV program mode \n"); - g_print("\t >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> [etc.]\n"); - g_print("\t 'z' Strobe (Flash) \n"); - g_print("\t 'x' Capture mode (Still/Multishot)\n"); - g_print("\t 'f' Face detection \n"); - g_print("\t 'k' Anti-handshake \n"); - g_print("\t 'u' Touch AF area \n"); - g_print("\t 'm' Stream callback function \n"); - g_print("\t 'b' back\n"); - g_print("\t=======================================\n"); - - } else if (hcamcorder->mode == MODE_VIDEO) { - g_print("\n\t=======================================\n"); - g_print("\t Video Recording > Setting\n"); - g_print("\t=======================================\n"); - g_print("\t >>>>>>>>>>>>>>>>>>>>>>>>>>>> [Camera] \n"); - g_print("\t '1' Recording resolution \n"); - g_print("\t '2' Digital zoom level \n"); - g_print("\t '3' Optical zoom level \n"); - g_print("\t '4' AF mode \n"); - g_print("\t '5' AF scan range \n"); - g_print("\t '6' Exposure mode \n"); - g_print("\t '7' Exposure value \n"); - g_print("\t '8' F number \n"); - g_print("\t 'i' ISO \n"); - g_print("\t 'r' Rotate camera input \n"); - g_print("\t 'p' FPS \n"); - g_print("\t >>>>>>>>>>>>>>>>>>>> [Display/Filter]\n"); - g_print("\t 'v' Visible \n"); - g_print("\t 'o' Output mode \n"); - g_print("\t 'y' Rotate display \n"); - g_print("\t 'g' Brightness \n"); - g_print("\t 'c' Contrast \n"); - g_print("\t 's' Saturation \n"); - g_print("\t 'h' Hue \n"); - g_print("\t 'a' Sharpness \n"); - g_print("\t 'w' White balance \n"); - g_print("\t 't' Color tone \n"); - g_print("\t 'd' WDR \n"); - g_print("\t >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> [etc.]\n"); - g_print("\t 'x' High speed recording\n"); - g_print("\t 'u' Mute \n"); - g_print("\t 'z' Strobe (Flash) \n"); - g_print("\t 'k' Anti-handshake \n"); - g_print("\t 'e' Camcorder-rotation setting \n"); - g_print("\t 'm' Stream callback function \n"); - g_print("\t 'b' back\n"); - g_print("\t=======================================\n"); - } + g_print("\n\t=======================================\n"); + g_print("\t Video Capture > Setting\n"); + g_print("\t=======================================\n"); + g_print("\t >>>>>>>>>>>>>>>>>>>>>>>>>>>> [Camera] \n"); + g_print("\t '1' Capture resolution \n"); + g_print("\t '2' Digital zoom level \n"); + g_print("\t '3' Optical zoom level \n"); + g_print("\t '4' AF mode \n"); + g_print("\t '5' AF scan range \n"); + g_print("\t '6' Exposure mode \n"); + g_print("\t '7' Exposure value \n"); + g_print("\t '8' F number \n"); + g_print("\t '9' Shutter speed \n"); + g_print("\t 'i' ISO \n"); + g_print("\t 'r' Rotate camera input \n"); + g_print("\t 'f' Flip camera input \n"); + g_print("\t 'j' Jpeg quality \n"); + g_print("\t 'p' Picture format \n"); + g_print("\t 'E' EXIF orientation \n"); + g_print("\t >>>>>>>>>>>>>>>>>>>> [Display/Filter]\n"); + g_print("\t 'v' Visible \n"); + g_print("\t 'n' Display mode \n"); + g_print("\t 'o' Output mode \n"); + g_print("\t 'y' Rotate display \n"); + g_print("\t 'Y' Flip display \n"); + g_print("\t 'g' Brightness \n"); + g_print("\t 'c' Contrast \n"); + g_print("\t 's' Saturation \n"); + g_print("\t 'h' Hue \n"); + g_print("\t 'a' Sharpness \n"); + g_print("\t 'w' White balance \n"); + g_print("\t 't' Color tone \n"); + g_print("\t 'd' WDR \n"); + g_print("\t 'e' EV program mode \n"); + g_print("\t >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> [etc.]\n"); + g_print("\t 'z' Strobe (Flash) \n"); + g_print("\t 'x' Capture mode (Still/Multishot/HDR)\n"); + g_print("\t 'l' Face detection \n"); + g_print("\t 'k' Anti-handshake \n"); + g_print("\t 'K' Video-stabilization \n"); + g_print("\t 'u' Touch AF area \n"); + g_print("\t 'm' Stream callback function \n"); + g_print("\t 'b' back\n"); + g_print("\t=======================================\n"); break; default: @@ -1001,93 +922,60 @@ static void main_menu(gchar buf) int current_fps = 0; int average_fps = 0; char *err_attr_name = NULL; - int width = 0, height = 0; - - if (hcamcorder->mode == MODE_IMAGE) { - switch(buf) { - case '1' : //Capture - if(hcamcorder->isMultishot) { - err = mm_camcorder_set_attributes(hcamcorder->camcorder, &err_attr_name, - MMCAM_CAPTURE_WIDTH, 640, - MMCAM_CAPTURE_HEIGHT, 480, - MMCAM_CAPTURE_COUNT, multishot_num, - MMCAM_CAPTURE_INTERVAL, IMAGE_CAPTURE_COUNT_INTERVAL, - NULL); - if (err < 0) { - err_msg_t("Attribute setting fail : (%s:%x)", err_attr_name, err); - SAFE_FREE (err_attr_name); - } - } else { - err = mm_camcorder_set_attributes(hcamcorder->camcorder, &err_attr_name, - MMCAM_CAPTURE_COUNT, IMAGE_CAPTURE_COUNT_STILL, - NULL); - if (err < 0) { - err_msg_t("Attribute setting fail : (%s:%x)", err_attr_name, err); - SAFE_FREE (err_attr_name); - } - } - g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)test_idle_capture_start, NULL, NULL); - break; - - case '2' : // Setting - hcamcorder->menu_state = MENU_STATE_SETTING; - break; - - case '3' : // Print frame rate - current_fps = _mmcamcorder_video_current_framerate(hcamcorder->camcorder); - average_fps = _mmcamcorder_video_average_framerate(hcamcorder->camcorder); - g_print("\tVideo Frame Rate[Current : %d.0 fps, Average : %d.0 fps]\n", current_fps, average_fps); - break; + if (hcamcorder->mode == MODE_VIDEO_CAPTURE) { + if (mmcamcorder_state == MM_CAMCORDER_STATE_PREPARE) { + switch (buf) { + case '1' : //Capture + if(hcamcorder->isMultishot) { + int interval = 0; + flush_stdin(); + printf("\ninput interval(ms) \n"); + err = scanf("%d", &interval); + if (err == EOF) { + printf("\nscanf error : errno %d\n", errno); + interval = 300; + } + err = mm_camcorder_set_attributes(hcamcorder->camcorder, &err_attr_name, + MMCAM_CAPTURE_INTERVAL, interval, + NULL); + if (err != MM_ERROR_NONE) { + err_msg_t("Attribute setting fail : (%s:%x)", err_attr_name, err); + SAFE_FREE (err_attr_name); + } + } else { + err = mm_camcorder_set_attributes(hcamcorder->camcorder, &err_attr_name, + MMCAM_CAPTURE_COUNT, IMAGE_CAPTURE_COUNT_STILL, + NULL); + if (err != MM_ERROR_NONE) { + err_msg_t("Attribute setting fail : (%s:%x)", err_attr_name, err); + SAFE_FREE (err_attr_name); + } + } - case 'b' : // back - hcamcorder->menu_state = MENU_STATE_MAIN; - mode_change(); - break; + g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, (GSourceFunc)test_idle_capture_start, NULL, NULL); + break; - default: - g_print("\t Invalid input \n"); - break; - } - } - else if (hcamcorder->mode == MODE_VIDEO) - { - if (mmcamcorder_state == MM_CAMCORDER_STATE_PREPARE) { - switch(buf) { - case '1' : // Start Recording + case '2' : // Start Recording g_print("*Recording start!\n"); video_stream_cb_cnt = 0; audio_stream_cb_cnt = 0; - mm_camcorder_get_attributes( hcamcorder->camcorder, NULL, - MMCAM_CAMERA_WIDTH, &width, - MMCAM_CAMERA_HEIGHT, &height, - NULL ); - - mm_camcorder_set_attributes( hcamcorder->camcorder, NULL, - MMCAM_CAMERA_AF_TOUCH_X, width>>1, - MMCAM_CAMERA_AF_TOUCH_Y, height>>1, - MMCAM_CAMERA_AF_TOUCH_WIDTH, 30, - MMCAM_CAMERA_AF_TOUCH_HEIGHT, 30, - NULL ); - - mm_camcorder_start_focusing(hcamcorder->camcorder); - g_timer_reset(timer); err = mm_camcorder_record(hcamcorder->camcorder); - if (err < 0) { - warn_msg_t("Rec start mm_camcorder_record = %x", err); + if (err != MM_ERROR_NONE) { + warn_msg_t("Rec start mm_camcorder_record 0x%x", err); } mmcamcorder_print_state = MM_CAMCORDER_STATE_RECORDING; break; - case '2' : // Setting + case '3' : // Setting hcamcorder->menu_state = MENU_STATE_SETTING; break; - case '3' : + case '4' : // Print frame rate current_fps = _mmcamcorder_video_current_framerate(hcamcorder->camcorder); average_fps = _mmcamcorder_video_average_framerate(hcamcorder->camcorder); g_print("\tVideo Frame Rate[Current : %d.0 fps, Average : %d.0 fps]\n", current_fps, average_fps); @@ -1097,9 +985,13 @@ static void main_menu(gchar buf) hcamcorder->menu_state = MENU_STATE_MAIN; mode_change(); break; + + default: + g_print("\t Invalid input \n"); + break; } } else if (mmcamcorder_state == MM_CAMCORDER_STATE_RECORDING || mmcamcorder_state == MM_CAMCORDER_STATE_PAUSED) { - switch(buf) { + switch (buf) { if (mmcamcorder_state == MM_CAMCORDER_STATE_RECORDING) { case 'p' : // Pause Recording g_print("*Pause!\n"); @@ -1145,6 +1037,10 @@ static void main_menu(gchar buf) mmcamcorder_print_state = MM_CAMCORDER_STATE_PREPARE; break; + case 'n' : /* Capture video snapshot */ + err = mm_camcorder_capture_start(hcamcorder->camcorder); + break; + default : g_print("\t Invalid input \n"); break; @@ -1152,9 +1048,7 @@ static void main_menu(gchar buf) } else { err_msg_t("Wrong camcorder state, check status!!"); } - } - else if (hcamcorder->mode == MODE_AUDIO) - { + } else if (hcamcorder->mode == MODE_AUDIO) { if (mmcamcorder_state == MM_CAMCORDER_STATE_PREPARE) { switch(buf) { case '1' : // Start Recording @@ -1244,31 +1138,48 @@ static void setting_menu(gchar buf) int min = 0; int max = 0; int width_count = 0; - int heigh_count = 0; + int height_count = 0; int i=0; int count = 0; int value = 0; int* array = NULL; int *width_array = NULL; - int *heigh_array = NULL; + int *height_array = NULL; char *err_attr_name = NULL; cam_xypair_t input_pair; int err = MM_ERROR_NONE; int x = 0, y = 0, width = 0, height = 0; - double new_volume = 0.0; gint error_num=0; - if (hcamcorder->mode == MODE_IMAGE) - { - switch(buf) { - /* Camera setting */ + if (hcamcorder->mode == MODE_VIDEO_CAPTURE) { + switch (buf) { + /* Camera setting */ case '1' : // Setting > Capture Resolution setting + /* check recommend preview resolution */ + camcordertest_get_attr_valid_intarray(MMCAM_RECOMMEND_CAMERA_WIDTH, &width_array, &width_count); + camcordertest_get_attr_valid_intarray(MMCAM_RECOMMEND_CAMERA_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("MMCAM_RECOMMEND_CAMERA_WIDTH/HEIGHT Not supported!!\n"); + } else { + g_print("\n - MMCAM_RECOMMEND_CAMERA_WIDTH and HEIGHT (count %d) -\n", width_count); + g_print("\t NORMAL ratio : %dx%d\n", + width_array[MM_CAMCORDER_PREVIEW_TYPE_NORMAL], height_array[MM_CAMCORDER_PREVIEW_TYPE_NORMAL]); + if (width_count >= 2) { + g_print("\t WIDE ratio : %dx%d\n\n", + width_array[MM_CAMCORDER_PREVIEW_TYPE_WIDE], height_array[MM_CAMCORDER_PREVIEW_TYPE_WIDE]); + } else { + g_print("\t There is ONLY NORMAL resolution\n\n"); + } + } + g_print("*Select the resolution!\n"); camcordertest_get_attr_valid_intarray("capture-width", &width_array, &width_count); - camcordertest_get_attr_valid_intarray("capture-height", &heigh_array, &heigh_count); + camcordertest_get_attr_valid_intarray("capture-height", &height_array, &height_count); - if(width_count != heigh_count) { - err_msg_t("System has wrong information!!"); + if(width_count != height_count) { + err_msg_t("System has wrong information!!\n"); } else if (width_count == 0) { g_print("Not supported!!\n"); } else { @@ -1276,17 +1187,20 @@ static void setting_menu(gchar buf) flush_stdin(); for ( i = 0; i < width_count; i++) { - g_print("\t %d. %d*%d\n", i+1, width_array[i], heigh_array[i]); + g_print("\t %d. %d*%d\n", i+1, width_array[i], height_array[i]); } - scanf("%d",&index); - - if( index > 0 && index <= width_count ) { - //Set capture size first - input_pair.attr_subcat_x = "capture-width"; - input_pair.attr_subcat_y = "capture-height"; - input_pair.x = width_array[index-1]; - input_pair.y = heigh_array[index-1]; - bret = camcordertest_set_attr_xypair(input_pair); + err = scanf("%d",&index); + if (err == EOF) { + printf("\nscanf error : errno %d\n", errno); + } else { + if( index > 0 && index <= width_count ) { + //Set capture size first + input_pair.attr_subcat_x = "capture-width"; + input_pair.attr_subcat_y = "capture-height"; + input_pair.x = width_array[index-1]; + input_pair.y = height_array[index-1]; + bret = camcordertest_set_attr_xypair(input_pair); + } } } break; @@ -1300,7 +1214,7 @@ static void setting_menu(gchar buf) } else { flush_stdin(); g_print("\n Select Digital zoom level (%d ~ %d)\n", min, max); - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("camera-digital-zoom", index); } break; @@ -1314,25 +1228,47 @@ static void setting_menu(gchar buf) } else { flush_stdin(); g_print("\n Select Optical zoom level (%d ~ %d)\n", min, max); - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("camera-optical-zoom", index); } break; case '4' : // Setting > AF mode - g_print("*Focus mode !\n"); - camcordertest_get_attr_valid_intarray("camera-focus-mode", &array, &count); + g_print("\t0. AF Mode setting !\n"); + g_print("\t1. AF Start !\n"); + g_print("\t2. AF Stop !\n\n"); - if(count <= 0) { - g_print("Not supported !! \n"); - } else { - g_print("\n Select Focus mode \n"); - flush_stdin(); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], focus_mode[array[i]]); + flush_stdin(); + err = scanf("%d", &index); + + switch (index) { + case 0: + { + g_print("*Focus mode !\n"); + camcordertest_get_attr_valid_intarray("camera-focus-mode", &array, &count); + + if(count <= 0) { + g_print("Not supported !! \n"); + } else { + g_print("\n Select Focus mode \n"); + flush_stdin(); + for (i = 0 ; i < count ; i++) { + g_print("\t %d. %s\n", array[i], focus_mode[array[i]]); + } + err = scanf("%d",&index); + bret = camcordertest_set_attr_int("camera-focus-mode", index); } - scanf("%d",&index); - bret = camcordertest_set_attr_int("camera-focus-mode", index); + } + break; + case 1: + mm_camcorder_start_focusing(hcamcorder->camcorder); + break; + case 2: + mm_camcorder_stop_focusing(hcamcorder->camcorder); + break; + default: + g_print("Wrong Input[%d] !! \n", index); + break; } break; @@ -1348,12 +1284,8 @@ static void setting_menu(gchar buf) for ( i = 0; i < count; i++) { g_print("\t %d. %s\n", array[i], af_scan[array[i]]); } - scanf("%d",&index); - bret = camcordertest_set_attr_int("camera-af-scan-range", index); - - if( bret ) { - mm_camcorder_start_focusing(hcamcorder->camcorder); - } + err = scanf("%d",&index); + camcordertest_set_attr_int("camera-af-scan-range", index); } break; @@ -1369,7 +1301,7 @@ static void setting_menu(gchar buf) for ( i = 0; i < count; i++) { g_print("\t %d. %s\n", array[i], exposure_mode[array[i]]); } - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("camera-exposure-mode", index); } break; @@ -1383,7 +1315,7 @@ static void setting_menu(gchar buf) } else { flush_stdin(); g_print("\n Select Exposure value(%d ~ %d)\n", min, max); - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("camera-exposure-value", index); } break; @@ -1404,7 +1336,7 @@ static void setting_menu(gchar buf) for ( i = 0; i < count; i++) { g_print("\t %d. %d \n", i+1, array[i]); } - scanf("%d",&index); + err = scanf("%d",&index); if( index > 0 && index <= count ) { bret = camcordertest_set_attr_int("camera-shutter-speed", array[index-1]); @@ -1424,32 +1356,48 @@ static void setting_menu(gchar buf) for ( i = 0; i < count; i++) { g_print("\t %d. %s\n", array[i], iso_name[array[i]]); } - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("camera-iso", index); } break; case 'r' : // Setting > Rotate camera input when recording - g_print("*Rotate camera input when recording !\n"); - camcordertest_get_attr_valid_intarray(MMCAM_CAMERA_ROTATION, &array, &count); + g_print("*Rotate camera input\n"); + camcordertest_get_attr_valid_intrange(MMCAM_CAMERA_ROTATION, &min, &max); - if(count <= 0) { + if(min >= max) { g_print("Not supported !! \n"); } else { - g_print("\n Select Rotate angle of camera \n"); flush_stdin(); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], camera_rotation[array[i]]); + for (i = min ; i <= max ; i++) { + g_print("\t %d. %s\n", i, camera_rotation[i]); } - scanf("%d",&index); - bret = camcordertest_set_attr_int(MMCAM_CAMERA_ROTATION, index); + err = scanf("%d",&index); CHECK_MM_ERROR(mm_camcorder_stop(hcamcorder->camcorder)); - CHECK_MM_ERROR(mm_camcorder_unrealize(hcamcorder->camcorder)); - CHECK_MM_ERROR(mm_camcorder_realize(hcamcorder->camcorder)); + bret = camcordertest_set_attr_int(MMCAM_CAMERA_ROTATION, index); CHECK_MM_ERROR(mm_camcorder_start(hcamcorder->camcorder)); } break; + case 'f' : // Setting > Flip camera input + flush_stdin(); + g_print("*Flip camera input\n"); + g_print(" 0. Flip NONE\n"); + g_print(" 1. Flip HORIZONTAL\n"); + g_print(" 2. Flip VERTICAL\n"); + g_print(" 3. Flip BOTH\n"); + + err = scanf("%d", &index); + + CHECK_MM_ERROR(mm_camcorder_stop(hcamcorder->camcorder)); + CHECK_MM_ERROR(mm_camcorder_unrealize(hcamcorder->camcorder)); + + camcordertest_set_attr_int(MMCAM_CAMERA_FLIP, index); + + CHECK_MM_ERROR(mm_camcorder_realize(hcamcorder->camcorder)); + CHECK_MM_ERROR(mm_camcorder_start(hcamcorder->camcorder)); + break; + case 'j' : // Setting > Jpeg quality g_print("*Jpeg quality !\n"); camcordertest_get_attr_valid_intrange("image-encoder-quality", &min, &max); @@ -1459,7 +1407,7 @@ static void setting_menu(gchar buf) } else { flush_stdin(); g_print("\n Select Jpeg quality (%d ~ %d)\n", min, max); - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("image-encoder-quality", index); } break; @@ -1476,7 +1424,7 @@ static void setting_menu(gchar buf) for ( i = 0; i < count; i++) { g_print("\t %d. %s\n", array[i], image_fmt[array[i]]); } - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("camera-format", index); CHECK_MM_ERROR(mm_camcorder_stop(hcamcorder->camcorder)); CHECK_MM_ERROR(mm_camcorder_unrealize(hcamcorder->camcorder)); @@ -1485,7 +1433,30 @@ static void setting_menu(gchar buf) } break; - /* Display / Filter setting */ + case 'E' : // Setting > EXIF orientation + g_print("* EXIF Orientation\n"); + + g_print("\t 1. TOP_LEFT\n"); + g_print("\t 2. TOP_RIGHT(flipped)\n"); + g_print("\t 3. BOTTOM_RIGHT\n"); + g_print("\t 4. BOTTOM_LEFT(flipped)\n"); + g_print("\t 5. LEFT_TOP(flipped)\n"); + g_print("\t 6. RIGHT_TOP\n"); + g_print("\t 7. RIGHT_BOTTOM(flipped)\n"); + g_print("\t 8. LEFT_BOTTOM\n"); + + flush_stdin(); + err = scanf("%d", &index); + + if (index < 1 || index > 8) { + g_print("Wrong INPUT[%d]!! \n", index); + } else { + camcordertest_set_attr_int(MMCAM_TAG_ORIENTATION, index); + } + + break; + + /* Display / Filter setting */ case 'v' : // Display visible g_print("* Display visible setting !\n"); camcordertest_get_attr_valid_intarray( "display-visible", &array, &count ); @@ -1498,11 +1469,28 @@ static void setting_menu(gchar buf) for ( i = 0; i < count; i++) { g_print("\t %d. %s\n", array[i], visible_mode[array[i]]); } - scanf("%d",&value); + err = scanf("%d",&value); bret = camcordertest_set_attr_int( "display-visible", value ); } break; + case 'n' : // Setting > Display mode + g_print("* Display mode!\n"); + camcordertest_get_attr_valid_intarray(MMCAM_DISPLAY_MODE, &array, &count); + + if (count <= 0 || count > 255) { + g_print("Not supported !! \n"); + } else { + flush_stdin(); + g_print("\n Select Display mode\n"); + for (i = 0 ; i < count ; i++) { + g_print("\t %d. %s\n", array[i], display_mode[array[i]]); + } + err = scanf("%d",&index); + bret = camcordertest_set_attr_int(MMCAM_DISPLAY_MODE, index); + } + break; + case 'o' : // Setting > Output mode g_print("* Output mode!\n"); camcordertest_get_attr_valid_intrange("display-geometry-method", &min, &max); @@ -1515,27 +1503,33 @@ static void setting_menu(gchar buf) for( i = min ; i <= max ; i++ ) { g_print( "%d. %s\n", i, output_mode[i] ); } - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("display-geometry-method", index); } break; case 'y' : // Setting > Rotate Display - camcordertest_get_attr_valid_intarray( MMCAM_DISPLAY_ROTATION, &array, &count ); + camcordertest_get_attr_valid_intrange(MMCAM_DISPLAY_ROTATION, &min, &max); - if( count <= 0 || count > 256 ) { + if( min > max ) { g_print("Not supported !! \n"); } else { flush_stdin(); - g_print("\n Select Rotation mode\n"); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], rotate_mode[array[i]]); - } - scanf("%d",&index); - bret = camcordertest_set_attr_int( MMCAM_DISPLAY_ROTATION, index ); + g_print("\n Select Rotate mode(%d ~ %d)\n", min, max); + g_print("\t0. 0\n\t1. 90\n\t2. 180\n\t3. 270\n\n"); + err = scanf("%d",&index); + bret = camcordertest_set_attr_int(MMCAM_DISPLAY_ROTATION, index); } break; + case 'Y' : // Setting > Flip Display + flush_stdin(); + g_print("\n Select Rotate mode(%d ~ %d)\n", min, max); + g_print("\t0. NONE\n\t1. HORIZONTAL\n\t2. VERTICAL\n\t3. BOTH\n\n"); + err = scanf("%d",&index); + camcordertest_set_attr_int(MMCAM_DISPLAY_FLIP, index); + break; + case 'g' : // Setting > Brightness g_print("*Brightness !\n"); camcordertest_get_attr_valid_intrange("filter-brightness", &min, &max); @@ -1545,7 +1539,7 @@ static void setting_menu(gchar buf) } else { flush_stdin(); g_print("\n Select brightness (%d ~ %d)\n", min, max); - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("filter-brightness", index); } break; @@ -1559,7 +1553,7 @@ static void setting_menu(gchar buf) } else { flush_stdin(); g_print("\n Select Contrast (%d ~ %d)\n", min, max); - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("filter-contrast", index); } break; @@ -1573,7 +1567,7 @@ static void setting_menu(gchar buf) } else { flush_stdin(); g_print("\n Select Saturation (%d ~ %d)\n", min, max); - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("filter-saturation", index); } break; @@ -1587,7 +1581,7 @@ static void setting_menu(gchar buf) } else { flush_stdin(); g_print("\n Select Hue (%d ~ %d)\n", min, max); - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("filter-hue", index); } break; @@ -1601,7 +1595,7 @@ static void setting_menu(gchar buf) } else { flush_stdin(); g_print("\n Select Sharpness (%d ~ %d)\n", min, max); - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("filter-sharpness", index); } break; @@ -1618,7 +1612,7 @@ static void setting_menu(gchar buf) for ( i = 0; i < count; i++) { g_print("\t %d. %s\n", array[i], wb[array[i]]); } - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("filter-wb", index); } break; @@ -1635,7 +1629,7 @@ static void setting_menu(gchar buf) for ( i = 0; i < count; i++) { g_print("\t %d. %s\n", array[i], ct[array[i]]); } - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("filter-color-tone", index); } break; @@ -1653,7 +1647,7 @@ static void setting_menu(gchar buf) for ( i = 0; i < count; i++) { g_print("\t %d. %s\n", array[i], wdr_mode[array[i]]); } - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("camera-wdr", index); } break; @@ -1670,12 +1664,12 @@ static void setting_menu(gchar buf) for ( i = 0; i < count; i++) { g_print("\t %d. %s\n", array[i], program_mode[array[i]]); } - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("filter-scene-mode", index); } break; - /* ext. setting */ + /* ext. setting */ case 'z' : // Setting > Strobe setting g_print("*Strobe Mode\n"); camcordertest_get_attr_valid_intarray("strobe-mode", &array, &count); @@ -1687,7 +1681,7 @@ static void setting_menu(gchar buf) for ( i = 0; i < count; i++) { g_print("\t %d. %s\n", array[i], strobe_mode[array[i]]); } - scanf("%d",&index); + err = scanf("%d",&index); bret = camcordertest_set_attr_int("strobe-mode", index); } break; @@ -1695,15 +1689,20 @@ static void setting_menu(gchar buf) case 'x' : // Setting > Capture mode ,Muitishot? g_print("*Select Capture mode!\n"); flush_stdin(); - g_print(" \n\t1. Stillshot mode\n\t2. Multishot mode \n"); - scanf("%d",&index); + g_print(" \n\t1. Stillshot mode\n\t2. Multishot mode\n\t3. HDR capture\n"); + err = scanf("%d",&index); - if(index == 1) { + switch (index) { + case 1: g_print("stillshot mode selected and capture callback is set!!!!\n"); hcamcorder->isMultishot = FALSE; - } else if (index == 2) { + camcordertest_set_attr_int(MMCAM_CAMERA_HDR_CAPTURE, 0); + break; + case 2: g_print("Multilshot mode selected!!\n"); + camcordertest_set_attr_int(MMCAM_CAMERA_HDR_CAPTURE, 0); + index = 0; min = 0; max = 0; @@ -1715,650 +1714,176 @@ static void setting_menu(gchar buf) flush_stdin(); //g_print("\n Check Point!!! [Change resolution to 800x480]\n"); g_print("Select mulitshot number (%d ~ %d)\n", min, max); - scanf("%d",&index); + err = scanf("%d",&index); if( index >= min && index <= max ) { multishot_num = index; + mm_camcorder_set_attributes(hcamcorder->camcorder, &err_attr_name, + MMCAM_CAPTURE_COUNT, multishot_num, + NULL); hcamcorder->isMultishot = TRUE; } else { g_print("Wrong input value, Multishot setting failed!!\n"); } } - } else { - g_print("Wrong input, select again!!\n"); - } - break; + break; + case 3: + g_print("HDR Capture mode selected\n"); + hcamcorder->isMultishot = FALSE; - case 'f' : // Setting > Face detection setting - //hcamcorder->menu_state = MENU_STATE_SETTING_DETECTION; - g_print("* Face detect mode !\n"); - - camcordertest_get_attr_valid_intarray("detect-mode", &array, &count); - if(count <= 0 || count > 256) { - g_print("Not supported !! \n"); - } else { - g_print("\n Face detect mode \n"); - flush_stdin(); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s \n", array[i], detection_mode[array[i]]); - } - scanf("%d",&index); - - if( index >= 0 && index < count ) { - bret = camcordertest_set_attr_int("detect-mode", array[index]); - } else { - g_print("Wrong input value. Try again!!\n"); - bret = FALSE; - } - } - break; - - case 'k' : // Setting > Anti-handshake - g_print("*Anti-handshake !\n"); - camcordertest_get_attr_valid_intarray("camera-anti-handshake", &array, &count); - - if(count <= 0) { - g_print("Not supported !! \n"); - } else { - g_print("\n Select Anti-handshake mode \n"); - flush_stdin(); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], ahs_mode[array[i]]); - } - scanf("%d",&index); - bret = camcordertest_set_attr_int("camera-anti-handshake", index); - } - break; - - case 'u': // Touch AF area - g_print("* Touch AF area !\n"); - camcordertest_get_attr_valid_intrange("camera-af-touch-x", &min, &max); - if( max < min ) { - g_print( "Not Supported camera-af-touch-x !!\n" ); - break; - } - camcordertest_get_attr_valid_intrange("camera-af-touch-y", &min, &max); - if( max < min ) { - g_print( "Not Supported camera-af-touch-y !!\n" ); - break; - } - camcordertest_get_attr_valid_intrange("camera-af-touch-width", &min, &max); - if( max < min ) { - g_print( "Not Supported camera-af-touch-width !!\n" ); - break; - } - camcordertest_get_attr_valid_intrange("camera-af-touch-height", &min, &max); - if( max < min ) { - g_print( "Not Supported camera-af-touch-height!!\n" ); - break; - } - - flush_stdin(); - g_print( "\n Input x,y,width,height \n" ); - scanf( "%d,%d,%d,%d", &x, &y, &width, &height ); - err = mm_camcorder_set_attributes(hcamcorder->camcorder, &err_attr_name, - MMCAM_CAMERA_AF_TOUCH_X, x, - MMCAM_CAMERA_AF_TOUCH_Y, y, - MMCAM_CAMERA_AF_TOUCH_WIDTH, width, - MMCAM_CAMERA_AF_TOUCH_HEIGHT, height, - NULL); - - if( err != MM_ERROR_NONE ) { - g_print( "Failed to set touch AF area.(%x)(%s)\n", err, err_attr_name ); - free( err_attr_name ); - err_attr_name = NULL; - } else { - g_print( "Succeed to set touch AF area.\n" ); - } - break; - - case 'm' : // Setting > Stream callback function - g_print("Not supported !! \n"); - break; - - case 'b' : // back - hcamcorder->menu_state = MENU_STATE_MAIN; - break; - - default : - g_print("\t Invalid input \n"); - break; - } - } - else if(hcamcorder->mode == MODE_VIDEO) - { - switch(buf) - { - /* Camera setting */ - case '1' : // Setting > Recording Resolution - g_print("*Select resolution!\n"); - - camcordertest_get_attr_valid_intarray("camera-width", &width_array, &width_count); - camcordertest_get_attr_valid_intarray("camera-height", &heigh_array, &heigh_count); - - if(width_count != heigh_count) { - err_msg_t("System has wrong information!!"); - } else if(width_count == 0) { - g_print("Not supported !! \n"); - } else { - g_print("\n Select the resolution \n"); - flush_stdin(); - for ( i = 0; i < width_count; i++) { - g_print("\t %d. %d*%d\n", i+1, width_array[i], heigh_array[i]); - } - scanf("%d",&index); - - if( index > 0 && index <= width_count ) { - g_timer_reset(timer); - CHECK_MM_ERROR(mm_camcorder_stop(hcamcorder->camcorder)); - CHECK_MM_ERROR(mm_camcorder_unrealize(hcamcorder->camcorder)); - - //Set source size - input_pair.attr_subcat_x = "camera-width"; - input_pair.attr_subcat_y = "camera-height"; - input_pair.x = width_array[index-1]; - input_pair.y = heigh_array[index-1]; - - bret = camcordertest_set_attr_xypair(input_pair); - - CHECK_MM_ERROR(mm_camcorder_realize(hcamcorder->camcorder)); - CHECK_MM_ERROR(mm_camcorder_start(hcamcorder->camcorder)); - time_msg_t("Resolution change : %12.6lf s", g_timer_elapsed(timer, NULL)); - } else { - warn_msg_t( "Out of index" ); - } - } - break; - - case '2' : // Setting > Digital zoom level - g_print("*Digital zoom level !\n"); - camcordertest_get_attr_valid_intrange("camera-digital-zoom", &min, &max); - - if(min >= max) { - g_print("Not supported !! \n"); - } else { - flush_stdin(); - g_print("\n Select Digital zoom level (%d ~ %d)\n", min, max); - scanf("%d",&index); - bret = camcordertest_set_attr_int("camera-digital-zoom", index); - } - break; - - case '3' : // Setting > Optical zoom level - g_print("*Optical zoom level !\n"); - camcordertest_get_attr_valid_intrange("camera-optical-zoom", &min, &max); - - if(min >= max) { - g_print("Not supported !! \n"); - } else { - flush_stdin(); - g_print("\n Select Optical zoom level (%d ~ %d)\n", min, max); - scanf("%d",&index); - bret = camcordertest_set_attr_int("camera-optical-zoom", index); - } - break; - - case '4' : // Setting > AF mode - g_print("*Focus mode !\n"); - camcordertest_get_attr_valid_intarray("camera-focus-mode", &array, &count); - - if(count <= 0) { - g_print("Not supported !! \n"); - } else { - g_print("\n Select Focus mode \n"); - flush_stdin(); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], focus_mode[array[i]]); - } - scanf("%d",&index); - bret = camcordertest_set_attr_int("camera-focus-mode", index); - } - break; - - case '5' : // Setting > AF scan range - g_print("*AF scan range !\n"); - camcordertest_get_attr_valid_intarray("camera-af-scan-range", &array, &count); - - if(count <= 0) { - g_print("Not supported !! \n"); - } else { - g_print("\n Select AF scan range \n"); - flush_stdin(); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], af_scan[array[i]]); - } - scanf("%d",&index); - bret = camcordertest_set_attr_int("camera-af-scan-range", index); - - if( bret ) { - mm_camcorder_start_focusing(hcamcorder->camcorder); - } - } - break; - - case '6' : // Setting > Exposure mode - g_print("* Exposure mode!\n"); - camcordertest_get_attr_valid_intarray("camera-exposure-mode", &array, &count); - - if(count <= 0) { - g_print("Not supported !! \n"); - } else { - g_print("\n Select Exposure mode \n"); - flush_stdin(); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], exposure_mode[array[i]]); - } - scanf("%d",&index); - bret = camcordertest_set_attr_int("camera-exposure-mode", index); - } - break; - - case '7' : // Setting > Exposure value - g_print("*Exposure value !\n"); - camcordertest_get_attr_valid_intrange("camera-exposure-value", &min, &max); - - if(min >= max) { - g_print("Not supported !! \n"); - } else { - flush_stdin(); - g_print("\n Select Exposure value(%d ~ %d)\n", min, max); - scanf("%d",&index); - bret = camcordertest_set_attr_int("camera-exposure-value", index); - } - break; - - case '8' : // Setting > F number - g_print("Not supported !! \n"); - break; - - case 'i' : // Setting > ISO - g_print("*ISO !\n"); - camcordertest_get_attr_valid_intarray("camera-iso", &array, &count); - - if(count <= 0) { - g_print("Not supported !! \n"); - } else { - g_print("\n Select ISO \n"); - flush_stdin(); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], iso_name[array[i]]); - } - scanf("%d",&index); - bret = camcordertest_set_attr_int("camera-iso", index); - } - break; - - case 'r' : // Setting > Rotate camera input when recording - g_print("*Rotate camera input !\n"); - camcordertest_get_attr_valid_intarray(MMCAM_CAMERA_ROTATION, &array, &count); - - if(count <= 0) { - g_print("Not supported !! \n"); - } else { - g_print("\n Select Rotate angle of camera (Do Not use it for recording test !!) \n"); - flush_stdin(); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], camera_rotation[array[i]]); - } - scanf("%d",&index); - - CHECK_MM_ERROR(mm_camcorder_stop(hcamcorder->camcorder)); - CHECK_MM_ERROR(mm_camcorder_unrealize(hcamcorder->camcorder)); - - bret = camcordertest_set_attr_int(MMCAM_CAMERA_ROTATION, index); - - CHECK_MM_ERROR(mm_camcorder_realize(hcamcorder->camcorder)); - CHECK_MM_ERROR(mm_camcorder_start(hcamcorder->camcorder)); - } - break; - - case 'p' : // Setting > FPS - g_print("* FPS !\n"); - - camcordertest_get_attr_valid_intarray("camera-fps", &array, &count); - - if(count <= 0 || count > 256) - { - g_print("Not supported !! \n"); - } - else - { - g_print("\n Select FPS \n"); - flush_stdin(); - for ( i = 0; i < count; i++) - { - g_print("\t %d. %d \n", i+1, array[i]); - } - scanf("%d",&index); - - if( index > 0 && index <= count ) - { - bret = camcordertest_set_attr_int("camera-fps", array[index-1]); - hcamcorder->fps = array[index-1]; - } - else - { - bret = FALSE; - g_print("\n Out of index \n"); - } - } - break; - - /* Display / Filter setting */ - case 'v' : // Setting > Display visible - g_print("* Display visible setting !\n"); - camcordertest_get_attr_valid_intarray( "display-visible", &array, &count ); - - if( count < 1 ) { - g_print("Not supported !! \n"); - } else { - g_print("\n Select Display visible \n"); - flush_stdin(); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], visible_mode[array[i]]); - } - scanf("%d",&value); - bret = camcordertest_set_attr_int( "display-visible", value ); - } - break; - - case 'o' : // Setting > Output mode - g_print("* Output mode!\n"); - camcordertest_get_attr_valid_intrange("display-geometry-method", &min, &max); - - if( min > max ) { - g_print("Not supported !! \n"); - } else { - flush_stdin(); - g_print("\n Select Output mode(%d ~ %d)\n", min, max); - for( i = min ; i <= max ; i++ ) { - g_print( "%d. %s\n", i, output_mode[i] ); - } - scanf("%d",&index); - bret = camcordertest_set_attr_int("display-geometry-method", index); - } - break; - - case 'y' : // Setting > Rotate Display - camcordertest_get_attr_valid_intarray( MMCAM_DISPLAY_ROTATION, &array, &count ); - - if( count <= 0 || count > 256 ) { - g_print("Not supported !! \n"); - } else { - flush_stdin(); - g_print("\n Select Rotation mode\n"); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], rotate_mode[array[i]]); - } - scanf("%d",&index); - bret = camcordertest_set_attr_int( MMCAM_DISPLAY_ROTATION, index ); - } - break; - - case 'g' : // Setting > Brightness - g_print("*Brightness !\n"); - camcordertest_get_attr_valid_intrange("filter-brightness", &min, &max); - - if(min >= max) { - g_print("Not supported !! \n"); - } else { - flush_stdin(); - g_print("\n Select brightness (%d ~ %d)\n", min, max); - scanf("%d",&index); - bret = camcordertest_set_attr_int("filter-brightness", index); - } - break; - - case 'c' : // Setting > Contrast - g_print("*Contrast !\n"); - camcordertest_get_attr_valid_intrange("filter-contrast", &min, &max); - - if(min >= max) { - g_print("Not supported !! \n"); - } else { - flush_stdin(); - g_print("\n Select Contrast (%d ~ %d)\n", min, max); - scanf("%d",&index); - bret = camcordertest_set_attr_int("filter-contrast", index); - } - break; - - case 's' : // Setting > Saturation - g_print("*Saturation !\n"); - camcordertest_get_attr_valid_intrange("filter-saturation", &min, &max); - - if(min >= max) { - g_print("Not supported !! \n"); - } else { - flush_stdin(); - g_print("\n Select Saturation (%d ~ %d)\n", min, max); - scanf("%d",&index); - bret = camcordertest_set_attr_int("filter-saturation", index); - } - break; - - case 'h' : // Setting > Hue - g_print("*Hue !\n"); - camcordertest_get_attr_valid_intrange("filter-hue", &min, &max); - - if(min >= max) { - g_print("Not supported !! \n"); - } else { - flush_stdin(); - g_print("\n Select Hue (%d ~ %d)\n", min, max); - scanf("%d",&index); - bret = camcordertest_set_attr_int("filter-hue", index); - } - break; - - case 'a' : // Setting > Sharpness - g_print("*Sharpness !\n"); - camcordertest_get_attr_valid_intrange("filter-sharpness", &min, &max); - - if(min >= max) { - g_print("Not supported !! \n"); - } else { - flush_stdin(); - g_print("\n Select Sharpness (%d ~ %d)\n", min, max); - scanf("%d",&index); - bret = camcordertest_set_attr_int("filter-sharpness", index); + camcordertest_get_attr_valid_intarray(MMCAM_CAMERA_HDR_CAPTURE, &array, &count); + if(count <= 0) { + g_print("Not supported !! \n"); + } else { + g_print("\nSelect HDR capture mode\n"); + flush_stdin(); + for ( i = 0; i < count; i++) { + g_print("\t %d. %s\n", array[i], hdr_mode[array[i]]); + } + err = scanf("%d",&index); + bret = camcordertest_set_attr_int(MMCAM_CAMERA_HDR_CAPTURE, index); + } + break; + default: + g_print("Wrong input, select again!!\n"); + break; } break; - case 'w' : // Setting > White balance - g_print("*White balance !\n"); - camcordertest_get_attr_valid_intarray("filter-wb", &array, &count); + case 'l' : // Setting > Face detection setting + //hcamcorder->menu_state = MENU_STATE_SETTING_DETECTION; + g_print("* Face detect mode !\n"); - if(count <= 0) { + camcordertest_get_attr_valid_intarray("detect-mode", &array, &count); + if(count <= 0 || count > 256) { g_print("Not supported !! \n"); } else { + g_print("\n Face detect mode \n"); flush_stdin(); - g_print("\n Select White balance \n"); for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], wb[array[i]]); + g_print("\t %d. %s \n", array[i], detection_mode[array[i]]); + } + err = scanf("%d",&index); + + if( index >= 0 && index < count ) { + bret = camcordertest_set_attr_int("detect-mode", array[index]); + } else { + g_print("Wrong input value. Try again!!\n"); + bret = FALSE; } - scanf("%d",&index); - bret = camcordertest_set_attr_int("filter-wb", index); } break; - case 't' : // Setting > Color tone - g_print("*Color tone !\n"); - camcordertest_get_attr_valid_intarray("filter-color-tone", &array, &count); + case 'k' : // Setting > Anti-handshake + g_print("*Anti-handshake !\n"); + camcordertest_get_attr_valid_intarray(MMCAM_CAMERA_ANTI_HANDSHAKE, &array, &count); if(count <= 0) { g_print("Not supported !! \n"); } else { - g_print("\n Select Color tone \n"); + g_print("\n Select Anti-handshake mode \n"); flush_stdin(); for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], ct[array[i]]); + g_print("\t %d. %s\n", array[i], ahs_mode[array[i]]); } - scanf("%d",&index); - bret = camcordertest_set_attr_int("filter-color-tone", index); + err = scanf("%d",&index); + bret = camcordertest_set_attr_int(MMCAM_CAMERA_ANTI_HANDSHAKE, index); } break; - case 'd' : // Setting > WDR - g_print("*WDR !\n"); - camcordertest_get_attr_valid_intarray("camera-wdr", &array, &count); + case 'K' : // Setting > Video-stabilization + g_print("*Video-stabilization !\n"); + camcordertest_get_attr_valid_intarray(MMCAM_CAMERA_VIDEO_STABILIZATION, &array, &count); if(count <= 0) { g_print("Not supported !! \n"); - } - else { - g_print("\n Select WDR Mode \n"); + } else { + g_print("\n Select Video-stabilization mode \n"); flush_stdin(); for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], wdr_mode[array[i]]); + g_print("\t %d. %s\n", array[i], vs_mode[array[i]]); } - scanf("%d",&index); - bret = camcordertest_set_attr_int("camera-wdr", index); - } - break; - - /* ext. setting */ - case 'x' : // Setting > High Speed - { - static int backup_width = 0; - static int backup_height = 0; - - g_print("\n Select High Speed Recording mode\n"); - g_print("\t 1. High Speed Recording mode ON\n"); - g_print("\t 2. High Speed Recording mode OFF \n"); + err = scanf("%d",&index); - flush_stdin(); - scanf("%d",&index); - if (index == 1) { - mm_camcorder_get_attributes(hcamcorder->camcorder, &err_attr_name, - MMCAM_CAMERA_WIDTH, &backup_width, - MMCAM_CAMERA_HEIGHT, &backup_height, - NULL); - - CHECK_MM_ERROR(mm_camcorder_stop(hcamcorder->camcorder)); - CHECK_MM_ERROR(mm_camcorder_unrealize(hcamcorder->camcorder)); - - err = mm_camcorder_set_attributes(hcamcorder->camcorder, &err_attr_name, - MMCAM_CAMERA_WIDTH, 320, - MMCAM_CAMERA_HEIGHT, 240, - MMCAM_CAMERA_FPS, 120, - "camera-slow-motion-fps", 30, - NULL); - if (err != MM_ERROR_NONE) { - warn_msg_t("High speed recording. mm_camcorder_set_attributes fail. (%s:%x)", err_attr_name, err); - SAFE_FREE(err_attr_name); - } + if (index == MM_CAMCORDER_VIDEO_STABILIZATION_ON) { + g_print("\n Restart preview with NV12 and 720p resolution\n"); - CHECK_MM_ERROR(mm_camcorder_realize(hcamcorder->camcorder)); - CHECK_MM_ERROR(mm_camcorder_start(hcamcorder->camcorder)); + err = mm_camcorder_stop(hcamcorder->camcorder); + if (err == MM_ERROR_NONE) { + err = mm_camcorder_unrealize(hcamcorder->camcorder); + } - } else if(index == 2) { - CHECK_MM_ERROR(mm_camcorder_stop(hcamcorder->camcorder)); - CHECK_MM_ERROR(mm_camcorder_unrealize(hcamcorder->camcorder)); + input_pair.attr_subcat_x = MMCAM_CAMERA_WIDTH; + input_pair.attr_subcat_y = MMCAM_CAMERA_HEIGHT; + input_pair.x = 1280; + input_pair.y = 720; + camcordertest_set_attr_xypair(input_pair); + camcordertest_set_attr_int(MMCAM_CAMERA_FORMAT, MM_PIXEL_FORMAT_NV12); + camcordertest_set_attr_int(MMCAM_CAMERA_VIDEO_STABILIZATION, index); + + if (err == MM_ERROR_NONE) { + err = mm_camcorder_realize(hcamcorder->camcorder); + if (err == MM_ERROR_NONE) { + err = mm_camcorder_start(hcamcorder->camcorder); + } + } - if (backup_width && backup_height) { - err = mm_camcorder_set_attributes(hcamcorder->camcorder, &err_attr_name, - MMCAM_CAMERA_WIDTH, backup_width, - MMCAM_CAMERA_HEIGHT, backup_height, - NULL); if (err != MM_ERROR_NONE) { - warn_msg_t("get_attributes fail. (%s:%x)", err_attr_name, err); - SAFE_FREE (err_attr_name); + g_print("\n Restart FAILED! %x\n", err); } + } else { + camcordertest_set_attr_int(MMCAM_CAMERA_VIDEO_STABILIZATION, index); } - - err = mm_camcorder_set_attributes(hcamcorder->camcorder, &err_attr_name, - MMCAM_CAMERA_FPS, SRC_VIDEO_FRAME_RATE_30, - "camera-slow-motion-fps", 0, - NULL); - if (err != MM_ERROR_NONE) { - warn_msg_t("Normal speed recording. mm_camcorder_set_attributes fail. (%s:%x)", err_attr_name, err); - SAFE_FREE (err_attr_name); - } - - CHECK_MM_ERROR(mm_camcorder_realize(hcamcorder->camcorder)); - CHECK_MM_ERROR(mm_camcorder_start(hcamcorder->camcorder)); - } else { - g_print("Wrong input, Try again!!\n"); } break; - } - case 'u' : // Setting > Mute - g_print("*Mute!(%d)\n", hcamcorder->isMute); - if (hcamcorder->isMute) { - new_volume = 0.0; - } else { - new_volume = 1.0; + case 'u': // Touch AF area + g_print("* Touch AF area !\n"); + camcordertest_get_attr_valid_intrange("camera-af-touch-x", &min, &max); + if( max < min ) { + g_print( "Not Supported camera-af-touch-x !!\n" ); + break; } - - err = mm_camcorder_set_attributes(hcamcorder->camcorder, &err_attr_name, - MMCAM_AUDIO_VOLUME, new_volume, - NULL); - if (err < 0) { - warn_msg_t("Can' Mute. mm_camcorder_set_attributes fail. (%s:%x)", err_attr_name, err); - SAFE_FREE (err_attr_name); + camcordertest_get_attr_valid_intrange("camera-af-touch-y", &min, &max); + if( max < min ) { + g_print( "Not Supported camera-af-touch-y !!\n" ); + break; } - - hcamcorder->isMute = !(hcamcorder->isMute); - break; - - case 'z' : // Setting > Strobe setting - g_print("*Strobe Mode\n"); - camcordertest_get_attr_valid_intarray("strobe-mode", &array, &count); - if(count <= 0) { - g_print("Not supported !! \n"); - } else { - g_print("\n Select Strobe Mode \n"); - flush_stdin(); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], strobe_mode[array[i]]); - } - scanf("%d",&index); - bret = camcordertest_set_attr_int("strobe-mode", index); + camcordertest_get_attr_valid_intrange("camera-af-touch-width", &min, &max); + if( max < min ) { + g_print( "Not Supported camera-af-touch-width !!\n" ); + break; } - break; - - case 'k' : // Setting > Anti-handshake - g_print("*Anti-handshake !\n"); - camcordertest_get_attr_valid_intarray("camera-anti-handshake", &array, &count); - - if(count <= 0) { - g_print("Not supported !! \n"); - } else { - g_print("\n Select Anti-handshake mode \n"); - flush_stdin(); - for ( i = 0; i < count; i++) { - g_print("\t %d. %s\n", array[i], ahs_mode[array[i]]); - } - scanf("%d",&index); - bret = camcordertest_set_attr_int("camera-anti-handshake", index); + camcordertest_get_attr_valid_intrange("camera-af-touch-height", &min, &max); + if( max < min ) { + g_print( "Not Supported camera-af-touch-height!!\n" ); + break; } - break; - case 'e' : // Setting > Camcorder-rotation setting - g_print("*Camcorder-rotation setting!\n"); - camcordertest_get_attr_valid_intrange("camcorder-rotation", &min, &max); + flush_stdin(); + g_print( "\n Input x,y,width,height \n" ); + err = scanf( "%d,%d,%d,%d", &x, &y, &width, &height ); + err = mm_camcorder_set_attributes(hcamcorder->camcorder, &err_attr_name, + MMCAM_CAMERA_AF_TOUCH_X, x, + MMCAM_CAMERA_AF_TOUCH_Y, y, + MMCAM_CAMERA_AF_TOUCH_WIDTH, width, + MMCAM_CAMERA_AF_TOUCH_HEIGHT, height, + NULL); - if(min >= max) { - g_print("Not supported !! \n"); + if( err != MM_ERROR_NONE ) { + g_print( "Failed to set touch AF area.(%x)(%s)\n", err, err_attr_name ); + free( err_attr_name ); + err_attr_name = NULL; } else { - g_print("\n Select camcorder-rotation value \n"); - flush_stdin(); - for ( i = 0; i < (max-min+1); i++) { - g_print("\t %d. %s\n", i, camcorder_rotate_val[i]); - } - scanf("%d",&index); - bret = camcordertest_set_attr_int("camcorder-rotation", index); + g_print( "Succeed to set touch AF area.\n" ); } break; case 'm' : // Setting > Stream callback function g_print("\n Select Stream Callback Function\n"); g_print("\t 1. Set Video Stream Callback \n"); - g_print("\t 2. Set Audio Stream Callback \n"); - g_print("\t 3. Unset Stream Callback \n"); + g_print("\t 2. Unset Video Stream Callback \n"); flush_stdin(); - scanf("%d", &index); + err = scanf("%d", &index); if(index == 1) { video_stream_cb_cnt = 0; error_num = mm_camcorder_set_video_stream_callback(hcamcorder->camcorder, (mm_camcorder_video_stream_callback)camcordertest_video_stream_cb, (void*)hcamcorder->camcorder); @@ -2368,26 +1893,16 @@ static void setting_menu(gchar buf) g_print("\n Setting Failure\n"); } } else if(index == 2) { - audio_stream_cb_cnt = 0; - error_num = mm_camcorder_set_audio_stream_callback(hcamcorder->camcorder, (mm_camcorder_audio_stream_callback)camcordertest_audio_stream_cb, (void*)hcamcorder->camcorder); - if( error_num == MM_ERROR_NONE ) { - g_print("\n Setting Success\n"); - } else { - g_print("\n Setting Failure\n"); - } - } else if(index == 3) { mm_camcorder_set_video_stream_callback(hcamcorder->camcorder, NULL, (void*)hcamcorder->camcorder); - mm_camcorder_set_audio_stream_callback(hcamcorder->camcorder, NULL, (void*)hcamcorder->camcorder); video_stream_cb_cnt = 0; audio_stream_cb_cnt = 0; g_print("\n Unset stream callback success\n"); } else { g_print("\t Invalid input \n"); } - //g_print("Not supported !! \n"); break; - case 'b' : // back + case 'b' : // back hcamcorder->menu_state = MENU_STATE_MAIN; break; @@ -2395,9 +1910,7 @@ static void setting_menu(gchar buf) g_print("\t Invalid input \n"); break; } - } - else - { + } else { g_print("\t Invalid mode, back to upper menu \n"); hcamcorder->menu_state = MENU_STATE_MAIN; } @@ -2411,7 +1924,7 @@ static void setting_menu(gchar buf) * * @return This function returns TRUE/FALSE * @remark - * @see + * @see */ static gboolean cmd_input(GIOChannel *channel) { @@ -2482,29 +1995,28 @@ static gboolean init(int type) int size; int preview_format = MM_PIXEL_FORMAT_NV12; MMHandleType cam_handle = 0; - + char *err_attr_name = NULL; if (!hcamcorder) return FALSE; - + if(!hcamcorder->camcorder) return FALSE; cam_handle = (MMHandleType)(hcamcorder->camcorder); - + /*================================================================================ - image mode + Video capture mode *=================================================================================*/ - if (type == MODE_IMAGE) - { + if (type == MODE_VIDEO_CAPTURE) { mm_camcorder_get_attributes((MMHandleType)cam_handle, NULL, MMCAM_RECOMMEND_PREVIEW_FORMAT_FOR_CAPTURE, &preview_format, NULL); /* camcorder attribute setting */ err = mm_camcorder_set_attributes( (MMHandleType)cam_handle, &err_attr_name, - MMCAM_MODE, MM_CAMCORDER_MODE_IMAGE, + MMCAM_MODE, MM_CAMCORDER_MODE_VIDEO_CAPTURE, MMCAM_CAMERA_FORMAT, preview_format, "camera-delay-attr-setting", TRUE, MMCAM_IMAGE_ENCODER, MM_IMAGE_CODEC_JPEG, @@ -2520,73 +2032,40 @@ static gboolean init(int type) MMCAM_DISPLAY_RECT_WIDTH, 480, MMCAM_DISPLAY_RECT_HEIGHT, 640, MMCAM_DISPLAY_ROTATION, MM_DISPLAY_ROTATION_270, + //MMCAM_DISPLAY_FLIP, MM_FLIP_HORIZONTAL, MMCAM_DISPLAY_GEOMETRY_METHOD, MM_DISPLAY_METHOD_LETTER_BOX, MMCAM_CAPTURE_COUNT, IMAGE_CAPTURE_COUNT_STILL, "capture-thumbnail", TRUE, "tag-gps-time-stamp", 72815.5436243543, "tag-gps-date-stamp", "2010:09:20", 10, "tag-gps-processing-method", "GPS NETWORK HYBRID ARE ALL FINE.", 32, - "capture-sound-enable", TRUE, - NULL ); - - if (err != MM_ERROR_NONE) { - warn_msg_t("Init fail. (%s:%x)", err_attr_name, err); - SAFE_FREE (err_attr_name); - goto ERROR; - } - - mm_camcorder_set_video_capture_callback(hcamcorder->camcorder, (mm_camcorder_video_capture_callback)camcordertest_video_capture_cb, hcamcorder); - } - /*================================================================================ - video mode - *=================================================================================*/ - else if (type == MODE_VIDEO) - { - mm_camcorder_get_attributes((MMHandleType)cam_handle, NULL, - MMCAM_RECOMMEND_PREVIEW_FORMAT_FOR_RECORDING, &preview_format, - NULL); - - size = strlen(TARGET_FILENAME_VIDEO)+1; - - /* camcorder attribute setting */ - err = mm_camcorder_set_attributes( (MMHandleType)cam_handle, &err_attr_name, - MMCAM_MODE, MM_CAMCORDER_MODE_VIDEO, MMCAM_AUDIO_DEVICE, MM_AUDIO_DEVICE_MIC, - MMCAM_AUDIO_ENCODER, MM_AUDIO_CODEC_AMR, - MMCAM_VIDEO_ENCODER, MM_VIDEO_CODEC_H264, + MMCAM_AUDIO_ENCODER, MM_AUDIO_CODEC_AAC, + MMCAM_VIDEO_ENCODER, MM_VIDEO_CODEC_MPEG4, + MMCAM_VIDEO_ENCODER_BITRATE, VIDEO_ENCODE_BITRATE, MMCAM_FILE_FORMAT, MM_FILE_FORMAT_3GP, - MMCAM_CAMERA_FORMAT, preview_format, MMCAM_CAMERA_FPS, SRC_VIDEO_FRAME_RATE_30, MMCAM_CAMERA_FPS_AUTO, 0, - "camera-delay-attr-setting", TRUE, MMCAM_CAMERA_ROTATION, MM_VIDEO_INPUT_ROTATION_NONE, - MMCAM_AUDIO_SAMPLERATE, AUDIO_SOURCE_SAMPLERATE_AMR, + MMCAM_AUDIO_SAMPLERATE, AUDIO_SOURCE_SAMPLERATE_AAC, MMCAM_AUDIO_FORMAT, AUDIO_SOURCE_FORMAT, - MMCAM_AUDIO_CHANNEL, AUDIO_SOURCE_CHANNEL_AMR, - MMCAM_AUDIO_INPUT_ROUTE, MM_AUDIOROUTE_CAPTURE_NORMAL, - MMCAM_TAG_ENABLE, 1, - MMCAM_TAG_LATITUDE, 37.25796666, - MMCAM_TAG_LONGITUDE, 127.05332222, - MMCAM_TAG_ALTITUDE, 45.0000, - MMCAM_DISPLAY_DEVICE, MM_DISPLAY_DEVICE_MAINLCD, - MMCAM_DISPLAY_SURFACE, MM_DISPLAY_SURFACE_X, - MMCAM_DISPLAY_RECT_X, DISPLAY_X_0, - MMCAM_DISPLAY_RECT_Y, DISPLAY_Y_0, - MMCAM_DISPLAY_RECT_WIDTH, 480, - MMCAM_DISPLAY_RECT_HEIGHT, 640, - MMCAM_DISPLAY_ROTATION, MM_DISPLAY_ROTATION_270, - MMCAM_TARGET_FILENAME, TARGET_FILENAME_VIDEO, size, - "capture-sound-enable", TRUE, + MMCAM_AUDIO_CHANNEL, AUDIO_SOURCE_CHANNEL_AAC, + //MMCAM_AUDIO_DISABLE, TRUE, + MMCAM_TARGET_FILENAME, TARGET_FILENAME_VIDEO, strlen(TARGET_FILENAME_VIDEO), + //MMCAM_TARGET_TIME_LIMIT, 360000, +#ifndef _TIZEN_PUBLIC_ + //MMCAM_TARGET_MAX_SIZE, 102400, +#endif /* _TIZEN_PUBLIC_ */ NULL ); if (err != MM_ERROR_NONE) { - fprintf(stderr, "video mode init fail. [%s][%x)", err_attr_name, err); + warn_msg_t("Init fail. (%s:%x)", err_attr_name, err); SAFE_FREE (err_attr_name); goto ERROR; } -// mm_camcorder_set_audio_stream_callback(hcamcorder->camcorder, (mm_camcorder_audio_stream_callback)camcordertest_audio_stream_cb, (void*)hcamcorder->camcorder); - } + mm_camcorder_set_video_capture_callback(hcamcorder->camcorder, (mm_camcorder_video_capture_callback)camcordertest_video_capture_cb, hcamcorder); + } /*================================================================================ Audio mode *=================================================================================*/ @@ -2602,20 +2081,24 @@ static gboolean init(int type) MMCAM_FILE_FORMAT, MM_FILE_FORMAT_AMR, MMCAM_AUDIO_SAMPLERATE, AUDIO_SOURCE_SAMPLERATE_AMR, MMCAM_AUDIO_FORMAT, AUDIO_SOURCE_FORMAT, - MMCAM_AUDIO_CHANNEL, AUDIO_SOURCE_CHANNEL_AMR, - MMCAM_AUDIO_INPUT_ROUTE, MM_AUDIOROUTE_CAPTURE_NORMAL, + MMCAM_AUDIO_CHANNEL, AUDIO_SOURCE_CHANNEL_AAC, MMCAM_TARGET_FILENAME, TARGET_FILENAME_AUDIO, size, MMCAM_TARGET_TIME_LIMIT, 360000, + MMCAM_AUDIO_ENCODER_BITRATE, 12200, +#ifndef _TIZEN_PUBLIC_ + MMCAM_TARGET_MAX_SIZE, 300, +#endif /* _TIZEN_PUBLIC_ */ NULL); - if (err < 0) - { + if (err < 0) { warn_msg_t("Init fail. (%s:%x)", err_attr_name, err); SAFE_FREE (err_attr_name); goto ERROR; } -// mm_camcorder_set_audio_stream_callback(hcamcorder->camcorder, (mm_camcorder_audio_stream_callback)camcordertest_audio_stream_cb, (void*)hcamcorder->camcorder); +#ifdef USE_AUDIO_STREAM_CB + mm_camcorder_set_audio_stream_callback(hcamcorder->camcorder, (mm_camcorder_audio_stream_callback)camcordertest_audio_stream_cb, (void*)hcamcorder->camcorder); +#endif /* USE_AUDIO_STREAM_CB */ } debug_msg_t("Init DONE."); @@ -2679,57 +2162,41 @@ static gboolean msg_callback(int message, void *msg_param, void *user_param) break; case MM_MESSAGE_CAMCORDER_CAPTURED: - { - if (hcamcorder->mode == MODE_IMAGE) - { - time_msg_t("Stillshot capture : %12.6lf s", g_timer_elapsed(timer, NULL)); - - g_print("*******************************************************\n"); - g_print("[Camcorder Testsuite] Camcorder Stillshot Captured!!\n"); - g_print("*******************************************************\n"); - - if (hcamcorder->isMultishot) //multishot - { - g_print("[CamcorderApp] Camcorder Captured(Capture Count=%d)\n", param->code); - - if (param->code >= multishot_num) - { - get_me_out(); -// g_timeout_add (100, (GSourceFunc)get_me_out, NULL); -// hcamcorder->isMultishot = FALSE; - } - } - else //singleshot - { + time_msg_t("Stillshot capture : %12.6lf s", g_timer_elapsed(timer, NULL)); + if (hcamcorder->isMultishot) { + //g_print("[CamcorderApp] Camcorder Captured(Capture Count=%d)\n", param->code); + if (param->code >= multishot_num) { get_me_out(); -// g_timeout_add (1000, (GSourceFunc)get_me_out, NULL); +// g_timeout_add (100, (GSourceFunc)get_me_out, NULL); +// hcamcorder->isMultishot = FALSE; } - + } else { + get_me_out(); +// g_timeout_add (1000, (GSourceFunc)get_me_out, NULL); } - else - { - MMCamRecordingReport* report ; - - time_msg_t("Recording commit time : %12.6lf s", g_timer_elapsed(timer, NULL)); + break; + case MM_MESSAGE_CAMCORDER_VIDEO_CAPTURED: + case MM_MESSAGE_CAMCORDER_AUDIO_CAPTURED: + { + MMCamRecordingReport* report ; - if (param) - report = (MMCamRecordingReport*)(param->data); - else - return FALSE; + time_msg_t("Recording commit time : %12.6lf s", g_timer_elapsed(timer, NULL)); - if( report != NULL ) - { - g_print("*******************************************************\n"); - g_print("[Camcorder Testsuite] Camcorder Captured(filename=%s)\n", report->recording_filename); - g_print("*******************************************************\n"); + if (param) { + report = (MMCamRecordingReport*)(param->data); + } else { + return FALSE; + } - SAFE_FREE (report->recording_filename); - SAFE_FREE (report); - } - else - { - g_print( "[Camcorder Testsuite] report is NULL.\n" ); - } + if (report != NULL) { + g_print("*******************************************************\n"); + g_print("[Camcorder Testsuite] Camcorder Captured(filename=%s)\n", report->recording_filename); + g_print("*******************************************************\n"); + + SAFE_FREE (report->recording_filename); + SAFE_FREE (report); + } else { + g_print( "[Camcorder Testsuite] report is NULL.\n" ); } } break; @@ -2740,18 +2207,19 @@ static gboolean msg_callback(int message, void *msg_param, void *user_param) break; case MM_MESSAGE_CAMCORDER_RECORDING_STATUS: { - unsigned int elapsed; + unsigned long long elapsed; elapsed = param->recording_status.elapsed / 1000; if (hcamcorder->elapsed_time != elapsed) { - unsigned int temp_time; - int hour, minute, second; + unsigned long temp_time; + unsigned long long hour, minute, second; hcamcorder->elapsed_time = elapsed; temp_time = elapsed; hour = temp_time / 3600; temp_time = elapsed % 3600; minute = temp_time / 60; second = temp_time % 60; - debug_msg_t("Current Time - %d:%d:%d", hour, minute, second); + debug_msg_t("Current Time - %lld:%lld:%lld, remained %lld ms, filesize %lld KB", + hour, minute, second, param->recording_status.remained_time, param->recording_status.filesize); } } break; @@ -2790,6 +2258,47 @@ static gboolean msg_callback(int message, void *msg_param, void *user_param) g_print( "Focus State changed. State:[%d]\n", param->code ); } break; + case MM_MESSAGE_CAMCORDER_FACE_DETECT_INFO: + { + static int info_count = 0; + MMCamFaceDetectInfo *cam_fd_info = NULL; + + cam_fd_info = (MMCamFaceDetectInfo *)(param->data); + + if (cam_fd_info) { + int i = 0; + + g_print("\tface detect num %d, pointer %p\n", cam_fd_info->num_of_faces, cam_fd_info); + + for (i = 0 ; i < cam_fd_info->num_of_faces ; i++) { + g_print("\t\t[%2d][score %d] position %d,%d %dx%d\n", + cam_fd_info->face_info[i].id, + cam_fd_info->face_info[i].score, + cam_fd_info->face_info[i].rect.x, + cam_fd_info->face_info[i].rect.y, + cam_fd_info->face_info[i].rect.width, + cam_fd_info->face_info[i].rect.height); + } + + if (info_count == 0) { + mm_camcorder_set_attributes(hcamcorder->camcorder, NULL, + MMCAM_CAMERA_FACE_ZOOM_MODE, MM_CAMCORDER_FACE_ZOOM_MODE_ON, + MMCAM_CAMERA_FACE_ZOOM_X, cam_fd_info->face_info[0].rect.x + (cam_fd_info->face_info[0].rect.width>>1), + MMCAM_CAMERA_FACE_ZOOM_Y, cam_fd_info->face_info[0].rect.y + (cam_fd_info->face_info[0].rect.height>>1), + MMCAM_CAMERA_FACE_ZOOM_LEVEL, 0, + NULL); + info_count = 1; + g_print("\n\t##### START FACE ZOOM [%d,%d] #####\n", cam_fd_info->face_info[0].rect.x, cam_fd_info->face_info[0].rect.y); + } else if (info_count++ == 90) { + mm_camcorder_set_attributes(hcamcorder->camcorder, NULL, + MMCAM_CAMERA_FACE_ZOOM_MODE, MM_CAMCORDER_FACE_ZOOM_MODE_OFF, + NULL); + g_print("\n\t##### STOP FACE ZOOM #####\n"); + info_count = -60; + } + } + } + break; default: g_print("Message %x received\n", message); break; @@ -2800,16 +2309,16 @@ static gboolean msg_callback(int message, void *msg_param, void *user_param) static gboolean init_handle() { - hcamcorder->mode = MODE_IMAGE; /* image(capture)/video(recording) mode */ + hcamcorder->mode = MODE_VIDEO_CAPTURE; /* image(capture)/video(recording) mode */ hcamcorder->isMultishot = FALSE; - hcamcorder->stillshot_count = 0; /* total stillshot count */ - hcamcorder->multishot_count = 0; /* total multishot count */ - hcamcorder->stillshot_filename = STILL_CAPTURE_FILE_PATH_NAME; /* stored filename of stillshot */ - hcamcorder->multishot_filename = MULTI_CAPTURE_FILE_PATH_NAME; /* stored filename of multishot */ + hcamcorder->stillshot_count = 0; /* total stillshot count */ + hcamcorder->multishot_count = 0; /* total multishot count */ + hcamcorder->stillshot_filename = STILL_CAPTURE_FILE_PATH_NAME; /* stored filename of stillshot */ + hcamcorder->multishot_filename = MULTI_CAPTURE_FILE_PATH_NAME; /* stored filename of multishot */ hcamcorder->menu_state = MENU_STATE_MAIN; - hcamcorder->isMute = FALSE; + hcamcorder->isMute = FALSE; hcamcorder->elapsed_time = 0; - hcamcorder->fps = SRC_VIDEO_FRAME_RATE_15; //SRC_VIDEO_FRAME_RATE_30; + hcamcorder->fps = SRC_VIDEO_FRAME_RATE_15; /*SRC_VIDEO_FRAME_RATE_30;*/ multishot_num = IMAGE_CAPTURE_COUNT_MULTI; return TRUE; @@ -2826,8 +2335,12 @@ static gboolean init_handle() static gboolean mode_change() { int err = MM_ERROR_NONE; - int state; + int state = MM_CAMCORDER_STATE_NONE; + int name_size = 0; + int device_count = 0; + int facing_direction = 0; char media_type = '\0'; + char *evassink_name = NULL; bool check= FALSE; debug_msg_t("MMCamcorder State : %d", mmcamcorder_state); @@ -2889,57 +2402,45 @@ static gboolean mode_change() g_print("\n\t=======================================\n"); g_print("\t MM_CAMCORDER_TESTSUIT\n"); g_print("\t=======================================\n"); - g_print("\t '1' Image Capture - Front Camera\n"); - g_print("\t '2' Image Capture - Rear Camera\n"); - g_print("\t '3' Video Recording - Front Camera\n"); - g_print("\t '4' Video Recording - Rear Camera\n"); - g_print("\t '5' Audio Recording\n"); + g_print("\t '1' Video Capture - Front Camera\n"); + g_print("\t '2' Video Capture - Rear Camera\n"); + g_print("\t '3' Audio Recording\n"); g_print("\t 'q' Exit\n"); g_print("\t=======================================\n"); g_print("\t Enter the media type:\n\t"); - while ((media_type=getchar()) == '\n'); + err = scanf("%c", &media_type); - switch(media_type) { - case '1': - hcamcorder->mode= MODE_IMAGE; - cam_info.videodev_type = MM_VIDEO_DEVICE_CAMERA1; - check = TRUE; - break; - case '2': - hcamcorder->mode= MODE_IMAGE; - cam_info.videodev_type = MM_VIDEO_DEVICE_CAMERA0; - check = TRUE; - break; - case '3': - hcamcorder->mode= MODE_VIDEO; - cam_info.videodev_type = MM_VIDEO_DEVICE_CAMERA1; - check = TRUE; - break; - case '4': - hcamcorder->mode= MODE_VIDEO; - cam_info.videodev_type = MM_VIDEO_DEVICE_CAMERA0; - check = TRUE; - break; - case '5': - hcamcorder->mode= MODE_AUDIO; - cam_info.videodev_type = MM_VIDEO_DEVICE_NONE; - check = TRUE; - break; - case 'q': - g_print("\t Quit Camcorder Testsuite!!\n"); - hcamcorder->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; + switch (media_type) { + case '1': + hcamcorder->mode= MODE_VIDEO_CAPTURE; + cam_info.videodev_type = MM_VIDEO_DEVICE_CAMERA1; + check = TRUE; + break; + case '2': + hcamcorder->mode= MODE_VIDEO_CAPTURE; + cam_info.videodev_type = MM_VIDEO_DEVICE_CAMERA0; + check = TRUE; + break; + case '3': + hcamcorder->mode= MODE_AUDIO; + cam_info.videodev_type = MM_VIDEO_DEVICE_NONE; + check = TRUE; + break; + case 'q': + g_print("\t Quit Camcorder Testsuite!!\n"); + hcamcorder->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_camcorder_create"); g_get_current_time(&previous); g_timer_reset(timer); @@ -2954,6 +2455,15 @@ static gboolean mode_change() mmcamcorder_state = MM_CAMCORDER_STATE_NULL; } + /* get evassink name */ + mm_camcorder_get_attributes(hcamcorder->camcorder, NULL, + MMCAM_DISPLAY_EVAS_SURFACE_SINK, &evassink_name, &name_size, + MMCAM_CAMERA_DEVICE_COUNT, &device_count, + MMCAM_CAMERA_FACING_DIRECTION, &facing_direction, + NULL); + debug_msg_t("evassink name[%s], device count[%d], facing direction[%d]", + evassink_name, device_count, facing_direction); + mm_camcorder_set_message_callback(hcamcorder->camcorder, (MMMessageCallback)msg_callback, hcamcorder); if (!init(hcamcorder->mode)) { -- 2.7.4