diff options
author | Kibum Kim <kb0929.kim@samsung.com> | 2012-02-27 21:16:21 +0900 |
---|---|---|
committer | Kibum Kim <kb0929.kim@samsung.com> | 2012-02-27 21:16:21 +0900 |
commit | 235c811494b7fcc70c9575df92cc69990352f888 (patch) | |
tree | 2748ff06cd7e40e5cc18a70c4e37f14c7700fafb /src | |
download | libmm-camcorder-235c811494b7fcc70c9575df92cc69990352f888.tar.gz libmm-camcorder-235c811494b7fcc70c9575df92cc69990352f888.tar.bz2 libmm-camcorder-235c811494b7fcc70c9575df92cc69990352f888.zip |
tizen beta release
Diffstat (limited to 'src')
26 files changed, 28029 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..dfaa6ba --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,69 @@ +ACLOCAL_AMFLAGS='-I m4' + +lib_LTLIBRARIES = libmmfcamcorder.la + +includelibmmfcamcorderdir = $(includedir)/mmf + +includelibmmfcamcorder_HEADERS = include/mm_camcorder.h + +noinst_HEADERS = include/mm_camcorder_audiorec.h \ + include/mm_camcorder_attribute.h \ + include/mm_camcorder_configure.h \ + include/mm_camcorder_gstcommon.h \ + include/mm_camcorder_internal.h \ + include/mm_camcorder_platform.h \ + include/mm_camcorder_stillshot.h \ + include/mm_camcorder_videorec.h \ + include/mm_camcorder_util.h \ + include/mm_camcorder_exifinfo.h\ + include/mm_camcorder_exifdef.h \ + include/mm_camcorder_sound.h + +libmmfcamcorder_la_SOURCES = mm_camcorder.c \ + mm_camcorder_internal.c \ + mm_camcorder_attribute.c \ + mm_camcorder_stillshot.c \ + mm_camcorder_videorec.c \ + mm_camcorder_audiorec.c \ + mm_camcorder_gstcommon.c \ + mm_camcorder_platform.c \ + mm_camcorder_configure.c \ + mm_camcorder_util.c \ + mm_camcorder_exifinfo.c \ + mm_camcorder_sound.c + +libmmfcamcorder_la_CFLAGS = -I$(srcdir)/include \ + $(GST_CFLAGS) \ + $(GST_PLUGIN_BASE_CFLAGS) \ + $(GST_INTERFACES_CFLAGS) \ + $(MM_LOG_CFLAGS) \ + $(MMTA_CFLAGS) \ + $(EXIF_CFLAGS) \ + $(MM_COMMON_CFLAGS) \ + $(MMSESSION_CFLAGS) \ + $(MMSOUND_CFLAGS) \ + $(SNDFILE_CFLAGS) \ + $(CAMSRCJPEGENC_CFLAGS) \ + $(AUDIOSESSIONMGR_CFLAGS) + +libmmfcamcorder_la_LIBADD = \ + $(GST_LIBS) \ + $(GST_PLUGIN_BASE_LIBS) \ + $(GST_INTERFACES_LIBS) \ + $(MM_COMMON_LIBS) \ + $(MM_LOG_LIBS) \ + $(MMTA_LIBS) \ + $(EXIF_LIBS) \ + $(MMSESSION_LIBS) \ + $(MMSOUND_LIBS) \ + $(SNDFILE_LIBS) \ + $(CAMSRCJPEGENC_LIBS) \ + $(AUDIOSESSIONMGR_LIBS) + +libmmfcamcorder_la_CFLAGS += $(MMLOGSVR_CFLAGS) -DMMF_LOG_OWNER=0x010 -DMMF_DEBUG_PREFIX=\"MMF-CAMCORDER\" -D_INTERNAL_SESSION_MANAGER_ +libmmfcamcorder_la_LIBADD += $(MMLOGSVR_LIBS) + +install-exec-hook: + mkdir -p $(DESTDIR)$(prefix)/share/sounds/mm-camcorder && \ + cp $(srcdir)/../sounds/*.wav $(DESTDIR)$(prefix)/share/sounds/mm-camcorder/ + diff --git a/src/include/mm_camcorder.h b/src/include/mm_camcorder.h new file mode 100644 index 0000000..a3f2f73 --- /dev/null +++ b/src/include/mm_camcorder.h @@ -0,0 +1,2925 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + @addtogroup CAMCORDER + @{ + + @par + This part describes the APIs with repect to Multimedia Camcorder. + Camcorder is for recording audio and video from audio and video input devices, capturing + still image from video input device, and audio recording from audio input + device. + + @par + Camcorder can be reached by calling functions as shown in the following + figure, "The State of Camcorder". + + @par + @image html camcorder_state.png "The State of Camcorder" width=12cm + @image latex camcorder_state.png "The State of Camcorder" width=12cm + + @par + Between each states there is intermediate state, and in this state, + any function call which change the camcorder state will be failed. + + @par + Recording state and paused state exists when the mode of camcorder is + video-capture or audio-capture mode. In case of image-capture mode, CAPTURING state will + exsit. + + @par +<div> +<table> + <tr> + <td>FUNCTION</td> + <td>PRE-STATE</td> + <td>POST-STATE</td> + <td>SYNC TYPE</td> + </tr> + <tr> + <td>mm_camcorder_create()</td> + <td>NONE</td> + <td>NULL</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_destroy()</td> + <td>NULL</td> + <td>NONE</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_realize()</td> + <td>NULL</td> + <td>READY</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_unrealize()</td> + <td>READY</td> + <td>NULL</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_start()</td> + <td>READY</td> + <td>PREPARED</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_stop()</td> + <td>PREPARED</td> + <td>READY</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_capture_start()</td> + <td>PREPARED</td> + <td>CAPTURING</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_capture_stop()</td> + <td>CAPTURING</td> + <td>PREPARED</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_record()</td> + <td>PREPARED/PAUSED</td> + <td>RECORDING</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_pause()</td> + <td>RECORDING</td> + <td>PAUSED</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_commit()</td> + <td>RECORDING/PAUSED</td> + <td>PREPARED</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_cancel()</td> + <td>RECORDING/PAUSED</td> + <td>PREPARED</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_set_message_callback()</td> + <td>N/A</td> + <td>N/A</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_set_video_stream_callback()</td> + <td>N/A</td> + <td>N/A</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_set_video_capture_callback()</td> + <td>N/A</td> + <td>N/A</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_get_state()</td> + <td>N/A</td> + <td>N/A</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_get_attributes()</td> + <td>N/A</td> + <td>N/A</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_set_attributes()</td> + <td>N/A</td> + <td>N/A</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_get_attribute_info()</td> + <td>N/A</td> + <td>N/A</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_init_focusing()</td> + <td>N/A</td> + <td>N/A</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_start_focusing()</td> + <td>N/A</td> + <td>N/A</td> + <td>SYNC</td> + </tr> + <tr> + <td>mm_camcorder_stop_focusing()</td> + <td>N/A</td> + <td>N/A</td> + <td>SYNC</td> + </tr> +</table> +</div> + + @par + * Attribute @n + Attribute system is an interface to operate camcorder. Depending on each attribute, camcorder behaves differently. + Attribute system provides get/set functions. Setting proper attributes, a user can control camcorder as he want. (mm_camcorder_set_attributes()) + Also, a user can comprehend current status of the camcorder, calling getter function(mm_camcorder_get_attributes()). + Beware, arguments of mm_camcorder_set_attributes() and mm_camcorder_get_attributes() should be finished with 'NULL'. + This is a rule for the variable argument. + @par + Besides its value, each Attribute also has 'type' and 'validity type'. 'type' describes variable type that the attribute can get. + If you input a value that has wrong type, camcorder will not work properly or be crashed. 'validity' describes array or + range of values that are able to set to the attribute. 'validity type' defines type of the 'validity'. + @par + A user can retrieve these values using mm_camcorder_get_attribute_info(). + Following tables have 'Attribute name', 'Attribute macro', 'Type', and 'Validity type'. You can refer '#MMCamAttrsType' and '#MMCamAttrsValidType' + for discerning 'Type' and 'Validity type'. + + + @par + Following are the attributes which should be set before initialization (#mm_camcorder_realize): + + @par +<div> +<table> + <tr> + <td><center><b>Attribute</b></center></td> + <td><center><b>Description</b></center></td> + </tr> + <tr> + <td>#MMCAM_MODE</td> + <td>Mode of camcorder ( still/video/audio )</td> + </tr> + <tr> + <td>#MMCAM_AUDIO_DEVICE</td> + <td>Audio device ID for capturing audio stream</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_DEVICE</td> + <td>Video device ID for capturing video stream</td> + </tr> + <tr> + <td>#MMCAM_AUDIO_ENCODER</td> + <td>Audio codec for encoding audio stream</td> + </tr> + <tr> + <td>#MMCAM_VIDEO_ENCODER</td> + <td>Video codec for encoding video stream</td> + </tr> + <tr> + <td>#MMCAM_IMAGE_ENCODER</td> + <td>Image codec for capturing still-image</td> + </tr> + <tr> + <td>#MMCAM_FILE_FORMAT</td> + <td>File format for recording media stream</td> + </tr> + <tr> + <td>#MMCAM_AUDIO_SAMPLERATE</td> + <td>Sampling rate of audio stream ( This is an integer field )</td> + </tr> + <tr> + <td>#MMCAM_AUDIO_FORMAT</td> + <td>Audio format of each sample</td> + </tr> + <tr> + <td>#MMCAM_AUDIO_CHANNEL</td> + <td>Channels of each sample ( This is an integer field )</td> + </tr> + <tr> + <td>#MMCAM_AUDIO_INPUT_ROUTE(deprecated)</td> + <td>Set audio input route</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_FORMAT</td> + <td>Format of video stream. This is an integer field</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_FPS</td> + <td>Frames per second ( This is an integer field )</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_WIDTH</td> + <td>Width of input video stream</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_HEIGHT</td> + <td>Height of input video stream</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_FPS_AUTO</td> + <td>FPS Auto. When you set true to this attribute, FPS will vary depending on the amount of the light.</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_HANDLE</td> + <td>Pointer of display buffer or ID of xwindow</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_DEVICE</td> + <td>Device of display</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_SURFACE</td> + <td>Surface of display</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_SOURCE_X</td> + <td>X position of source rectangle. When you want to crop the source, you can set the area with this value.</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_SOURCE_Y</td> + <td>Y position of source rectangle. When you want to crop the source, you can set the area with this value.</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_SOURCE_WIDTH</td> + <td>Width of source rectangle. When you want to crop the source, you can set the area with this value.</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_SOURCE_HEIGHT</td> + <td>Height of source rectangle. When you want to crop the source, you can set the area with this value.</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_ROTATION</td> + <td>Rotation of display</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_VISIBLE</td> + <td>Visible of display</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_SCALE</td> + <td>A scale of displayed image</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_GEOMETRY_METHOD</td> + <td>A method that describes a form of geometry for display</td> + </tr> +</table> +</div> + + @par + Following are the attributes which should be set before recording (mm_camcorder_record()): + + @par +<div> +<table> + <tr> + <td><center><b>Attribute</b></center></td> + <td><center><b>Description</b></center></td> + </tr> + <tr> + <td>#MMCAM_AUDIO_ENCODER_BITRATE</td> + <td>Bitrate of Audio Encoder</td> + </tr> + <tr> + <td>#MMCAM_VIDEO_ENCODER_BITRATE</td> + <td>Bitrate of Video Encoder</td> + </tr> + <tr> + <td>#MMCAM_TARGET_FILENAME</td> + <td>Target filename. Only used in Audio/Video recording. This is not used for capturing.</td> + </tr> + <tr> + <td>#MMCAM_TARGET_TIME_LIMIT</td> + <td>Time limit of recording file. If the elapsed time of recording reaches this value.</td> + </tr> +</table> +</div> + + @par + Following are the attributes which should be set before capturing (mm_camcorder_capture_start()): + + @par +<div> +<table> + <tr> + <td><center><b>Attribute</b></center></td> + <td><center><b>Description</b></center></td> + </tr> + <tr> + <td>#MMCAM_IMAGE_ENCODER_QUALITY</td> + <td>Encoding quality of Image codec</td> + </tr> + <tr> + <td>#MMCAM_CAPTURE_FORMAT</td> + <td>Pixel format that you want to capture</td> + </tr> + <tr> + <td>#MMCAM_CAPTURE_WIDTH</td> + <td>Width of the image that you want to capture</td> + </tr> + <tr> + <td>#MMCAM_CAPTURE_HEIGHT</td> + <td>Height of the image that you want to capture</td> + </tr> + <tr> + <td>#MMCAM_CAPTURE_COUNT</td> + <td>Total count of capturing</td> + </tr> + <tr> + <td>#MMCAM_CAPTURE_INTERVAL</td> + <td>Interval between each capturing on Multishot ( MMCAM_CAPTURE_COUNT > 1 )</td> + </tr> +</table> +</div> + + @par + Following are the attributes which can be set anytime: + + @par +<div> +<table> + <tr> + <td><center><b>Attribute</b></center></td> + <td><center><b>Description</b></center></td> + </tr> + <tr> + <td>#MMCAM_AUDIO_VOLUME</td> + <td>Input volume of audio source ( double value )</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_DIGITAL_ZOOM</td> + <td>Digital zoom level</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_OPTICAL_ZOOM</td> + <td>Optical zoom level</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_FOCUS_MODE</td> + <td>Focus mode</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_AF_SCAN_RANGE</td> + <td>AF Scan range</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_AF_TOUCH_X</td> + <td>X coordinate of touching position</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_AF_TOUCH_Y</td> + <td>Y coordinate of touching position</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_AF_TOUCH_WIDTH</td> + <td>Width of touching area</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_AF_TOUCH_HEIGHT</td> + <td>Height of touching area</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_EXPOSURE_MODE</td> + <td>Exposure mode</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_EXPOSURE_VALUE</td> + <td>Exposure value</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_F_NUMBER</td> + <td>f number of camera</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_SHUTTER_SPEED</td> + <td>Shutter speed</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_ISO</td> + <td>ISO of capturing image</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_WDR</td> + <td>Wide dynamic range</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_ANTI_HANDSHAKE</td> + <td>Anti Handshake</td> + </tr> + <tr> + <td>#MMCAM_CAMERA_FOCAL_LENGTH</td> + <td>Focal length of camera lens</td> + </tr> + <tr> + <td>#MMCAM_FILTER_BRIGHTNESS</td> + <td>Brightness level</td> + </tr> + <tr> + <td>#MMCAM_FILTER_CONTRAST</td> + <td>Contrast level</td> + </tr> + <tr> + <td>#MMCAM_FILTER_WB</td> + <td>White balance</td> + </tr> + <tr> + <td>#MMCAM_FILTER_COLOR_TONE</td> + <td>Color tone (Color effect)</td> + </tr> + <tr> + <td>#MMCAM_FILTER_SCENE_MODE</td> + <td>Scene mode (Program mode)</td> + </tr> + <tr> + <td>#MMCAM_FILTER_SATURATION</td> + <td>Saturation level</td> + </tr> + <tr> + <td>#MMCAM_FILTER_HUE</td> + <td>Hue level</td> + </tr> + <tr> + <td>#MMCAM_FILTER_SHARPNESS</td> + <td>Sharpness level</td> + </tr> + <tr> + <td>#MMCAM_CAPTURE_BREAK_CONTINUOUS_SHOT</td> + <td>Set this as true when you want to stop multishot immediately</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_RECT_X</td> + <td>X position of display rectangle (This is only available when MMCAM_DISPLAY_GEOMETRY_METHOD is MM_CAMCORDER_CUSTOM_ROI)</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_RECT_Y</td> + <td>Y position of display rectangle (This is only available when MMCAM_DISPLAY_GEOMETRY_METHOD is MM_CAMCORDER_CUSTOM_ROI)</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_RECT_WIDTH</td> + <td>Width of display rectangle (This is only available when MMCAM_DISPLAY_GEOMETRY_METHOD is MM_CAMCORDER_CUSTOM_ROI)</td> + </tr> + <tr> + <td>#MMCAM_DISPLAY_RECT_HEIGHT</td> + <td>Height of display rectangle (This is only available when MMCAM_DISPLAY_GEOMETRY_METHOD is MM_CAMCORDER_CUSTOM_ROI)</td> + </tr> + <tr> + <td>#MMCAM_TAG_ENABLE</td> + <td>Enable to write tags (If this value is FALSE, none of tag information will be written to captured file)</td> + </tr> + <tr> + <td>#MMCAM_TAG_IMAGE_DESCRIPTION</td> + <td>Image description</td> + </tr> + <tr> + <td>#MMCAM_TAG_ORIENTATION</td> + <td>Orientation of captured image</td> + </tr> + <tr> + <td>#MMCAM_TAG_SOFTWARE</td> + <td>software name and version</td> + </tr> + <tr> + <td>#MMCAM_TAG_LATITUDE</td> + <td>Latitude of captured postion (GPS information)</td> + </tr> + <tr> + <td>#MMCAM_TAG_LONGITUDE</td> + <td>Longitude of captured postion (GPS information)</td> + </tr> + <tr> + <td>#MMCAM_TAG_ALTITUDE</td> + <td>Altitude of captured postion (GPS information)</td> + </tr> + <tr> + <td>#MMCAM_STROBE_CONTROL</td> + <td>Strobe control</td> + </tr> + <tr> + <td>#MMCAM_STROBE_MODE</td> + <td>Operation Mode of strobe</td> + </tr> + <tr> + <td>#MMCAM_DETECT_MODE</td> + <td>Detection mode</td> + </tr> + <tr> + <td>#MMCAM_DETECT_NUMBER</td> + <td>Total number of detected object</td> + </tr> + <tr> + <td>#MMCAM_DETECT_FOCUS_SELECT</td> + <td>Select one of detected objects</td> + </tr> +</table> +</div> + */ + + + +#ifndef __MM_CAMCORDER_H__ +#define __MM_CAMCORDER_H__ + + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ +#include <glib.h> + +#include <mm_types.h> +#include <mm_error.h> +#include <mm_message.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| GLOBAL DEFINITIONS AND DECLARATIONS FOR CAMCORDER | +========================================================================================*/ + +/*======================================================================================= +| MACRO DEFINITIONS | +========================================================================================*/ +/** + * Get numerator. Definition for fraction setting, such as MMCAM_CAMERA_SHUTTER_SPEED and MMCAM_CAMERA_EXPOSURE_VALUE. + */ +#define MM_CAMCORDER_GET_NUMERATOR(x) ((int)(((int)(x) >> 16) & 0xFFFF)) +/** + * Get denominator. Definition for fraction setting, such as MMCAM_CAMERA_SHUTTER_SPEED and MMCAM_CAMERA_EXPOSURE_VALUE. + */ +#define MM_CAMCORDER_GET_DENOMINATOR(x) ((int)(((int)(x)) & 0xFFFF)) +/** + * Set fraction value. Definition for fraction setting, such as MMCAM_CAMERA_SHUTTER_SPEED and MMCAM_CAMERA_EXPOSURE_VALUE. + */ +#define MM_CAMCORDER_SET_FRACTION(numerator,denominator) ((int)((((int)(numerator)) << 16) | (int)(denominator))) + +/* Attributes Macros */ +/** + * Mode of camcorder (still/video/audio). + * @see MMCamcorderModeType + */ +#define MMCAM_MODE "mode" + +/** + * Audio device ID for capturing audio stream. + * @see MMAudioDeviceType (in mm_types.h) + */ +#define MMCAM_AUDIO_DEVICE "audio-device" + +/** + * Video device ID for capturing video stream. + * @see MMVideoDeviceType (in mm_types.h) + */ +#define MMCAM_CAMERA_DEVICE "camera-device" + +/** + * Audio codec for encoding audio stream. + * @see MMAudioCodecType (in mm_types.h) + */ +#define MMCAM_AUDIO_ENCODER "audio-encoder" + +/** + * Video codec for encoding video stream. + * @see MMVideoCodecType (in mm_types.h) + */ +#define MMCAM_VIDEO_ENCODER "video-encoder" + +/** + * Image codec for capturing still-image. + * @see MMImageCodecType (in mm_types.h) + */ +#define MMCAM_IMAGE_ENCODER "image-encoder" + +/** + * File format for recording media stream. + * @see MMFileFormatType (in mm_types.h) + */ +#define MMCAM_FILE_FORMAT "file-format" + +/** + * Sampling rate of audio stream. This is an integer field. + */ +#define MMCAM_AUDIO_SAMPLERATE "audio-samplerate" + +/** + * Audio format of each sample. + * @see MMCamcorderAudioFormat + */ +#define MMCAM_AUDIO_FORMAT "audio-format" + +/** + * Channels of each sample. This is an integer field. + */ +#define MMCAM_AUDIO_CHANNEL "audio-channel" + +/** + * Input volume of audio source. Double value. + */ +#define MMCAM_AUDIO_VOLUME "audio-volume" + +/** + * Set audio input route + * @remarks Deprecated. This will be removed soon. + * @see MMAudioRoutePolicy (in mm_types.h) + */ +#define MMCAM_AUDIO_INPUT_ROUTE "audio-input-route" + +/** + * Format of video stream. This is an integer field + * @see MMPixelFormatType (in mm_types.h) + */ +#define MMCAM_CAMERA_FORMAT "camera-format" + +/** + * Frames per second. This is an integer field + * + */ +#define MMCAM_CAMERA_FPS "camera-fps" + +/** + * Width of input video stream. + */ +#define MMCAM_CAMERA_WIDTH "camera-width" + +/** + * Height of input video stream. + * @see + */ +#define MMCAM_CAMERA_HEIGHT "camera-height" + +/** + * Digital zoom level. + */ +#define MMCAM_CAMERA_DIGITAL_ZOOM "camera-digital-zoom" + +/** + * Optical zoom level. + */ +#define MMCAM_CAMERA_OPTICAL_ZOOM "camera-optical-zoom" + +/** + * Focus mode + * @see MMCamcorderFocusMode + */ +#define MMCAM_CAMERA_FOCUS_MODE "camera-focus-mode" + +/** + * AF Scan range + * @see MMCamcorderAutoFocusType + */ +#define MMCAM_CAMERA_AF_SCAN_RANGE "camera-af-scan-range" + +/** + * X coordinate of touching position. Only available when you set '#MM_CAMCORDER_AUTO_FOCUS_TOUCH' to '#MMCAM_CAMERA_AF_SCAN_RANGE'. + * @see MMCamcorderAutoFocusType + */ +#define MMCAM_CAMERA_AF_TOUCH_X "camera-af-touch-x" + +/** + * Y coordinate of touching position. Only available when you set '#MM_CAMCORDER_AUTO_FOCUS_TOUCH' to '#MMCAM_CAMERA_AF_SCAN_RANGE'. + * @see MMCamcorderAutoFocusType + */ +#define MMCAM_CAMERA_AF_TOUCH_Y "camera-af-touch-y" + +/** + * Width of touching area. Only available when you set '#MM_CAMCORDER_AUTO_FOCUS_TOUCH' to '#MMCAM_CAMERA_AF_SCAN_RANGE'. + * @see MMCamcorderAutoFocusType + */ +#define MMCAM_CAMERA_AF_TOUCH_WIDTH "camera-af-touch-width" + +/** + * Height of touching area. Only available when you set '#MM_CAMCORDER_AUTO_FOCUS_TOUCH' to '#MMCAM_CAMERA_AF_SCAN_RANGE'. + * @see MMCamcorderAutoFocusType + */ +#define MMCAM_CAMERA_AF_TOUCH_HEIGHT "camera-af-touch-height" + +/** + * Exposure mode + * @see MMCamcorderAutoExposureType + */ +#define MMCAM_CAMERA_EXPOSURE_MODE "camera-exposure-mode" + +/** + * Exposure value + */ +#define MMCAM_CAMERA_EXPOSURE_VALUE "camera-exposure-value" + +/** + * f number of camera + */ +#define MMCAM_CAMERA_F_NUMBER "camera-f-number" + +/** + * Shutter speed + */ +#define MMCAM_CAMERA_SHUTTER_SPEED "camera-shutter-speed" + +/** + * ISO of capturing image + * @see MMCamcorderISOType + */ +#define MMCAM_CAMERA_ISO "camera-iso" + +/** + * Wide dynamic range. + * @see MMCamcorderWDRMode + */ +#define MMCAM_CAMERA_WDR "camera-wdr" + +/** + * Focal length of camera lens. + */ +#define MMCAM_CAMERA_FOCAL_LENGTH "camera-focal-length" + +/** + * Anti Handshake + * @see MMCamcorderAHSMode + */ +#define MMCAM_CAMERA_ANTI_HANDSHAKE "camera-anti-handshake" + +/** + * 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" + +/** + * Rotation angle of video input stream. + * @see MMVideoInputRotationType (in mm_types.h) + */ +#define MMCAM_CAMERA_ROTATION "camera-rotation" + +/** + * Bitrate of Audio Encoder + */ +#define MMCAM_AUDIO_ENCODER_BITRATE "audio-encoder-bitrate" + +/** + * Bitrate of Video Encoder + */ +#define MMCAM_VIDEO_ENCODER_BITRATE "video-encoder-bitrate" + +/** + * Encoding quality of Image codec + */ +#define MMCAM_IMAGE_ENCODER_QUALITY "image-encoder-quality" + +/** + * Brightness level + */ +#define MMCAM_FILTER_BRIGHTNESS "filter-brightness" + +/** + * Contrast level + */ +#define MMCAM_FILTER_CONTRAST "filter-contrast" + +/** + * White balance + * @see MMCamcorderWhiteBalanceType + */ +#define MMCAM_FILTER_WB "filter-wb" + +/** + * Color tone. (Color effect) + * @see MMCamcorderColorToneType + */ +#define MMCAM_FILTER_COLOR_TONE "filter-color-tone" + +/** + * Scene mode (Program mode) + * @see MMCamcorderSceneModeType + */ +#define MMCAM_FILTER_SCENE_MODE "filter-scene-mode" + +/** + * Saturation level + */ +#define MMCAM_FILTER_SATURATION "filter-saturation" + +/** + * Hue level + */ +#define MMCAM_FILTER_HUE "filter-hue" + +/** + * Sharpness level + */ +#define MMCAM_FILTER_SHARPNESS "filter-sharpness" + +/** + * Pixel format that you want to capture. If you set MM_PIXEL_FORMAT_ENCODED, + * the result will be encoded by image codec specified in #MMCAM_IMAGE_ENCODER. + * If not, the result will be raw data. + * + * @see MMPixelFormatType (in mm_types.h) + */ +#define MMCAM_CAPTURE_FORMAT "capture-format" + +/** + * Width of the image that you want to capture + */ +#define MMCAM_CAPTURE_WIDTH "capture-width" + +/** + * Height of the image that you want to capture + + */ +#define MMCAM_CAPTURE_HEIGHT "capture-height" + +/** + * Total count of capturing. If you set this, it will caputre multiple time. + */ +#define MMCAM_CAPTURE_COUNT "capture-count" + +/** + * Interval between each capturing on Multishot. + */ +#define MMCAM_CAPTURE_INTERVAL "capture-interval" + +/** + * Set this when you want to stop multishot immediately. + */ +#define MMCAM_CAPTURE_BREAK_CONTINUOUS_SHOT "capture-break-cont-shot" + +/** + * Pointer of display buffer or ID of xwindow. + */ +#define MMCAM_DISPLAY_HANDLE "display-handle" + +/** + * Device of display. + * @see MMDisplayDeviceType (in mm_types.h) + */ +#define MMCAM_DISPLAY_DEVICE "display-device" + +/** + * Surface of display. + * @see MMDisplaySurfaceType (in mm_types.h) + */ +#define MMCAM_DISPLAY_SURFACE "display-surface" + +/** + * X position of display rectangle. + * This is only available when #MMCAM_DISPLAY_GEOMETRY_METHOD is MM_CAMCORDER_CUSTOM_ROI. + * @see MMCamcorderGeometryMethod + */ +#define MMCAM_DISPLAY_RECT_X "display-rect-x" + +/** + * Y position of display rectangle + * This is only available when #MMCAM_DISPLAY_GEOMETRY_METHOD is MM_CAMCORDER_CUSTOM_ROI. + * @see MMCamcorderGeometryMethod + */ +#define MMCAM_DISPLAY_RECT_Y "display-rect-y" + +/** + * Width of display rectangle + * This is only available when #MMCAM_DISPLAY_GEOMETRY_METHOD is MM_CAMCORDER_CUSTOM_ROI. + * @see MMCamcorderGeometryMethod + */ +#define MMCAM_DISPLAY_RECT_WIDTH "display-rect-width" + +/** + * Height of display rectangle + * This is only available when #MMCAM_DISPLAY_GEOMETRY_METHOD is MM_CAMCORDER_CUSTOM_ROI. + * @see MMCamcorderGeometryMethod + */ +#define MMCAM_DISPLAY_RECT_HEIGHT "display-rect-height" + +/** + * X position of source rectangle. When you want to crop the source, you can set the area with this value. + */ +#define MMCAM_DISPLAY_SOURCE_X "display-src-x" + +/** + * Y position of source rectangle. When you want to crop the source, you can set the area with this value. + */ +#define MMCAM_DISPLAY_SOURCE_Y "display-src-y" + +/** + * Width of source rectangle. When you want to crop the source, you can set the area with this value. + */ +#define MMCAM_DISPLAY_SOURCE_WIDTH "display-src-width" + +/** + * Height of source rectangle. When you want to crop the source, you can set the area with this value. + */ +#define MMCAM_DISPLAY_SOURCE_HEIGHT "display-src-height" + +/** + * Rotation angle of display. + * @see MMDisplayRotationType (in mm_types.h) + */ +#define MMCAM_DISPLAY_ROTATION "display-rotation" + +/** + * Visible of display. + */ +#define MMCAM_DISPLAY_VISIBLE "display-visible" + +/** + * A scale of displayed image. Available value is like below. + * @see MMDisplayScaleType (in mm_types.h) + */ +#define MMCAM_DISPLAY_SCALE "display-scale" + +/** + * A method that describes a form of geometry for display. + * @see MMCamcorderGeometryMethod + */ +#define MMCAM_DISPLAY_GEOMETRY_METHOD "display-geometry-method" + +/** + * Target filename. Only used in Audio/Video recording. This is not used for capturing. + */ +#define MMCAM_TARGET_FILENAME "target-filename" + +/** + * Time limit(Second) of recording file. If the elapsed time of recording reaches this value, + * camcorder will send 'MM_MESSAGE_CAMCORDER_TIME_LIMIT' message. + */ +#define MMCAM_TARGET_TIME_LIMIT "target-time-limit" + +/** + * Enable to write tags. If this value is FALSE, none of tag information will be written to captured file. + */ +#define MMCAM_TAG_ENABLE "tag-enable" + +/** + * Image description. + */ +#define MMCAM_TAG_IMAGE_DESCRIPTION "tag-image-description" + +/** + * Orientation of captured image + * @see MMCamcorderTagOrientation + */ +#define MMCAM_TAG_ORIENTATION "tag-orientation" + +/** + * software name and version + */ +#define MMCAM_TAG_SOFTWARE "tag-software" + +/** + * Enable to write tags related to GPS. If this value is TRUE, tags related GPS information will be written to captured file. + */ +#define MMCAM_TAG_GPS_ENABLE "tag-gps-enable" + +/** + * Latitude of captured postion. GPS information. + */ +#define MMCAM_TAG_LATITUDE "tag-latitude" + +/** + * Longitude of captured postion. GPS information. + */ +#define MMCAM_TAG_LONGITUDE "tag-longitude" + +/** + * Altitude of captured postion. GPS information. + */ +#define MMCAM_TAG_ALTITUDE "tag-altitude" + +/** + * Strobe control + * @see MMCamcorderStrobeControl + */ +#define MMCAM_STROBE_CONTROL "strobe-control" + +/** + * Operation Mode of strobe + * @see MMCamcorderStrobeMode + */ +#define MMCAM_STROBE_MODE "strobe-mode" + +/** + * Detection mode + * @see MMCamcorderDetectMode + */ +#define MMCAM_DETECT_MODE "detect-mode" + +/** + * Total number of detected object + */ +#define MMCAM_DETECT_NUMBER "detect-number" + +/** + * You can use this attribute to select one of detected objects. + */ +#define MMCAM_DETECT_FOCUS_SELECT "detect-focus-select" + +/** + * Recommend preview format for capture + */ +#define MMCAM_RECOMMEND_PREVIEW_FORMAT_FOR_CAPTURE "recommend-preview-format-for-capture" + +/** + * Recommend preview format for recording + */ +#define MMCAM_RECOMMEND_PREVIEW_FORMAT_FOR_RECORDING "recommend-preview-format-for-recording" + +/** + * Recommend rotation of display + */ +#define MMCAM_RECOMMEND_DISPLAY_ROTATION "recommend-display-rotation" + +/** + * Rotation angle of video input stream and display for video recording. + */ +#define MMCAM_CAMCORDER_ROTATION "camcorder-rotation" + +/*======================================================================================= +| ENUM DEFINITIONS | +========================================================================================*/ +/** + * An enumeration for camcorder states. + */ +typedef enum { + MM_CAMCORDER_STATE_NONE, /**< Camcorder is not created yet */ + MM_CAMCORDER_STATE_NULL, /**< Camcorder is created, but not initialized yet */ + MM_CAMCORDER_STATE_READY, /**< Camcorder is ready to capture */ + MM_CAMCORDER_STATE_PREPARE, /**< Camcorder is prepared to capture (Preview) */ + MM_CAMCORDER_STATE_CAPTURING, /**< Camcorder is now capturing still images */ + MM_CAMCORDER_STATE_RECORDING, /**< Camcorder is now recording */ + MM_CAMCORDER_STATE_PAUSED, /**< Camcorder is paused while recording */ + MM_CAMCORDER_STATE_NUM, /**< Number of camcorder states */ +} MMCamcorderStateType; + +/** + * 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 */ +} MMCamcorderModeType; + + +/** + * An enumeration of Audio Format. + */ +typedef enum +{ + MM_CAMCORDER_AUDIO_FORMAT_PCM_U8 = 0, /**< unsigned 8bit audio */ + MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE = 2, /**< signed 16bit audio. Little endian. */ +} MMCamcorderAudioFormat; + + +/** + * An enumeration for color tone. Color tone provides an impression of + * 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 */ +}; + + +/** + * An enumeration for white balance. White Balance is the control that adjusts + * the camcorder's color sensitivity to match the prevailing color of white + * outdoor light, yellower indoor light, or (sometimes) greenish fluorescent + * light. White balance may be set either automatically or manually. White balance + * may be set "incorrectly" on purpose to achieve special effects. + */ +enum MMCamcorderWhiteBalanceType { + MM_CAMCORDER_WHITE_BALANCE_NONE = 0, /**< None */ + MM_CAMCORDER_WHITE_BALANCE_AUTOMATIC, /**< Automatic */ + MM_CAMCORDER_WHITE_BALANCE_DAYLIGHT, /**< Daylight */ + MM_CAMCORDER_WHITE_BALANCE_CLOUDY, /**< Cloudy */ + MM_CAMCORDER_WHITE_BALANCE_FLUOROSCENT, /**< Fluorescent */ + MM_CAMCORDER_WHITE_BALANCE_INCANDESCENT, /**< Incandescent */ + MM_CAMCORDER_WHITE_BALANCE_SHADE, /**< Shade */ + MM_CAMCORDER_WHITE_BALANCE_HORIZON, /**< Horizon */ + MM_CAMCORDER_WHITE_BALANCE_FLASH, /**< Flash */ + MM_CAMCORDER_WHITE_BALANCE_CUSTOM, /**< Custom */ + +}; + + +/** + * An enumeration for scene mode. Scene mode gives the environment condition + * for operating camcorder. The mode of operation can be in daylight, night and + * backlight. It can be an automatic setting also. + */ +enum MMCamcorderSceneModeType { + MM_CAMCORDER_SCENE_MODE_NORMAL = 0, /**< Normal */ + MM_CAMCORDER_SCENE_MODE_PORTRAIT, /**< Portrait */ + MM_CAMCORDER_SCENE_MODE_LANDSCAPE, /**< Landscape */ + MM_CAMCORDER_SCENE_MODE_SPORTS, /**< Sports */ + MM_CAMCORDER_SCENE_MODE_PARTY_N_INDOOR, /**< Party & indoor */ + MM_CAMCORDER_SCENE_MODE_BEACH_N_INDOOR, /**< Beach & indoor */ + MM_CAMCORDER_SCENE_MODE_SUNSET, /**< Sunset */ + MM_CAMCORDER_SCENE_MODE_DUSK_N_DAWN, /**< Dusk & dawn */ + MM_CAMCORDER_SCENE_MODE_FALL_COLOR, /**< Fall */ + MM_CAMCORDER_SCENE_MODE_NIGHT_SCENE, /**< Night scene */ + MM_CAMCORDER_SCENE_MODE_FIREWORK, /**< Firework */ + MM_CAMCORDER_SCENE_MODE_TEXT, /**< Text */ + MM_CAMCORDER_SCENE_MODE_SHOW_WINDOW, /**< Show window */ + MM_CAMCORDER_SCENE_MODE_CANDLE_LIGHT, /**< Candle light */ + MM_CAMCORDER_SCENE_MODE_BACKLIGHT, /**< Backlight */ +}; + + +/** + * An enumeration for focusing . + */ +enum MMCamcorderFocusMode { + MM_CAMCORDER_FOCUS_MODE_NONE = 0, /**< Focus mode is None */ + MM_CAMCORDER_FOCUS_MODE_PAN, /**< Pan focus mode*/ + MM_CAMCORDER_FOCUS_MODE_AUTO, /**< Autofocus mode*/ + MM_CAMCORDER_FOCUS_MODE_MANUAL, /**< Manual focus mode*/ + MM_CAMCORDER_FOCUS_MODE_TOUCH_AUTO, /**< Touch Autofocus mode*/ + MM_CAMCORDER_FOCUS_MODE_CONTINUOUS, /**< Continuous Autofocus mode*/ +}; + + +/** + * An enumeration for auto focus scan range (af scan range) + */ +enum MMCamcorderAutoFocusType { + MM_CAMCORDER_AUTO_FOCUS_NONE = 0, /**< Scan autofocus is not set */ + MM_CAMCORDER_AUTO_FOCUS_NORMAL, /**< Scan autofocus normally*/ + MM_CAMCORDER_AUTO_FOCUS_MACRO, /**< Scan autofocus in macro mode(close distance)*/ + MM_CAMCORDER_AUTO_FOCUS_FULL, /**< Scan autofocus in full mode(all range scan, limited by dev spec)*/ +}; + + +/** + * An enumeration for focus state. + * When 'MM_MESSAGE_CAMCORDER_FOCUS_CHANGED' is delievered through 'MMMessageCallback', + * this enumeration will be set to 'code' of MMMessageParamType. + */ +enum MMCamcorderFocusStateType { + MM_CAMCORDER_FOCUS_STATE_RELEASED = 0, /**< Focus released.*/ + MM_CAMCORDER_FOCUS_STATE_ONGOING, /**< Focus in pregress*/ + MM_CAMCORDER_FOCUS_STATE_FOCUSED, /**< Focus success*/ + MM_CAMCORDER_FOCUS_STATE_FAILED, /**< Focus failed*/ +}; + + +/** + * An enumeration for ISO. + */ +enum MMCamcorderISOType { + MM_CAMCORDER_ISO_AUTO = 0, /**< ISO auto mode*/ + MM_CAMCORDER_ISO_50, /**< ISO 50*/ + MM_CAMCORDER_ISO_100, /**< ISO 100*/ + MM_CAMCORDER_ISO_200, /**< ISO 200*/ + MM_CAMCORDER_ISO_400, /**< ISO 400*/ + MM_CAMCORDER_ISO_800, /**< ISO 800*/ + MM_CAMCORDER_ISO_1600, /**< ISO 1600*/ + MM_CAMCORDER_ISO_3200, /**< ISO 3200*/ + MM_CAMCORDER_ISO_6400, /**< ISO 6400*/ + MM_CAMCORDER_ISO_12800, /**< ISO 12800*/ +}; + +/** + * An enumeration for Automatic exposure. + */ +enum MMCamcorderAutoExposureType { + MM_CAMCORDER_AUTO_EXPOSURE_OFF = 0, /**< AE off*/ + MM_CAMCORDER_AUTO_EXPOSURE_ALL, /**< AE on, XXX mode*/ + MM_CAMCORDER_AUTO_EXPOSURE_CENTER_1, /**< AE on, XXX mode*/ + MM_CAMCORDER_AUTO_EXPOSURE_CENTER_2, /**< AE on, XXX mode*/ + MM_CAMCORDER_AUTO_EXPOSURE_CENTER_3, /**< AE on, XXX mode*/ + MM_CAMCORDER_AUTO_EXPOSURE_SPOT_1, /**< AE on, XXX mode*/ + MM_CAMCORDER_AUTO_EXPOSURE_SPOT_2, /**< AE on, XXX mode*/ + MM_CAMCORDER_AUTO_EXPOSURE_CUSTOM_1, /**< AE on, XXX mode*/ + MM_CAMCORDER_AUTO_EXPOSURE_CUSTOM_2, /**< AE on, XXX mode*/ +}; + + +/** + * An enumeration for WDR mode . + */ +enum MMCamcorderWDRMode { + MM_CAMCORDER_WDR_OFF = 0, /**< WDR OFF*/ + MM_CAMCORDER_WDR_ON, /**< WDR ON*/ + MM_CAMCORDER_WDR_AUTO, /**< WDR AUTO*/ +}; + + +/** + * An enumeration for Anti-handshake mode . + */ +enum MMCamcorderAHSMode { + MM_CAMCORDER_AHS_OFF = 0, /**< AHS OFF*/ + MM_CAMCORDER_AHS_ON, /**< AHS ON*/ + MM_CAMCORDER_AHS_AUTO, /**< AHS AUTO*/ + MM_CAMCORDER_AHS_MOVIE, /**< AHS MOVIE*/ +}; + + +/** + * Geometry method for camcorder display. + */ +enum MMCamcorderGeometryMethod { + MM_CAMCORDER_LETTER_BOX = 0, /**< Letter box*/ + MM_CAMCORDER_ORIGIN_SIZE, /**< Origin size*/ + MM_CAMCORDER_FULL, /**< full-screen*/ + MM_CAMCORDER_CROPPED_FULL, /**< Cropped full-screen*/ + MM_CAMCORDER_CUSTOM_ROI, /**< Explicitely described destination ROI*/ +}; + + +/** + * An enumeration for orientation values of tag . + */ +enum MMCamcorderTagOrientation { + MM_CAMCORDER_TAG_ORT_NONE =0, /**< No Orientation.*/ + MM_CAMCORDER_TAG_ORT_0R_VT_0C_VL, /**< The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.*/ + MM_CAMCORDER_TAG_ORT_0R_VT_0C_VR, /**< The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.*/ + MM_CAMCORDER_TAG_ORT_0R_VB_0C_VR, /**< The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.*/ + MM_CAMCORDER_TAG_ORT_0R_VB_0C_VL, /**< The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.*/ + MM_CAMCORDER_TAG_ORT_0R_VL_0C_VT, /**< The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.*/ + MM_CAMCORDER_TAG_ORT_0R_VR_0C_VT, /**< The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.*/ + MM_CAMCORDER_TAG_ORT_0R_VR_0C_VB, /**< The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.*/ + MM_CAMCORDER_TAG_ORT_0R_VL_0C_VB, /**< The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.*/ +}; + + +/** + * An enumeration for Strobe mode. + */ +enum MMCamcorderStrobeMode { + MM_CAMCORDER_STROBE_MODE_OFF = 0, /**< Always off */ + MM_CAMCORDER_STROBE_MODE_ON, /**< Always splashes */ + MM_CAMCORDER_STROBE_MODE_AUTO, /**< Depending on intensity of light, strobe starts to flash. */ + MM_CAMCORDER_STROBE_MODE_REDEYE_REDUCTION, /**< Red eye reduction. Multiple flash before capturing. */ + MM_CAMCORDER_STROBE_MODE_SLOW_SYNC, /**< Slow sync. A type of curtain synchronization. */ + MM_CAMCORDER_STROBE_MODE_FRONT_CURTAIN, /**< Front curtain. A type of curtain synchronization. */ + MM_CAMCORDER_STROBE_MODE_REAR_CURTAIN, /**< Rear curtain. A type of curtain synchronization. */ + MM_CAMCORDER_STROBE_MODE_PERMANENT, /**< keep turned on until turning off */ +}; + + +/** + * An enumeration for Strobe Control. + */ +enum MMCamcorderStrobeControl { + MM_CAMCORDER_STROBE_CONTROL_OFF = 0, /**< turn off the flash light */ + MM_CAMCORDER_STROBE_CONTROL_ON, /**< turn on the flash light */ + MM_CAMCORDER_STROBE_CONTROL_CHARGE, /**< charge the flash light */ +}; + + +/** + * An enumeration for Detection mode. + */ +enum MMCamcorderDetectMode { + MM_CAMCORDER_DETECT_MODE_OFF = 0, /**< turn detection off */ + MM_CAMCORDER_DETECT_MODE_ON, /**< turn detection on */ +}; + + +/********************************** +* Attribute info * +**********************************/ +/** + * An enumeration for attribute values types. + */ +typedef enum{ + MM_CAM_ATTRS_TYPE_INVALID = -1, /**< Type is invalid */ + MM_CAM_ATTRS_TYPE_INT, /**< Integer type attribute */ + 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; + + +/** + * An enumeration for attribute validation type. + */ +typedef enum { + MM_CAM_ATTRS_VALID_TYPE_INVALID = -1, /**< Invalid validation type */ + MM_CAM_ATTRS_VALID_TYPE_NONE, /**< Do not check validity */ + MM_CAM_ATTRS_VALID_TYPE_INT_ARRAY, /**< validity checking type of integer array */ + MM_CAM_ATTRS_VALID_TYPE_INT_RANGE, /**< validity checking type of integer range */ + MM_CAM_ATTRS_VALID_TYPE_DOUBLE_ARRAY, /**< validity checking type of double array */ + MM_CAM_ATTRS_VALID_TYPE_DOUBLE_RANGE, /**< validity checking type of double range */ +} MMCamAttrsValidType; + + +/** + * An enumeration for attribute access flag. + */ +typedef enum { + MM_CAM_ATTRS_FLAG_DISABLED = 0, /**< None flag is set. This means the attribute is not allowed to use. */ + MM_CAM_ATTRS_FLAG_READABLE = 1 << 0, /**< Readable */ + MM_CAM_ATTRS_FLAG_WRITABLE = 1 << 1, /**< Writable */ + MM_CAM_ATTRS_FLAG_MODIFIED = 1 << 2, /**< Modified */ + MM_CAM_ATTRS_FLAG_RW = MM_CAM_ATTRS_FLAG_READABLE | MM_CAM_ATTRS_FLAG_WRITABLE, /**< Readable and Writable */ +} MMCamAttrsFlag; + + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ +/** + * A structure for attribute information + */ +typedef struct { + MMCamAttrsType type; + MMCamAttrsFlag flag; + MMCamAttrsValidType validity_type; + + /** + * A union that describes validity of the attribute. + * Only when type is 'MM_CAM_ATTRS_TYPE_INT' or 'MM_CAM_ATTRS_TYPE_DOUBLE', + * the attribute can have validity. + */ + union { + /** + * Validity structure for integer array. + */ + struct { + int *array; /**< a pointer of array */ + int count; /**< size of array */ + int def; /**< default value. Real value not index of array */ + } int_array; + + /** + * Validity structure for integer range. + */ + struct { + int min; /**< minimum range */ + int max; /**< maximum range */ + int def; /**< default value */ + } int_range; + + /** + * Validity structure for double array. + */ + struct { + double *array; /**< a pointer of array */ + int count; /**< size of array */ + double def; /**< default value. Real value not index of array */ + } double_array; + + /** + * Validity structure for double range. + */ + struct { + double min; /**< minimum range */ + double max; /**< maximum range */ + double def; /**< default value */ + } double_range; + }; +} MMCamAttrsInfo; + + +/* General Structure */ +/** + * Structure for capture data. + */ +typedef struct { + void *data; /**< pointer of captured image */ + unsigned int length; /**< length of captured image (in byte)*/ + MMPixelFormatType format; /**< image format */ + int width; /**< width of captured image */ + int height; /**< height of captured image */ + int encoder_type; /**< encoder type */ +} MMCamcorderCaptureDataType; + + +/** + * 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)*/ +} MMCamcorderVideoStreamDataType; + + +/** + * Structure for audio stream data. + */ +typedef struct { + void *data; /**< pointer of captured stream */ + unsigned int length; /**< length of stream buffer (in byte)*/ + MMCamcorderAudioFormat format; /**< audio format */ + int channel; /**< number of channel of the stream */ + unsigned int timestamp; /**< timestamp of stream buffer (msec)*/ + float volume_dB; /**< dB value of audio stream */ +} MMCamcorderAudioStreamDataType; + + +/** + * Prerequisite information for mm_camcorder_create() + * The information to set prior to create. + */ +typedef struct { + enum MMVideoDeviceType videodev_type; /**< Video device type */ + /* For future use */ + int reserved[4]; /**< reserved fields */ +} MMCamPreset; + + +/** + * Report structure of recording file + */ +typedef struct MMCamRecordingReport { + char *recording_filename; /**< File name of stored recording file. Please free after using. */ +}MMCamRecordingReport; /**< report structure definition of recording file */ + + +/*======================================================================================= +| TYPE DEFINITIONS | +========================================================================================*/ +/** + * Function definition for video stream callback. + * Be careful! In this function, you can't call functions that change the state of camcorder such as mm_camcorder_stop(), + * mm_camcorder_unrealize(), mm_camcorder_record(), mm_camcorder_commit(), and mm_camcorder_cancel(), etc. + * Please don't hang this function long. It may cause low performance of preview or occur timeout error from video source. + * Also, you're not allowed to call mm_camcorder_stop() even in other context, while you're hanging this function. + * I recommend to you releasing this function ASAP. + * + * @param[in] stream Reference pointer to video stream data + * @param[in] user_param User parameter which is received from user when callback function was set + * @return This function returns true on success, or false on failure. + * @remarks This function is issued in the context of gstreamer (video sink thread). + */ +typedef gboolean (*mm_camcorder_video_stream_callback)(MMCamcorderVideoStreamDataType *stream, void *user_param); + + +/** + * Function definition for audio stream callback. + * Be careful! In this function, you can't call functions that change the state of camcorder such as mm_camcorder_stop(), + * mm_camcorder_unrealize(), mm_camcorder_record(), mm_camcorder_commit(), and mm_camcorder_cancel(), etc. + * Please don't hang this function long. It may cause low performance of camcorder or occur timeout error from audio source. + * I recommend to you releasing this function ASAP. + * + * @param[in] stream Reference pointer to audio stream data + * @param[in] user_param User parameter which is received from user when callback function was set + * @return This function returns true on success, or false on failure. + * @remarks + */ +typedef gboolean (*mm_camcorder_audio_stream_callback)(MMCamcorderAudioStreamDataType *stream, void *user_param); + + +/** + * Function definition for video capture callback. + * Like '#mm_camcorder_video_stream_callback', you can't call mm_camcorder_stop() while you are hanging this function. + * + * @param[in] frame Reference pointer to captured data + * @param[in] thumbnail Reference pointer to thumbnail data + * @param[in] user_param User parameter which is received from user when callback function was set + * @return This function returns true on success, or false on failure. + * @remarks This function is issued in the context of gstreamer (video src thread). + */ +typedef gboolean (*mm_camcorder_video_capture_callback)(MMCamcorderCaptureDataType *frame, MMCamcorderCaptureDataType *thumbnail, void *user_param); + + +/*======================================================================================= +| GLOBAL FUNCTION PROTOTYPES | +========================================================================================*/ +/** + * mm_camcorder_create:\n + * Create camcorder object. This is the function that an user who wants to use mm_camcorder calls first. + * This function creates handle structure and initialize mutex, attributes, gstreamer. + * When this function success, it will return a handle of newly created object. + * A user have to put the handle when he calls every function of mm_camcorder. \n + * Second argument of this function is the field to decribe pre-setting information of mm_camcorder such as which camera device it will use. + * Normally, MM_VIDEO_DEVICE_CAMERA0 is for Main camera(or Mega camera, Back camera), + * and MM_VIDEO_DEVICE_CAMERA1 is for VGA camera (or Front camera). If you want audio recording, + * please set MM_VIDEO_DEVICE_NONE. (No camera device is needed.) + * + * @param[out] camcorder A handle of camcorder. + * @param[in] info Information for camera device. Depending on this information, + * camcorder opens different camera devices. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_destroy + * @pre None + * @post Next state of mm-camcorder will be MM_CAMCORDER_STATE_NULL + * @remarks You can create multiple handles on a context at the same time. However, + * camcorder cannot guarantee proper operation because of limitation of resources, such as + * camera device, audio device, and display device. + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean initialize_camcorder() +{ + int err; + MMCamPreset cam_info; +#if 1 + cam_info.videodev_type = MM_VIDEO_DEVICE_CAMERA0; +#else + // when you want to record audio only, enable this. + cam_info.videodev_type = MM_VIDEO_DEVICE_NONE; +#endif + + err = mm_camcorder_create(&hcam, &cam_info); + + if (err != MM_ERROR_NONE) { + printf("Fail to call mm_camcorder_create = %x\n", err); + return FALSE; + } + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_create(MMHandleType *camcorder, MMCamPreset *info); + + +/** + * mm_camcorder_destroy:\n + * Destroy camcorder object. Release handle and all of the resources that were created in mm_camcorder_create().\n + * This is the finalizing function of mm_camcorder. If this function is not called or fails to call, the handle isn't released fully. + * This function releases attributes, mutexes, sessions, and handle itself. This function also removes all of remaining messages. + * So if your application should wait a certain message of mm_camcorder, please wait to call this function till getting the message. + * + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_create + * @pre Previous state of mm-camcorder should be MM_CAMCORDER_STATE_NULL + * @post Because the handle is not valid, you can't check the state. + * @remarks None + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean destroy_camcorder() +{ + int err; + + //Destroy camcorder handle + err = mm_camcorder_destroy(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_destroy = %x\n", err); + return FALSE; + } + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_destroy(MMHandleType camcorder); + + +/** + * mm_camcorder_realize:\n + * Allocate resources for camcorder and initialize it. + * This also creates streamer pipeline. So you have to set attributes that are pivotal to create + * the pipeline before calling this function. This function also takes a roll to manage confliction + * between different applications which use camcorder. For example, if you try to use camcorder when + * other application that is more important such as call application, this function will return + * 'MM_ERROR_POLICY_BLOCKED'. On the contrary, if your application that uses camcorder starts to launch + * while another application that uses speaker and has lower priority, your application will kick + * another application. + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_unrealize + * @pre Previous state of mm-camcorder should be MM_CAMCORDER_STATE_NULL + * @post Next state of mm-camcorder will be MM_CAMCORDER_STATE_READY + * @remarks None + * @par example + * @code + +#include <mm_camcorder.h> + +//For image capturing +gboolean initialize_image_capture() +{ + int err; + MMCamPreset cam_info; + char *err_attr_name = NULL; + void * hdisplay = NULL; + int hsize = 0; + + //Set video device as 'camera0' (main camera device) + cam_info.videodev_type = MM_VIDEO_DEVICE_CAMERA0; + + err = mm_camcorder_create(&hcam, &cam_info); + + if (err != MM_ERROR_NONE) { + printf("Fail to call mm_camcorder_create = %x\n", err); + return FALSE; + } + + mm_camcorder_set_message_callback(hcam,(MMMessageCallback)msg_callback, (void*)hcam); + mm_camcorder_set_video_capture_callback(hcam,(mm_camcorder_video_capture_callback)camcordertest_video_capture_cb, (void*)hcam); + + hdisplay = &ad.xid; //xid of xwindow. This value can be different depending on your environment. + hsize = sizeof(ad.xid); //size of xid structure. + + // camcorder attribute setting + err = mm_camcorder_set_attributes((MMHandleType)hcam, &err_attr_name, + MMCAM_MODE, MM_CAMCORDER_MODE_IMAGE, + MMCAM_IMAGE_ENCODER, MM_IMAGE_CODEC_JPEG, + MMCAM_CAMERA_WIDTH, 640, + MMCAM_CAMERA_HEIGHT, 480, + MMCAM_CAMERA_FORMAT, MM_PIXEL_FORMAT_YUYV, + MMCAM_CAMERA_FPS, 30, + MMCAM_DISPLAY_ROTATION, MM_DISPLAY_ROTATION_270, + MMCAM_DISPLAY_HANDLE, (void*) hdisplay, hsize, + MMCAM_CAPTURE_FORMAT, MM_PIXEL_FORMAT_ENCODED, + MMCAM_CAPTURE_WIDTH, 640, + MMCAM_CAPTURE_HEIGHT, 480, + NULL); + + if (err < 0) { + printf("Set attrs fail. (%s:%x)\n", err_attr_name, err); + if (err_attr_name) { + free(err_attr_name); + err_attr_name = NULL; + return FALSE; + } + } + + err = mm_camcorder_realize(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_realize = %x\n", err); + return FALSE; + } + + return TRUE; +} + +//For A/V capturing +gboolean initialize_video_capture() +{ + int err; + MMCamPreset cam_info; + char *err_attr_name = NULL; + void * hdisplay = NULL; + int hsize = 0; + + //Set video device as 'camera0' (main camera device) + cam_info.videodev_type = MM_VIDEO_DEVICE_CAMERA0; + + err = mm_camcorder_create(&hcam, &cam_info); + + if (err != MM_ERROR_NONE) { + printf("Fail to call mm_camcorder_create = %x\n", err); + return FALSE; + } + + mm_camcorder_set_message_callback(hcam,(MMMessageCallback)msg_callback, hcam); + + hdisplay = &ad.xid; //xid of xwindow. This value can be different depending on your environment. + hsize = sizeof(ad.xid); //size of xid structure. + + // camcorder attribute setting + err = mm_camcorder_set_attributes((MMHandleType)hcam, &err_attr_name, + MMCAM_MODE, MM_CAMCORDER_MODE_VIDEO, + MMCAM_AUDIO_DEVICE, MM_AUDIO_DEVICE_MIC, + MMCAM_AUDIO_ENCODER, MM_AUDIO_CODEC_AAC, + MMCAM_VIDEO_ENCODER, MM_VIDEO_CODEC_MPEG4, + MMCAM_FILE_FORMAT, MM_FILE_FORMAT_3GP, + MMCAM_CAMERA_WIDTH, 1280, + MMCAM_CAMERA_HEIGHT, 720, + MMCAM_CAMERA_FORMAT, MM_PIXEL_FORMAT_NV12, + MMCAM_CAMERA_FPS, 30, + MMCAM_AUDIO_SAMPLERATE, 44100, + MMCAM_AUDIO_FORMAT, MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE, + MMCAM_AUDIO_CHANNEL, 2, + MMCAM_DISPLAY_ROTATION, MM_DISPLAY_ROTATION_270, + MMCAM_DISPLAY_HANDLE, (void*) hdisplay, hsize, + MMCAM_TARGET_FILENAME, TARGET_FILENAME, strlen(TARGET_FILENAME), + NULL); + + if (err < 0) { + printf("Set attrs fail. (%s:%x)\n", err_attr_name, err); + if (err_attr_name) { + free(err_attr_name); + err_attr_name = NULL; + return FALSE; + } + } + + err = mm_camcorder_realize(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_realize = %x\n", err); + return FALSE; + } + + return TRUE; +} + +//For audio(only) capturing +gboolean initialize_audio_capture() +{ + int err; + MMCamPreset cam_info; + char *err_attr_name = NULL; + void * hdisplay = NULL; + int hsize = 0; + + //Set no video device, because audio recording doesn't need video input. + cam_info.videodev_type = MM_VIDEO_DEVICE_NONE; + + err = mm_camcorder_create(&hcam, &cam_info); + + if (err != MM_ERROR_NONE) { + printf("Fail to call mm_camcorder_create = %x\n", err); + return FALSE; + } + + mm_camcorder_set_message_callback(hcam,(MMMessageCallback)msg_callback, (void*)hcam); + + hdisplay = &ad.xid; //xid of xwindow. This value can be different depending on your environment. + hsize = sizeof(ad.xid); //size of xid structure. + + // camcorder attribute setting + err = mm_camcorder_set_attributes((MMHandleType)hcam, &err_attr_name, + MMCAM_MODE, MM_CAMCORDER_MODE_AUDIO, + MMCAM_AUDIO_DEVICE, MM_AUDIO_DEVICE_MIC, + MMCAM_AUDIO_ENCODER, MM_AUDIO_CODEC_AAC, + MMCAM_FILE_FORMAT, MM_FILE_FORMAT_3GP, + MMCAM_AUDIO_SAMPLERATE, 44100, + MMCAM_AUDIO_FORMAT, MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE, + MMCAM_AUDIO_CHANNEL, 2, + MMCAM_TARGET_FILENAME, TARGET_FILENAME, strlen(TARGET_FILENAME), + MMCAM_TARGET_TIME_LIMIT, 360000, + NULL); + + if (err < 0) { + printf("Set attrs fail. (%s:%x)\n", err_attr_name, err); + if (err_attr_name) { + free(err_attr_name); + err_attr_name = NULL; + return FALSE; + } + } + + err = mm_camcorder_realize(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_realize = %x\n", err); + return FALSE; + } + + return TRUE; +} + * @endcode + */ +int mm_camcorder_realize(MMHandleType camcorder); + + +/** + * mm_camcorder_unrealize:\n + * Uninitialize camcoder resources and free allocated memory. + * Most important resource that is released here is gstreamer pipeline of mm_camcorder. + * Because most of resources, such as camera device, video display device, and audio I/O device, are operating on the gstreamer pipeline, + * this function should be called to release its resources. + * Moreover, mm_camcorder is controlled by audio session manager. If an user doesn't call this function when he want to release mm_camcorder, + * other multimedia frameworks may face session problem. For more detail information, please refer mm_session module. + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_realize + * @pre Previous state of mm-camcorder should be MM_CAMCORDER_STATE_READY + * @post Next state of mm-camcorder will be MM_CAMCORDER_STATE_NULL + * @remarks None + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean unrealize_camcorder() +{ + int err; + + //Release all resources of camcorder handle + err = mm_camcorder_unrealize(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_unrealize = %x\n", err); + return FALSE; + } + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_unrealize(MMHandleType camcorder); + + +/** + * mm_camcorder_start:\n + * Start previewing. (Image/Video mode) + * 'mm_camcorder_video_stream_callback' is activated after calling this function. + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_stop + * @pre Previous state of mm-camcorder should be MM_CAMCORDER_STATE_READY + * @post Next state of mm-camcorder will be MM_CAMCORDER_STATE_PREPARE + * @remarks None + * @par example + * @code + +#include <mm_camcorder.h> + +//For image capturing +gboolean initialize_image_capture() +{ + int err; + MMCamPreset cam_info; + char *err_attr_name = NULL; + void * hdisplay = NULL; + int hsize = 0; + + //Set video device as 'camera0' (main camera device) + cam_info.videodev_type = MM_VIDEO_DEVICE_CAMERA0; + + err = mm_camcorder_create(&hcam, &cam_info); + + if (err != MM_ERROR_NONE) { + printf("Fail to call mm_camcorder_create = %x\n", err); + return FALSE; + } + + mm_camcorder_set_message_callback(hcam,(MMMessageCallback)msg_callback, (void*)hcam); + mm_camcorder_set_video_capture_callback(hcam,(mm_camcorder_video_capture_callback)camcordertest_video_capture_cb, (void*)hcam); + + hdisplay = &ad.xid; //xid of xwindow. This value can be different depending on your environment. + hsize = sizeof(ad.xid); //size of xid structure. + + // camcorder attribute setting + err = mm_camcorder_set_attributes((MMHandleType)hcam, &err_attr_name, + MMCAM_MODE, MM_CAMCORDER_MODE_IMAGE, + MMCAM_IMAGE_ENCODER, MM_IMAGE_CODEC_JPEG, + MMCAM_CAMERA_WIDTH, 640, + MMCAM_CAMERA_HEIGHT, 480, + MMCAM_CAMERA_FORMAT, MM_PIXEL_FORMAT_YUYV, + MMCAM_CAMERA_FPS, 30, + MMCAM_DISPLAY_ROTATION, MM_DISPLAY_ROTATION_270, + MMCAM_DISPLAY_HANDLE, (void*) hdisplay, hsize, + MMCAM_CAPTURE_FORMAT, MM_PIXEL_FORMAT_ENCODED, + MMCAM_CAPTURE_WIDTH, 640, + MMCAM_CAPTURE_HEIGHT, 480, + NULL); + + if (err < 0) { + printf("Set attrs fail. (%s:%x)\n", err_attr_name, err); + if (err_attr_name) { + free(err_attr_name); + err_attr_name = NULL; + return FALSE; + } + } + + err = mm_camcorder_realize(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_realize = %x\n", err); + return FALSE; + } + + // start camcorder + err = mm_camcorder_start(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_start = %x\n", err); + return FALSE; + } + + return TRUE; +} + +//For A/V capturing +gboolean initialize_video_capture() +{ + int err; + MMCamPreset cam_info; + char *err_attr_name = NULL; + void * hdisplay = NULL; + int hsize = 0; + + //Set video device as 'camera0' (main camera device) + cam_info.videodev_type = MM_VIDEO_DEVICE_CAMERA0; + + err = mm_camcorder_create(&hcam, &cam_info); + + if (err != MM_ERROR_NONE) { + printf("Fail to call mm_camcorder_create = %x\n", err); + return FALSE; + } + + mm_camcorder_set_message_callback(hcam,(MMMessageCallback)msg_callback, hcam); + + hdisplay = &ad.xid; //xid of xwindow. This value can be different depending on your environment. + hsize = sizeof(ad.xid); //size of xid structure. + + // camcorder attribute setting + err = mm_camcorder_set_attributes((MMHandleType)hcam, &err_attr_name, + MMCAM_MODE, MM_CAMCORDER_MODE_VIDEO, + MMCAM_AUDIO_DEVICE, MM_AUDIO_DEVICE_MIC, + MMCAM_AUDIO_ENCODER, MM_AUDIO_CODEC_AAC, + MMCAM_VIDEO_ENCODER, MM_VIDEO_CODEC_MPEG4, + MMCAM_FILE_FORMAT, MM_FILE_FORMAT_3GP, + MMCAM_CAMERA_WIDTH, 1280, + MMCAM_CAMERA_HEIGHT, 720, + MMCAM_CAMERA_FORMAT, MM_PIXEL_FORMAT_NV12, + MMCAM_CAMERA_FPS, 30, + MMCAM_AUDIO_SAMPLERATE, 44100, + MMCAM_AUDIO_FORMAT, MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE, + MMCAM_AUDIO_CHANNEL, 2, + MMCAM_DISPLAY_ROTATION, MM_DISPLAY_ROTATION_270, + MMCAM_DISPLAY_HANDLE, (void*) hdisplay, hsize, + MMCAM_TARGET_FILENAME, TARGET_FILENAME, strlen(TARGET_FILENAME), + NULL); + + if (err < 0) { + printf("Set attrs fail. (%s:%x)\n", err_attr_name, err); + if (err_attr_name) { + free(err_attr_name); + err_attr_name = NULL; + return FALSE; + } + } + + err = mm_camcorder_realize(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_realize = %x\n", err); + return FALSE; + } + + // start camcorder + err = mm_camcorder_start(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_start = %x\n", err); + return FALSE; + } + + return TRUE; +} + +//For audio(only) capturing +gboolean initialize_audio_capture() +{ + int err; + MMCamPreset cam_info; + char *err_attr_name = NULL; + void * hdisplay = NULL; + int hsize = 0; + + //Set no video device, because audio recording doesn't need video input. + cam_info.videodev_type = MM_VIDEO_DEVICE_NONE; + + err = mm_camcorder_create(&hcam, &cam_info); + + if (err != MM_ERROR_NONE) { + printf("Fail to call mm_camcorder_create = %x\n", err); + return FALSE; + } + + mm_camcorder_set_message_callback(hcam,(MMMessageCallback)msg_callback, (void*)hcam); + + hdisplay = &ad.xid; //xid of xwindow. This value can be different depending on your environment. + hsize = sizeof(ad.xid); //size of xid structure. + + // camcorder attribute setting + err = mm_camcorder_set_attributes((MMHandleType)hcam, &err_attr_name, + MMCAM_MODE, MM_CAMCORDER_MODE_AUDIO, + MMCAM_AUDIO_DEVICE, MM_AUDIO_DEVICE_MIC, + MMCAM_AUDIO_ENCODER, MM_AUDIO_CODEC_AAC, + MMCAM_FILE_FORMAT, MM_FILE_FORMAT_3GP, + MMCAM_AUDIO_SAMPLERATE, 44100, + MMCAM_AUDIO_FORMAT, MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE, + MMCAM_AUDIO_CHANNEL, 2, + MMCAM_TARGET_FILENAME, TARGET_FILENAME, strlen(TARGET_FILENAME), + MMCAM_TARGET_TIME_LIMIT, 360000, + NULL); + + if (err < 0) { + printf("Set attrs fail. (%s:%x)\n", err_attr_name, err); + if (err_attr_name) { + free(err_attr_name); + err_attr_name = NULL; + return FALSE; + } + } + + err = mm_camcorder_realize(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_realize = %x\n", err); + return FALSE; + } + + // start camcorder + err = mm_camcorder_start(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_start = %x\n", err); + return FALSE; + } + + return TRUE; +} + * @endcode + */ +int mm_camcorder_start(MMHandleType camcorder); + + +/** + * mm_camcorder_stop:\n + * Stop previewing. (Image/Video mode) + * This function will change the status of pipeline. If an application doesn't return callbacks + * of camcorder, this function can be locked. For example, if your application still + * holds '#mm_camcorder_video_capture_callback' or '#mm_camcorder_video_stream_callback', + * this function could be hung. So users have to return every callback before calling this function. + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_start + * @pre Previous state of mm-camcorder should be MM_CAMCORDER_STATE_PREPARE + * @post Next state of mm-camcorder will be MM_CAMCORDER_STATE_READY + * @remarks None + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean stop_camcorder() +{ + int err; + + //Stop preview + err = mm_camcorder_stop(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_stop = %x\n", err); + return FALSE; + } + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_stop(MMHandleType camcorder); + + +/** + * mm_camcorder_capture_start:\n + * Start capturing of still images. (Image mode only) + * Captured image will be delievered through 'mm_camcorder_video_capture_callback'. + * So basically, the operation is working asynchronously. \n + * When a user call this function, MSL will stop to retrieving preview from camera device. + * Then set capture resolution, pixel format, and encoding type to camera driver. After resuming, + * camera can get still image. A user will be notified by + * 'MM_MESSAGE_CAMCORDER_CAPTURED' message when capturing succeed. When a user sets + * multishot (by setting multiple number to MMCAM_CAPTURE_COUNT), the message + * will be called multiple time. You can get the number of image from 'code' of + * 'MMMessageParamType'. + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_capture_stop + * @pre Previous state of mm-camcorder should be MM_CAMCORDER_STATE_PREPARE + * @post Next state of mm-camcorder will be MM_CAMCORDER_STATE_CAPTURING + * @remarks To call this function, preview should be started successfully.\n + * This function is a pair of mm_camcorder_capture_stop(). + * So user should call mm_camcorder_capture_stop() after getting captured image. + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean capturing_picture() +{ + int err; + + err = mm_camcorder_capture_start(hcam); + if (err < 0) + { + printf("Fail to call mm_camcorder_capture_start = %x\n", err); + return FALSE; + } + + //mm_camcorder_capture_stop should be called after getting + //MM_MESSAGE_CAMCORDER_CAPTURED message. + + return TRUE; +} + + + * @endcode + */ +int mm_camcorder_capture_start(MMHandleType camcorder); + + +/** + * mm_camcorder_capture_stop:\n + * Stop capturing of still images. (Image mode only) + * This function notifies the end of capturing and launch preview again. + * Just as mm_camcorder_capture_start(), this funciton stops still image stream and set preview information such as + * resolution, pixel format, and framerate to camera driver. Then it command to start preview. + * If you don't call this, preview will not be displayed even though capturing was finished. + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_capture_start + * @pre Previous state of mm-camcorder should be MM_CAMCORDER_STATE_CAPTURING + * @post Next state of mm-camcorder will be MM_CAMCORDER_STATE_PREPARE + * @remarks To call this function, a user has to call mm_camcorder_capture_start() first.\n + * This is not a function to stop multishot in the middle of operation. For that, + * please use '#MMCAM_CAPTURE_BREAK_CONTINUOUS_SHOT' instead. + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean capturing_picture_stop() +{ + int err; + + err = mm_camcorder_capture_stop(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_capture_stop = %x\n", err); + return FALSE; + } + + //After calling upper function, preview will start. + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_capture_stop(MMHandleType camcorder); + + +/** + * mm_camcorder_record:\n + * Start recording. (Audio/Video mode only) + * Camcorder starts to write a file when you call this function. You can specify the name of file + * using '#MMCAM_TARGET_FILENAME'. Beware, if you fail to call mm_camcorder_commit() or mm_camcorder_cancel(), + * the recorded file is still on the storage. + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_pause + * @pre Previous state of mm-camcorder should be MM_CAMCORDER_STATE_PREPARE + * @post Next state of mm-camcorder will be MM_CAMCORDER_STATE_RECORDING + * @remarks None + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean record_and_cancel_video_file() +{ + int err; + + // Start recording + err = mm_camcorder_record(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_record = %x\n", err); + return FALSE; + } + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_record(MMHandleType camcorder); + + +/** + * mm_camcorder_pause:\n + * Pause A/V recording or Audio recording. (Audio/Video mode only) + * On video recording, you can see preview while on pausing. So mm_camcorder cuts video stream path to encoder and keep the flow to preview. + * If you call mm_camcorder_commit() while on pausing, the recorded file only has Audio and Video stream which were generated before pause(). + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_record + * @pre Previous state of mm-camcorder should be MM_CAMCORDER_STATE_RECORDING + * @post Next state of mm-camcorder will be MM_CAMCORDER_STATE_PAUSED + * @remarks Even though this function is for pausing recording, small amount of buffers could be recorded after pause(). + * Because the buffers which are existed in the queue were created before pause(), the buffers should be recorded. + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean record_pause_and_resume_recording() +{ + int err; + + // Start recording + err = mm_camcorder_record(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_record = %x\n", err); + return FALSE; + } + + // Wait while recording... + + // Pause + err = mm_camcorder_pause(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_pause = %x\n", err); + return FALSE; + } + + // Pausing... + + // Resume + err = mm_camcorder_record(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_record = %x\n", err); + return FALSE; + } + + return TRUE; +} + + + * @endcode + */ +int mm_camcorder_pause(MMHandleType camcorder); + + +/** + * mm_camcorder_commit:\n + * Stop recording and save results. (Audio/Video mode only)\n + * After starting recording, encoded data frame will be stored in the location specified in MMCAM_TARGET_FILENAME. + * Some encoder or muxer require a certain type of finalizing such as adding some information to header. + * This function takes that roll. So if you don't call this function after recording, the result file may not be playable.\n + * After committing successfully, camcorder resumes displaying preview (video recording case). + * Because this is the function for saving the recording result, the operation is available + * only when the mode of camcorder is MM_CAMCORDER_MODE_AUDIO or MM_CAMCORDER_MODE_VIDEO. + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_cancel + * @pre Previous state of mm-camcorder should be MM_CAMCORDER_STATE_RECORDING + * @post Next state of mm-camcorder will be MM_CAMCORDER_STATE_PREPARE + * @remarks This function can take a few second when recording time is long. + * and if there are only quite few input buffer from video src or audio src, + * committing could be failed. + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean record_and_save_video_file() +{ + int err; + + // Start recording + err = mm_camcorder_record(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_record = %x\n", err); + return FALSE; + } + + // Wait while recording for test... + // In normal case, mm_camcorder_record() and mm_camcorder_commit() aren't called in the same function. + + // Save file + err = mm_camcorder_commit(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_commit = %x\n", err); + return FALSE; + } + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_commit(MMHandleType camcorder); + + +/** + * mm_camcorder_cancel:\n + * Stop recording and discard the result. (Audio/Video mode only) + * When a user want to finish recording without saving the result file, this function can be used. + * Like mm_camcorder_commit(), this function also stops recording, release related resources(like codec) ,and goes back to preview status. + * However, instead of saving file, this function unlinks(delete) the result.\n + * Because this is the function for canceling recording, the operation is available + * only when mode is MM_CAMCORDER_MODE_AUDIO or MM_CAMCORDER_MODE_VIDEO. + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_commit + * @pre Previous state of mm-camcorder should be MM_CAMCORDER_STATE_RECORDING + * @post Next state of mm-camcorder will be MM_CAMCORDER_STATE_PREPARE + * @remarks None + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean record_and_cancel_video_file() +{ + int err; + + // Start recording + err = mm_camcorder_record(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_record = %x\n", err); + return FALSE; + } + + // Wait while recording... + + // Cancel recording + err = mm_camcorder_cancel(hcam); + if (err < 0) { + printf("Fail to call mm_camcorder_cancel = %x\n", err); + return FALSE; + } + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_cancel(MMHandleType camcorder); + + +/** + * mm_camcorder_set_message_callback:\n + * Set callback for receiving messages from camcorder. Through this callback function, camcorder + * sends various message including status changes, asynchronous error, capturing, and limitations. + * One thing you have to know is that message callback is working on the main loop of application. + * So until releasing the main loop, message callback will not be called. + * + * @param[in] camcorder A handle of camcorder. + * @param[in] callback Function pointer of callback function. Please refer 'MMMessageCallback'. + * @param[in] user_data User parameter for passing to callback function. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see MMMessageCallback + * @pre None + * @post None + * @remarks registered 'callback' is called on main loop of the application. So until the main loop is released, 'callback' will not be called. + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean setting_msg_callback() +{ + //set callback + mm_camcorder_set_message_callback(hcam,(MMMessageCallback)msg_callback, (void*)hcam); + + return TRUE; +} + + + * @endcode + */ +int mm_camcorder_set_message_callback(MMHandleType camcorder, MMMessageCallback callback, void *user_data); + + +/** + * mm_camcorder_set_video_stream_callback:\n + * Set callback for user defined video stream callback function. + * Users can retrieve video frame using registered callback. + * The callback function holds the same buffer that will be drawed on the display device. + * So if an user change the buffer, it will be displayed on the device. + * + * @param[in] camcorder A handle of camcorder. + * @param[in] callback Function pointer of callback function. + * @param[in] user_data User parameter for passing to callback function. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_video_stream_callback + * @pre None + * @post None + * @remarks registered 'callback' is called on internal thread of camcorder. Regardless of the status of main loop, this function will be called. + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean setting_video_stream_callback() +{ + //set callback + mm_camcorder_set_video_stream_callback(hcam, (mm_camcorder_video_stream_callback)camcordertest_video_stream_cb, (void*)hcam); + + return TRUE; +} + * @endcode + */ +int mm_camcorder_set_video_stream_callback(MMHandleType camcorder, mm_camcorder_video_stream_callback callback, void *user_data); + + +/** + * mm_camcorder_set_video_capture_callback:\n + * Set callback for user defined video capture callback function. (Image mode only) + * mm_camcorder deliever captured image through the callback.\n + * Normally, this function provides main captured image and thumnail image. But depending on the environment, + * thumnail would not be available. Information related with main captured image and thumnail image is also included + * in the argument of the callback function. + * For more detail information of callback, please refer 'mm_camcorder_video_capture_callback'. + * + * @param[in] camcorder A handle of camcorder. + * @param[in] callback Function pointer of callback function. + * @param[in] user_data User parameter for passing to callback function. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_video_capture_callback + * @pre None + * @post None + * @remarks registered 'callback' is called on internal thread of camcorder. Regardless of the status of main loop, this function will be called. + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean setting_capture_callback() +{ + //set callback + mm_camcorder_set_video_capture_callback(hcam,(mm_camcorder_video_capture_callback)camcordertest_video_capture_cb, (void*)hcam); + + return TRUE; +} + * @endcode + */ +int mm_camcorder_set_video_capture_callback(MMHandleType camcorder, mm_camcorder_video_capture_callback callback, void *user_data); + + +/** + * mm_camcorder_set_audio_stream_callback:\n + * Set callback for user defined audio stream callback function. + * Users can retrieve audio data using registered callback. + * The callback function holds the same buffer that will be recorded. + * So if an user change the buffer, the result file will has the buffer. + * + * @param[in] camcorder A handle of camcorder. + * @param[in] callback Function pointer of callback function. + * @param[in] user_data User parameter for passing to callback function. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_audio_stream_callback + * @pre None + * @post None + * @remarks registered 'callback' is called on internal thread of camcorder. Regardless of the status of main loop, this function will be called. + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean setting_audio_stream_callback() +{ + //set callback + mm_camcorder_set_audio_stream_callback(hcam, (mm_camcorder_audio_stream_callback)camcordertest_audio_stream_cb, (void*)hcam); + + return TRUE; +} + * @endcode + */ +int mm_camcorder_set_audio_stream_callback(MMHandleType camcorder, mm_camcorder_audio_stream_callback callback, void *user_data); + + +/** + * mm_camcorder_get_state:\n + * Get the current state of camcorder. + * mm_camcorder is working on the base of its state. An user should check the state of mm_camcorder before calling its functions. + * If the handle is avaiable, user can retrieve the value. + * + * @param[in] camcorder A handle of camcorder. + * @param[out] state On return, it contains current state of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see MMCamcorderStateType + * @pre None + * @post None + * @remarks None + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean get_state_of_camcorder() +{ + MMCamcorderStateType state; + + //Get state of camcorder + mm_camcorder_get_state(hcam, &state); + printf("Current status is %d\n", state); + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_get_state(MMHandleType camcorder, MMCamcorderStateType *state); + + +/** + * mm_camcorder_get_attributes:\n + * Get attributes of camcorder with given attribute names. This function can get multiple attributes + * simultaneously. If one of attribute fails, this function will stop at the point. + * 'err_attr_name' let you know the name of the attribute. + * + * @param[in] camcorder Specifies the camcorder handle. + * @param[out] err_attr_name Specifies the name of attributes that made an error. If the function doesn't make an error, this will be null. @n + * Free this variable after using. + * @param[in] attribute_name attribute name that user want to get. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @pre None + * @post None + * @remarks You can retrieve multiple attributes at the same time. @n + * This function must finish with 'NULL' argument. @n + * ex) mm_camcorder_get_attributes(....... , NULL); + * @see mm_camcorder_set_attributes + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean getting_attribute() +{ + int err; + MMCamPreset cam_info; + char *err_attr_name = NULL; + void * hdisplay = NULL; + int hsize = 0; + + hdisplay = &ad.xid; //xid of xwindow. This value can be different depending on your environment. + hsize = sizeof(ad.xid); //size of xid structure. + + // camcorder attribute setting + err = mm_camcorder_get_attributes(hcamcorder, NULL, //The second is the argument for debugging. But you can skip this. + MMCAM_MODE, &mode, //You have to input a pointer instead of variable itself. + NULL); //mm_camcorder_set_attributes() should be finished with a NULL argument. + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_get_attributes(MMHandleType camcorder, char **err_attr_name, const char *attribute_name, ...) G_GNUC_NULL_TERMINATED; + + + +/** + * mm_camcorder_set_attributes:\n + * Set attributes of camcorder with given attribute names. This function can set multiple attributes + * simultaneously. If one of attribute fails, this function will stop at the point. + * 'err_attr_name' let you know the name of the attribute. + * + * @param[in] camcorder Specifies the camcorder handle. + * @param[out] err_attr_name Specifies the name of attributes that made an error. If the function doesn't make an error, this will be null. @n + * Free this variable after using. + * @param[in] attribute_name attribute name that user want to set. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @pre None + * @post None + * @remarks You can put multiple attributes to camcorder at the same time. @n + * This function must finish with 'NULL' argument. @n + * ex) mm_camcorder_set_attributes(....... , NULL); + * @see mm_camcorder_get_attributes + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean setting_attribute() +{ + int err; + MMCamPreset cam_info; + char *err_attr_name = NULL; + void * hdisplay = NULL; + int hsize = 0; + + hdisplay = &ad.xid; //xid of xwindow. This value can be different depending on your environment. + hsize = sizeof(ad.xid); //size of xid structure. + + // camcorder attribute setting + err = mm_camcorder_set_attributes((MMHandleType)hcam, &err_attr_name, //The second is the argument for debugging. + MMCAM_MODE, MM_CAMCORDER_MODE_IMAGE, + MMCAM_IMAGE_ENCODER, MM_IMAGE_CODEC_JPEG, + MMCAM_CAMERA_WIDTH, 640, + MMCAM_CAMERA_HEIGHT, 480, + MMCAM_CAMERA_FORMAT, MM_PIXEL_FORMAT_YUYV, + MMCAM_CAMERA_FPS, 30, + MMCAM_DISPLAY_ROTATION, MM_DISPLAY_ROTATION_270, + MMCAM_DISPLAY_HANDLE, (void*) hdisplay, hsize, //Beware some types require 'size' value, too. (STRING, DATA type attributes) + MMCAM_CAPTURE_FORMAT, MM_PIXEL_FORMAT_ENCODED, + MMCAM_CAPTURE_WIDTH, 640, + MMCAM_CAPTURE_HEIGHT, 480, + NULL); //mm_camcorder_set_attributes() should be finished with a NULL argument. + + if (err < 0) { + printf("Set attrs fail. (%s:%x)\n", err_attr_name, err); //When the function failed, 'err_attr_name' has the name of attr that made the error. + if (err_attr_name) { + free(err_attr_name); //Please free 'err_attr_name', after using the argument. + err_attr_name = NULL; + return FALSE; + } + } + + return TRUE; +} + * @endcode + */ +int mm_camcorder_set_attributes(MMHandleType camcorder, char **err_attr_name, const char *attribute_name, ...) G_GNUC_NULL_TERMINATED; + + +/** + * mm_camcorder_get_attribute_info:\n + * Get detail information of the attribute. To manager attributes, an user may want to know the exact character of the attribute, + * such as type, flag, and validity. This is the function to provide such information. + * Depending on the 'validity_type', validity union would be different. To know about the type of union, please refer 'MMCamAttrsInfo'. + * + * @param[in] camcorder Specifies the camcorder handle. + * @param[in] attribute_name attribute name that user want to get information. + * @param[out] info a structure that holds information related with the attribute. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @pre None + * @post None + * @remarks If the function succeeds, 'info' holds detail information about the attribute, such as type, + * flag, validity_type, validity_values, and default values. + * @see mm_camcorder_get_attributes, mm_camcorder_set_attributes + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean getting_info_from_attribute() +{ + MMCamAttrsInfo info; + int err; + + err = mm_camcorder_get_attribute_info(handle, MMCAM_CAPTURE_HEIGHT, &info); + if (err < 0) { + printf("Fail to call mm_camcorder_get_attribute_info()"); + return FALSE; + } + + //Now 'info' has many information about 'MMCAM_CAPTURE_HEIGHT' + + return TRUE; +} + * @endcode + */ +int mm_camcorder_get_attribute_info(MMHandleType camcorder, const char *attribute_name, MMCamAttrsInfo *info); + + +/** + * mm_camcorder_init_focusing:\n + * Initialize focusing. \n + * This function stops focusing action and adjust the camera lens to initial position. + * Some camera applciation requires to initialize its lens position after releasing half shutter. In that case, + * this should be a good choice. Comparing with mm_camcorder_stop_focusing, this function not only stops focusing, + * but also initialize the lens. Preview image might be out-focused after calling this function. + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @pre The status of camcorder should be MM_CAMCORDER_STATE_PREPARE, MM_CAMCORDER_STATE_RECORDING, or MM_CAMCORDER_STATE_PAUSED. + * @post None + * @remarks None + * @see mm_camcorder_start_focusing, mm_camcorder_stop_focusing + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean start_autofocus() +{ + int err; + char * err_attr_name = NULL; + + // Set focus mode to 'AUTO' and scan range to 'AF Normal'. + //You just need to set these values one time. After that, just call mm_camcorder_start_focusing(). + err = mm_camcorder_set_attributes((MMHandleType)hcam, &err_attr_name, + MMCAM_CAMERA_FOCUS_MODE, MM_CAMCORDER_FOCUS_MODE_AUTO, + MMCAM_CAMERA_AF_SCAN_RANGE, MM_CAMCORDER_AUTO_FOCUS_NORMAL, + NULL); + + if (err < 0) { + printf("Set attrs fail. (%s:%x)\n", err_attr_name, err); + if (err_attr_name) { + free(err_attr_name); + err_attr_name = NULL; + return FALSE; + } + } + + mm_camcorder_init_focusing(hcam); + mm_camcorder_start_focusing(hcam); + printf("Waiting for adjusting focus\n"); + + // Waiting for 'MM_MESSAGE_CAMCORDER_FOCUS_CHANGED' + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_init_focusing(MMHandleType camcorder); + + +/** + * mm_camcorder_start_focusing:\n + * Start focusing. \n + * This function command to start focusing opeartion. Because focusing operation depends on mechanic or electric module, + * it may take small amount of time. (For ex, 500ms ~ 3sec). \n + * This function works asynchronously. When an user call this function, it will return immediately. + * However, focusing operation will continue until it gets results. + * After finishing operation, you can get 'MM_MESSAGE_CAMCORDER_FOCUS_CHANGED' message. + * 'param.code' of the message structure describes the fucusing was success or not. + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @pre None + * @post None + * @remarks None + * @see mm_camcorder_init_focusing, mm_camcorder_stop_focusing + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean start_autofocus() +{ + int err; + char * err_attr_name = NULL; + + // Set focus mode to 'AUTO' and scan range to 'AF Normal'. + //You just need to set these values one time. After that, just call mm_camcorder_start_focusing(). + err = mm_camcorder_set_attributes((MMHandleType)hcam, &err_attr_name, + MMCAM_CAMERA_FOCUS_MODE, MM_CAMCORDER_FOCUS_MODE_AUTO, + MMCAM_CAMERA_AF_SCAN_RANGE, MM_CAMCORDER_AUTO_FOCUS_NORMAL, + NULL); + + if (err < 0) { + printf("Set attrs fail. (%s:%x)\n", err_attr_name, err); + if (err_attr_name) { + free(err_attr_name); + err_attr_name = NULL; + return FALSE; + } + } + + mm_camcorder_init_focusing(hcam); + mm_camcorder_start_focusing(hcam); + printf("Waiting for adjusting focus\n"); + + // Waiting for 'MM_MESSAGE_CAMCORDER_FOCUS_CHANGED' + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_start_focusing(MMHandleType camcorder); + + +/** + * mm_camcorder_stop_focusing:\n + * Stop focusing. This function halts focusing operation.\n + * This is the function to stop focusing in the middle of the operation. So if focusing is already finished or not started yet, + * this function will do nothing. + * + * @param[in] camcorder A handle of camcorder. + * @return This function returns zero(MM_ERROR_NONE) on success, or negative value with error code.\n + * Please refer 'mm_error.h' to know the exact meaning of the error. + * @see mm_camcorder_init_focusing, mm_camcorder_start_focusing + * @pre mm_camcorder_start_focusing() should be called before calling this function. + * @post None + * @remarks None + * @par example + * @code + +#include <mm_camcorder.h> + +gboolean stop_autofocus() +{ + int err; + + //Stop focusing + mm_camcorder_stop_focusing(hcam); + + return TRUE; +} + + * @endcode + */ +int mm_camcorder_stop_focusing(MMHandleType camcorder); + +/** + @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __MM_CAMCORDER_H__ */ diff --git a/src/include/mm_camcorder_attribute.h b/src/include/mm_camcorder_attribute.h new file mode 100644 index 0000000..8a499e5 --- /dev/null +++ b/src/include/mm_camcorder_attribute.h @@ -0,0 +1,365 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_CAMCORDER_ATTRIBUTE_H__ +#define __MM_CAMCORDER_ATTRIBUTE_H__ + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ +#include <mm_types.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| GLOBAL DEFINITIONS AND DECLARATIONS FOR CAMCORDER | +========================================================================================*/ +/* Disabled +#define GET_AND_STORE_ATTRS_AFTER_SCENE_MODE +*/ + +/*======================================================================================= +| MACRO DEFINITIONS | +========================================================================================*/ +/** + * Caster of attributes handle + */ +#define MMF_CAMCORDER_ATTRS(h) (((mmf_camcorder_t *)(h))->attributes) + +/*======================================================================================= +| ENUM DEFINITIONS | +========================================================================================*/ +/** + * Enumerations for camcorder attribute ID. + */ +typedef enum +{ + MM_CAM_MODE, /* 0 */ + MM_CAM_AUDIO_DEVICE, + MM_CAM_CAMERA_DEVICE, + MM_CAM_AUDIO_ENCODER, + MM_CAM_VIDEO_ENCODER, + MM_CAM_IMAGE_ENCODER, + MM_CAM_FILE_FORMAT, + MM_CAM_CAMERA_DEVICE_NAME, + MM_CAM_AUDIO_SAMPLERATE, + MM_CAM_AUDIO_FORMAT, + MM_CAM_AUDIO_CHANNEL, /* 10 */ + MM_CAM_AUDIO_VOLUME, + MM_CAM_AUDIO_INPUT_ROUTE, + MM_CAM_FILTER_SCENE_MODE, + MM_CAM_FILTER_BRIGHTNESS, + MM_CAM_FILTER_CONTRAST, + MM_CAM_FILTER_WB, + MM_CAM_FILTER_COLOR_TONE, + MM_CAM_FILTER_SATURATION, + MM_CAM_FILTER_HUE, + MM_CAM_FILTER_SHARPNESS, /* 20 */ + MM_CAM_CAMERA_FORMAT, + MM_CAM_CAMERA_SLOW_MOTION_FPS, + MM_CAM_CAMERA_FPS, + MM_CAM_CAMERA_WIDTH, + MM_CAM_CAMERA_HEIGHT, + 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, /* 30 */ + MM_CAM_CAMERA_EXPOSURE_VALUE, + MM_CAM_CAMERA_F_NUMBER, + MM_CAM_CAMERA_SHUTTER_SPEED, + MM_CAM_CAMERA_ISO, + MM_CAM_CAMERA_WDR, + MM_CAM_CAMERA_ANTI_HANDSHAKE, + MM_CAM_CAMERA_FPS_AUTO, + MM_CAM_CAMERA_HOLD_AF_AFTER_CAPTURING, + MM_CAM_CAMERA_DELAY_ATTR_SETTING, + MM_CAM_AUDIO_ENCODER_BITRATE, /* 40 */ + MM_CAM_VIDEO_ENCODER_BITRATE, + MM_CAM_IMAGE_ENCODER_QUALITY, + MM_CAM_CAPTURE_FORMAT, + MM_CAM_CAPTURE_WIDTH, + MM_CAM_CAPTURE_HEIGHT, + MM_CAM_CAPTURE_COUNT, + MM_CAM_CAPTURE_INTERVAL, + MM_CAM_CAPTURE_BREAK_CONTINUOUS_SHOT, + MM_CAM_DISPLAY_HANDLE, + MM_CAM_DISPLAY_DEVICE, /* 50 */ + MM_CAM_DISPLAY_SURFACE, + MM_CAM_DISPLAY_RECT_X, + MM_CAM_DISPLAY_RECT_Y, + MM_CAM_DISPLAY_RECT_WIDTH, + MM_CAM_DISPLAY_RECT_HEIGHT, + MM_CAM_DISPLAY_SOURCE_X, + MM_CAM_DISPLAY_SOURCE_Y, + MM_CAM_DISPLAY_SOURCE_WIDTH, + MM_CAM_DISPLAY_SOURCE_HEIGHT, + MM_CAM_DISPLAY_ROTATION, /* 60 */ + MM_CAM_DISPLAY_VISIBLE, + MM_CAM_DISPLAY_SCALE, + MM_CAM_DISPLAY_GEOMETRY_METHOD, + MM_CAM_TARGET_FILENAME, + MM_CAM_TARGET_MAX_SIZE, + MM_CAM_TARGET_TIME_LIMIT, + MM_CAM_TAG_ENABLE, + MM_CAM_TAG_IMAGE_DESCRIPTION, + MM_CAM_TAG_ORIENTATION, + MM_CAM_TAG_SOFTWARE, /* 70 */ + MM_CAM_TAG_LATITUDE, + MM_CAM_TAG_LONGITUDE, + MM_CAM_TAG_ALTITUDE, + MM_CAM_STROBE_CONTROL, + MM_CAM_STROBE_CAPABILITIES, + MM_CAM_STROBE_MODE, + MM_CAM_DETECT_MODE, + MM_CAM_DETECT_NUMBER, + MM_CAM_DETECT_FOCUS_SELECT, + MM_CAM_DETECT_SELECT_NUMBER, /* 80 */ + MM_CAM_DETECT_STATUS, + MM_CAM_CAPTURE_ZERO_SYSTEMLAG, + MM_CAM_CAMERA_AF_TOUCH_X, + MM_CAM_CAMERA_AF_TOUCH_Y, + MM_CAM_CAMERA_AF_TOUCH_WIDTH, + MM_CAM_CAMERA_AF_TOUCH_HEIGHT, + MM_CAM_CAMERA_FOCAL_LENGTH, + MM_CAM_RECOMMEND_PREVIEW_FORMAT_FOR_CAPTURE, + MM_CAM_RECOMMEND_PREVIEW_FORMAT_FOR_RECORDING, + MM_CAM_CAPTURE_THUMBNAIL, /* 90 */ + MM_CAM_TAG_GPS_ENABLE, + MM_CAM_TAG_GPS_TIME_STAMP, + MM_CAM_TAG_GPS_DATE_STAMP, + MM_CAM_TAG_GPS_PROCESSING_METHOD, + MM_CAM_CAMERA_ROTATION, + MM_CAM_ENABLE_CONVERTED_STREAM_CALLBACK, + MM_CAM_CAPTURED_SCREENNAIL, + MM_CAM_CAPTURE_SOUND_ENABLE, + MM_CAM_RECOMMEND_DISPLAY_ROTATION, + MM_CAM_CAMCORDER_ROTATION, /* 100 */ + MM_CAM_NUM +}MMCamcorderAttrsID; + +/*======================================================================================= +| TYPE DEFINITIONS | +========================================================================================*/ +typedef bool (*mmf_cam_commit_func_t)(MMHandleType handle, int attr_idx, const mmf_value_t *value); + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ +typedef struct { + MMCamcorderAttrsID attrid; + char *name; + int value_type; + int flags; + void* 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. */ + mmf_cam_commit_func_t attr_commit; +} mm_cam_attr_construct_info; + +/*======================================================================================= +| CONSTANT DEFINITIONS | +========================================================================================*/ + +/*======================================================================================= +| STATIC VARIABLES | +========================================================================================*/ + +/*======================================================================================= +| EXTERN GLOBAL VARIABLE | +========================================================================================*/ + +/*======================================================================================= +| GLOBAL FUNCTION PROTOTYPES | +========================================================================================*/ +/** + * This function allocates structure of attributes and sets initial values. + * + * @param[in] handle Handle of camcorder. + * @param[in] info Preset information of camcorder. + * @return This function returns allocated structure of attributes. + * @remarks + * @see _mmcamcorder_dealloc_attribute() + * + */ +MMHandleType _mmcamcorder_alloc_attribute(MMHandleType handle, MMCamPreset *info); + +/** + * This function release structure of attributes. + * + * @param[in] attrs Handle of camcorder attribute. + * @return void + * @remarks + * @see _mmcamcorder_alloc_attribute() + * + */ +void _mmcamcorder_dealloc_attribute(MMHandleType attrs); + +/** + * This is a meta function to get attributes of camcorder with given attribute names. + * + * @param[in] handle Handle of camcorder. + * @param[out] err_attr_name Specifies the name of attributes that made an error. If the function doesn't make an error, this will be null. + * @param[in] attribute_name attribute name that user want to get. + * @param[in] var_args Specifies variable arguments. + * @return This function returns MM_ERROR_NONE on Success, minus on Failure. + * @remarks You can retrieve multiple attributes at the same time. @n + * @see _mmcamcorder_set_attributes + */ +int _mmcamcorder_get_attributes(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list var_args); + + +/** + * This is a meta function to set attributes of camcorder with given attribute names. + * + * @param[in] handle Handle of camcorder. + * @param[out] err_attr_name Specifies the name of attributes that made an error. If the function doesn't make an error, this will be null. + * @param[in] attribute_name attribute name that user want to set. + * @param[in] var_args Specifies variable arguments. + * @return This function returns MM_ERROR_NONE on Success, minus on Failure. + * @remarks You can put multiple attributes to camcorder at the same time. @n + * @see _mmcamcorder_get_attributes + */ +int _mmcamcorder_set_attributes(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list var_args); + + +/** + * This is a meta function to get detail information of the attribute. + * + * @param[in] handle Handle of camcorder. + * @param[in] attr_name attribute name that user want to get information. + * @param[out] info a structure that holds information related with the attribute. + * @return This function returns MM_ERROR_NONE on Success, minus on Failure. + * @remarks If the function succeeds, 'info' holds detail information about the attribute, such as type, flag, validity_type, validity_values @n + * @see _mmcamcorder_get_attributes, _mmcamcorder_set_attributes + */ +int _mmcamcorder_get_attribute_info(MMHandleType handle, const char *attr_name, MMCamAttrsInfo *info); + +/*======================================================================================= +| CAMCORDER INTERNAL LOCAL | +========================================================================================*/ +/** + * A commit function to set camcorder attributes + * If the attribute needs actual setting, this function handles that activity. + * When application sets an attribute, setting function in MSL common calls this function. + * If this function fails, original value will not change. + * + * @param[in] attr_idx Attribute index of subcategory. + * @param[in] attr_name Attribute name. + * @param[in] value Handle of camcorder. + * @param[in] commit_param Allocation type of camcorder context. + * @return This function returns TRUE on success, or FALSE on failure + * @remarks + * @see + * + */ +bool _mmcamcorder_commit_camcorder_attrs(int attr_idx, const char *attr_name, const mmf_value_t *value, void *commit_param); + +/** + * A commit function to set videosource attribute + * If the attribute needs actual setting, this function handles that activity. + * When application sets an attribute, setting function in MSL common calls this function. + * If this function fails, original value will not change. + * + * @param[in] attr_idx Attribute index of subcategory. + * @param[in] attr_name Attribute name. + * @param[in] value Handle of camcorder. + * @param[in] commit_param Allocation type of camcorder context. + * @return This function returns TRUE on success, or FALSE on failure + * @remarks + * @see + * + */ +bool _mmcamcorder_commit_capture_width(MMHandleType handle, int attr_idx, const mmf_value_t *value); +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_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_camera_fps(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); +bool _mmcamcorder_commit_camera_focus_mode(MMHandleType handle, int attr_idx, const mmf_value_t *value); +bool _mmcamcorder_commit_camera_af_scan_range(MMHandleType handle, int attr_idx, const mmf_value_t *value); +bool _mmcamcorder_commit_camera_af_touch_area(MMHandleType handle, int attr_idx, const mmf_value_t *value); +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_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_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_rotation(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_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); + +/** + * This function initialize effect setting. + * + * @param[in] handle Handle of camcorder. + * @return bool + * @remarks + * @see + * + */ +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 + * + */ +int _mmcamcorder_lock_readonly_attributes(MMHandleType handle); + +/** + * This function disable pre-defined attributes. + * + * @param[in] handle Handle of camcorder. + * @return void + * @remarks + * @see + * + */ +int _mmcamcorder_set_disabled_attributes(MMHandleType handle); + +#ifdef __cplusplus +} +#endif + +#endif /* __MM_CAMCORDER_ATTRIBUTE_H__ */ diff --git a/src/include/mm_camcorder_audiorec.h b/src/include/mm_camcorder_audiorec.h new file mode 100644 index 0000000..eb10677 --- /dev/null +++ b/src/include/mm_camcorder_audiorec.h @@ -0,0 +1,103 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_CAMCORDER_AUDIOREC_H__ +#define __MM_CAMCORDER_AUDIOREC_H__ + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ +#include <mm_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ +/** + * MMCamcorder information for audio mode + */ +typedef struct { + int iSamplingRate; /**< Sampling rate */ + int iBitDepth; /**< Bit depth */ + int iChannels; /**< audio channels */ + char *filename; /**< recorded file name */ + gboolean b_commiting; /**< Is it commiting now? */ + gboolean bMuxing; /**< whether muxing */ + guint64 filesize; /**< current recorded file size */ + guint64 max_time; /**< max recording time */ + int fileformat; /**< recording file format */ +} _MMCamcorderAudioInfo; + +/*======================================================================================= +| GLOBAL FUNCTION PROTOTYPES | +========================================================================================*/ +/** + * This function creates audio pipeline for audio recording. + * + * @param[in] handle Handle of camcorder. + * @return This function returns MM_ERROR_NONE on success, or others on failure. + * @remarks + * @see _mmcamcorder_destroy_audio_pipeline() + * + */ +int _mmcamcorder_create_audio_pipeline(MMHandleType handle); + +/** + * This function destroy audio pipeline. + * + * @param[in] handle Handle of camcorder. + * @return void + * @remarks + * @see _mmcamcorder_destroy_pipeline() + * + */ +void _mmcamcorder_destroy_audio_pipeline(MMHandleType handle); + +/** + * This function runs command for audio recording. + * + * @param[in] handle Handle of camcorder. + * @param[in] command audio recording command. + * @return This function returns MM_ERROR_NONE on success, or others on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_audio_command(MMHandleType handle, int command); + +/** + * This function handles EOS(end of stream) when audio recording is finished. + * + * @param[in] handle Handle of camcorder. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_audio_handle_eos(MMHandleType handle); + +#ifdef __cplusplus +} +#endif +#endif /* __MM_CAMCORDER_AUDIOREC_H__ */ diff --git a/src/include/mm_camcorder_configure.h b/src/include/mm_camcorder_configure.h new file mode 100644 index 0000000..5f2abf3 --- /dev/null +++ b/src/include/mm_camcorder_configure.h @@ -0,0 +1,366 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_CAMCORDER_CONFIGURE_H__ +#define __MM_CAMCORDER_CONFIGURE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| MACRO DEFINITIONS | +========================================================================================*/ +#define SAFE_FREE(x) \ + if (x) {\ + g_free(x); \ + x = NULL; \ + } + +#define CONFIGURE_MAIN_FILE "mmfw_camcorder.ini" + +/*======================================================================================= +| ENUM DEFINITIONS | +========================================================================================*/ +enum ConfigureType { + CONFIGURE_TYPE_MAIN, + CONFIGURE_TYPE_CTRL, +}; + +enum ConfigureValueType { + CONFIGURE_VALUE_INT, + CONFIGURE_VALUE_INT_RANGE, + CONFIGURE_VALUE_INT_ARRAY, + CONFIGURE_VALUE_INT_PAIR_ARRAY, + CONFIGURE_VALUE_STRING, + CONFIGURE_VALUE_STRING_ARRAY, + CONFIGURE_VALUE_ELEMENT, + CONFIGURE_VALUE_NUM, +}; + +enum ConfigureCategoryMain { + CONFIGURE_CATEGORY_MAIN_GENERAL, + CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, + CONFIGURE_CATEGORY_MAIN_AUDIO_INPUT, + CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT, + CONFIGURE_CATEGORY_MAIN_CAPTURE, + CONFIGURE_CATEGORY_MAIN_RECORD, + CONFIGURE_CATEGORY_MAIN_VIDEO_ENCODER, + CONFIGURE_CATEGORY_MAIN_AUDIO_ENCODER, + CONFIGURE_CATEGORY_MAIN_IMAGE_ENCODER, + CONFIGURE_CATEGORY_MAIN_MUX, + CONFIGURE_CATEGORY_MAIN_NUM, +}; + +enum ConfigureCategoryCtrl { + CONFIGURE_CATEGORY_CTRL_CAMERA, + CONFIGURE_CATEGORY_CTRL_STROBE, + CONFIGURE_CATEGORY_CTRL_EFFECT, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + CONFIGURE_CATEGORY_CTRL_CAPTURE, + CONFIGURE_CATEGORY_CTRL_DETECT, + CONFIGURE_CATEGORY_CTRL_NUM, +}; + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ +typedef struct _type_int type_int; +struct _type_int { + char *name; + int value; +}; + +typedef struct _type_int_range type_int_range; +struct _type_int_range { + char *name; + int min; + int max; + int default_value; +}; + +typedef struct _type_int_array type_int_array; +struct _type_int_array { + char *name; + int *value; + int count; + int default_value; +}; + +typedef struct _type_int_pair_array type_int_pair_array; +struct _type_int_pair_array { + char *name; + int *value[2]; + int count; + int default_value[2]; +}; + +typedef struct _type_string type_string; +struct _type_string { + char *name; + char *value; +}; + +typedef struct _type_string_array type_string_array; +struct _type_string_array { + char *name; + char **value; + int count; + char *default_value; +}; + +typedef struct _type_element type_element; +struct _type_element { + char *name; + char *element_name; + type_int **value_int; + int count_int; + type_string **value_string; + int count_string; +}; + +typedef struct _conf_info conf_info; +struct _conf_info { + int count; + void **detail_info; +}; + +typedef struct _conf_info_table conf_info_table; +struct _conf_info_table { + char *name; + int value_type; + union { + int value_int; + char *value_string; + type_element *value_element; + }; +}; + +typedef struct _camera_conf camera_conf; +struct _camera_conf { + int type; + conf_info **info; +}; + +/*======================================================================================= +| MODULE FUNCTION PROTOTYPES | +========================================================================================*/ +/* User function */ +/** + * This function creates configure info structure from ini file. + * + * @param[in] type configure type(MAIN or CTRL). + * @param[in] ConfFile ini file path. + * @param[out] configure_info configure structure to be got. + * @return This function returns MM_ERROR_NONE on success, or others on failure. + * @remarks + * @see _mmcamcorder_conf_release_info() + * + */ +int _mmcamcorder_conf_get_info(int type, char *ConfFile, camera_conf **configure_info); + +/** + * This function releases configure info. + * + * @param[in] configure_info configure structure to be released. + * @return void + * @remarks + * @see _mmcamcorder_conf_get_info() + * + */ +void _mmcamcorder_conf_release_info(camera_conf **configure_info); + +/** + * This function gets integer type value from configure info. + * + * @param[in] configure_info configure structure created by _mmcamcorder_conf_get_info. + * @param[in] category configure category. + * @param[in] name detail name in category. + * @param[out] value value to be got. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_conf_get_value_int(camera_conf *configure_info, int category, char *name, int *value); + +/** + * This function gets integer-range type value from configure info. + * + * @param[in] configure_info configure structure created by _mmcamcorder_conf_get_info. + * @param[in] category configure category. + * @param[in] name detail name in category. + * @param[out] value value to be got. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_conf_get_value_int_range(camera_conf *configure_info, int category, char *name, type_int_range **value); + +/** + * This function gets integer-array type value from configure info. + * + * @param[in] configure_info configure structure created by _mmcamcorder_conf_get_info. + * @param[in] category configure category. + * @param[in] name detail name in category. + * @param[out] value value to be got. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_conf_get_value_int_array(camera_conf *configure_info, int category, char *name, type_int_array **value); + +/** + * This function gets integer-pair-array type value from configure info. + * + * @param[in] configure_info configure structure created by _mmcamcorder_conf_get_info. + * @param[in] category configure category. + * @param[in] name detail name in category. + * @param[out] value value to be got. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_conf_get_value_int_pair_array(camera_conf *configure_info, int category, char *name, type_int_pair_array **value); + +/** + * This function gets string type value from configure info. + * + * @param[in] configure_info configure structure created by _mmcamcorder_conf_get_info. + * @param[in] category configure category. + * @param[in] name detail name in category. + * @param[out] value value to be got. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_conf_get_value_string(camera_conf *configure_info, int category, char *name, char **value); + +/** + * This function gets string-array type value from configure info. + * + * @param[in] configure_info configure structure created by _mmcamcorder_conf_get_info. + * @param[in] category configure category. + * @param[in] name detail name in category. + * @param[out] value value to be got. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_conf_get_value_string_array(camera_conf *configure_info, int category, char *name, type_string_array **value); + +/** + * This function gets element info from configure info. + * + * @param[in] configure_info configure structure created by _mmcamcorder_conf_get_info. + * @param[in] category configure category. + * @param[in] name detail name in category. + * @param[out] element element info to be got. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_conf_get_element(camera_conf *configure_info, int category, char *name, type_element **element); + +/** + * This function gets element name from element info. + * + * @param[in] element element info. + * @param[out] name element name to be got. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_conf_get_value_element_name(type_element *element, char **value); + +/** + * This function gets integer value of element's named property from element info. + * + * @param[in] element element info. + * @param[in] name property name. + * @param[out] value value to be got. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_conf_get_value_element_int(type_element *element, char *name, int *value); + +/** + * This function gets string value of element's named property from element info. + * + * @param[in] element element info. + * @param[in] name property name. + * @param[out] value value to be got. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_conf_get_value_element_string(type_element *element, char *name, char **value); + +/** + * This function sets all property of element info. + * + * @param[in] gst gstreamer element. + * @param[in] element element info. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +int _mmcamcorder_conf_set_value_element_property(GstElement *gst, type_element *element); + +/** + * This function prints all values of configure info. + * + * @param[in] configure_info configure structure created by _mmcamcorder_conf_get_info. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see + * + */ +void _mmcamcorder_conf_print_info(camera_conf **configure_info); + +type_element *_mmcamcorder_get_type_element(MMHandleType handle, int type); +int _mmcamcorder_get_available_format(MMHandleType handle, int conf_category, int **format); + +/* Internal function */ +void _mmcamcorder_conf_init(int type, camera_conf **configure_info); +int _mmcamcorder_conf_parse_info(int type, FILE *fd, camera_conf **configure_info); +int _mmcamcorder_conf_get_value_type(int type, int category, char *name, int *value_type); +int _mmcamcorder_conf_add_info(int type, conf_info **info, char **buffer_details, int category, int count_details); +int _mmcamcorder_conf_get_default_value_int(int type, int category, char *name, int *value); +int _mmcamcorder_conf_get_default_value_string(int type, int category, char *name, char **value); +int _mmcamcorder_conf_get_default_element(int type, int category, char *name, type_element **element); +int _mmcamcorder_conf_get_category_size(int type, int category, int *size); + +#ifdef __cplusplus +} +#endif +#endif /* __MM_CAMCORDER_CONFIGURE_H__ */ diff --git a/src/include/mm_camcorder_exifdef.h b/src/include/mm_camcorder_exifdef.h new file mode 100644 index 0000000..b27db16 --- /dev/null +++ b/src/include/mm_camcorder_exifdef.h @@ -0,0 +1,99 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*! \brief The definitions for exif information + + Some of the EXIF informations aren't needed to be changed within a + session. For example, everytime still-image taken, [Maker name] field + or [Model name] field always be same in a device, while [Datetime] or + [Exposure value] isn't. This definitions are for the un-changeable + values. +*/ + +/*! + \def MM_MAKER_NAME + Shows manufacturer of digicam, "Samsung". +*/ +/*! + \def MM_MODEL_NAME + Shows model number of digicam. +*/ +/*! + \def MM_SOFTWARE_NAME + Shows firmware(internal software of digicam) version number. +*/ +/*! + \def MM_EXIF_ORIENTATION + The orientation of the camera relative to the scene, when the image + was captured. The start point of stored data is, '1' means upper left, + '3' lower right, '6' upper right, '8' lower left, '9' undefined. +*/ +/*! + \def MM_EXIF_YCBCRPOSITIONING + When image format is YCbCr and uses 'Subsampling'(cropping of chroma + data, all the digicam do that), this value defines the chroma sample + point of subsampled pixel array. '1' means the center of pixel array, + '2' means the datum point(0,0). +*/ +/*! + \def MM_COMPONENTS_CONFIGURATION + Order arrangement of pixel. +*/ +/*! + \def MM_EXIF_COLORSPACE + Color space of stilled JPEG image. +*/ +/*! + \def MM_EXIF_CUSTOMRENDERED + The method of compressed jpeg image rendering. +*/ + +#ifndef __MM_EXIFDEF_H__ +#define __MM_EXIFDEF_H__ + +/*======================================================================================= +| MACRO DEFINITIONS | +========================================================================================*/ +#define MM_EXIF_VERSION (0x00000030) | (0x00000032 << 8) | (0x00000032 << 16) | (0x00000030 << 24) /* ASCII 0220 */ +#define MM_MAKER_NAME "SAMSUNG" +#define MM_USER_COMMENT "User comment " +#define MM_SOFTWARE_NAME "Camera Application " +#define MM_EXIF_ORIENTATION 1 /* upper-top */ +#define MM_EXIF_YCBCRPOSITIONING 1 /* centered */ +#define MM_COMPONENTS_CONFIGURATION (0x00000000) | (0x00000001) | (0x00000002 << 8) | (0x00000003 << 16) /* Y Cb Cr - */ +#define MM_EXIF_COLORSPACE 1 /* sRGB */ +#define MM_EXIF_CUSTOMRENDERED 0 /* Normal rendered */ +#define MM_EXPOSURE_PROGRAM 3 /* 0~8 0 : not defined */ +#define MM_METERING_MODE 0 /* 0~6 0: unkown */ +#define MM_SENSING_MODE 1 /* 1~8 1: not defined */ +#define MM_FOCAL_LENGTH 450 +#define MM_FOCAL_LENGTH_35MMFILM 0 /*unknown */ +#define MM_GAIN_CONTROL 0 /* 0~4 0 none */ +#define MM_FILE_SOURCE 3 /* 3: DSC */ +#define MM_SCENE_TYPE 1 /* 1 DSC : a directly photographed image */ +#define MM_EXPOSURE_MODE 0 /*0~2 0 : auto exposure */ +#define MM_VALUE_NORMAL 0 /* 1 DSC : a directly photographed image */ +#define MM_VALUE_LOW 1 /* 1 DSC : a directly photographed image */ +#define MM_VALUE_HARD 2 /* 1 DSC : a directly photographed image */ +#define MM_SUBJECT_DISTANCE_RANGE 0 /* 0~3. 0 : unknown */ +#define INVALID_GPS_VALUE 1000 + +#endif /* __MM_EXIFDEF_H__ */ diff --git a/src/include/mm_camcorder_exifinfo.h b/src/include/mm_camcorder_exifinfo.h new file mode 100644 index 0000000..3356122 --- /dev/null +++ b/src/include/mm_camcorder_exifinfo.h @@ -0,0 +1,161 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef _MM_EXIFINFO_H_ +#define _MM_EXIFINFO_H_ + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ +#include <libexif/exif-ifd.h> +#include <libexif/exif-tag.h> +#include <libexif/exif-format.h> +#include <libexif/exif-data.h> +#include <libexif/mnote-samsung-tag.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ +/** + * Structure for exif data infomation. + */ +typedef struct { + void *data; /**< saved exif data*/ + unsigned int size; /**< size of saved exif data*/ +} mm_exif_info_t; + +/*======================================================================================= +| GLOBAL FUNCTION PROTOTYPES | +========================================================================================*/ +/** + * Create exif info + * @param[in] info exif info. + * @return return int. + */ +int mm_exif_create_exif_info(mm_exif_info_t **info); + +/** + * Destroy exif info + * @param[in] info exif info. + * @return void + */ +void mm_exif_destory_exif_info(mm_exif_info_t *info); + +/** + * get exif data information from data buffer + * @param[in] info exif info. + * @return return ExifData. + */ +ExifData *mm_exif_get_exif_data_from_data(mm_exif_info_t *info); + +/** + * get exif data information from exif info + * @param[in] info exif info. + * @param[out] Exif tag . + * @return return int. + */ +ExifData *mm_exif_get_exif_from_info(mm_exif_info_t *info); + +/** + * Write exif data information into exif info + * @param[in] info exif info. + * @param[in] Exif tag . + * @param[in] Exif tag value to be written. + * @return return int. + */ +int mm_exif_set_exif_to_info(mm_exif_info_t *info, ExifData *exif); + +/** + * add one tag information into exif + * @param[in] info exif info. + * @param[in] Exif tag . + * @param[in] tag content category. + * @param[in] tag format. + * @param[in] the number of the component . + * @param[in] the pointer of the tag data. + * @return return int. + */ +int mm_exif_set_add_entry(ExifData *exif, ExifIfd ifd, ExifTag tag, + ExifFormat format, unsigned long components, + unsigned char *data); + +/** + * Write thumbnail data into exif info. + * @param[in] info exif info. + * @param[in] thumbnail image thumbnail data. + * @param[in] width width of thumbnail image. + * @param[in] height height of thumbnail image. + * @param[in] length length of thumbnail image. + * @return return int. + */ +int mm_exif_add_thumbnail_info(mm_exif_info_t *info, void *thumbnail, + int width, int height, int len); + +/** + * create ExifMnoteDataSamsung and set up related function pointers + * @param[in/out] info exif info. + * @return return int. + */ +int mm_exif_mnote_create(ExifData *exif); + +/** + * add one Samsung maker note tag information into exif + * @param[in/out] info exif info. + * @param[in] Samsung maker note tag . + * @param[in] tag index. + * @param[in] sub tag index 1. + * @param[in] sub tag index 2. + * @return return int. + */ +int mm_exif_mnote_set_add_entry(ExifData *exif, MnoteSamsungTag tag, + int index, int subindex1, int subindex2); + +/** + * Write exif info into a jpeg image and then save as a jpeg file. + * @param[in/out] filename jpeg filename. + * @param[in] info exif info. + * @param[in] jpeg jpeg image data. + * @param[in] length length of jpeg image. + * @return return int. + */ +int mm_exif_write_exif_jpeg_to_file(char *filename, mm_exif_info_t *info, void *jpeg, int jpeg_len); + +/** + * Write exif info into a jpeg memory buffer. + * @param[in/out] mem image data buffer. + * @param[in/out] length image data length. + * @param[in] info exif info. + * @param[in] jpeg jpeg image data. + * @param[in] length length of jpeg image. + * @return return int. + */ +int mm_exif_write_exif_jpeg_to_memory(void **mem, unsigned int *length, + mm_exif_info_t *info, void *jpeg, + unsigned int jpeg_len); + +#ifdef __cplusplus +} +#endif +#endif /*_MM_EXIFINFO_H_*/ diff --git a/src/include/mm_camcorder_gstcommon.h b/src/include/mm_camcorder_gstcommon.h new file mode 100644 index 0000000..7ba1605 --- /dev/null +++ b/src/include/mm_camcorder_gstcommon.h @@ -0,0 +1,183 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_CAMCORDER_GSTCOMMON_H__ +#define __MM_CAMCORDER_GSTCOMMON_H__ + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ +#include <mm_types.h> +#include "mm_camcorder_configure.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| GLOBAL DEFINITIONS AND DECLARATIONS FOR CAMCORDER | +========================================================================================*/ + +/*======================================================================================= +| MACRO DEFINITIONS | +========================================================================================*/ + +/*======================================================================================= +| ENUM DEFINITIONS | +========================================================================================*/ +/** +* Enumerations for AMR bitrate +*/ +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 */ + MM_CAMCORDER_MR67, /**< MR67 : 6.70 kbit/s */ + MM_CAMCORDER_MR74, /**< MR74 : 7.40 kbit/s */ + MM_CAMCORDER_MR795, /**< MR795 : 7.95 kbit/s */ + MM_CAMCORDER_MR102, /**< MR102 : 10.20 kbit/s */ + MM_CAMCORDER_MR122, /**< MR122 : 12.20 kbit/s */ + MM_CAMCORDER_MRDTX /**< MRDTX */ +} MMCamcorderAMRBitRate; + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ +/** + * Element name table. + * @note if name is NULL, not supported. + */ +typedef struct { + unsigned int prof_id; /**< id of mmcamcorder_profile_attrs_id */ + unsigned int id; /**< id of value id */ + char *name; /**< gstreamer element name*/ +} _MMCamcorderElementName; + +/*======================================================================================= +| CONSTANT DEFINITIONS | +========================================================================================*/ + +/*======================================================================================= +| STATIC VARIABLES | +========================================================================================*/ + +/*======================================================================================= +| EXTERN GLOBAL VARIABLE | +========================================================================================*/ + +/*======================================================================================= +| GLOBAL FUNCTION PROTOTYPES | +========================================================================================*/ +/* create bin */ +/** + * This function creates bin of video source. + * Basically, main pipeline of camcorder is composed of several bin(a bundle + * of elements). Each bin operates its own function. This bin has a roll + * inputting video data from camera. + * + * @param[in] handle Handle of camcorder context. + * @return This function returns MM_ERROR_NONE on success, or the other values on error. + * @remarks + * @see __mmcamcorder_create_preview_pipeline() + */ +int _mmcamcorder_create_videosrc_bin(MMHandleType handle); + +/** + * This function creates bin of audio source. + * Basically, main pipeline of camcorder is composed of several bin(a bundle + * of elements). Each bin operates its own function. This bin has a roll + * inputting audio data from audio source(such as mike). + * + * @param[in] handle Handle of camcorder context. + * @return This function returns MM_ERROR_NONE on success, or the other values on error. + * @remarks + * @see __mmcamcorder_create_preview_pipeline() + */ +int _mmcamcorder_create_audiosrc_bin(MMHandleType handle); + +/** + * This function creates bin of video sink. + * Basically, main pipeline of camcorder is composed of several bin(a bundle + * of elements). Each bin operates its own function. This bin has a roll + * transferring video data to frame buffer. + * + * @param[in] handle Handle of camcorder context. + * @return This function returns MM_ERROR_NONE on success, or the other values on error. + * @remarks + * @see __mmcamcorder_create_preview_pipeline() + */ +int _mmcamcorder_create_videosink_bin(MMHandleType handle); + +/** + * This function creates outputsink bin. + * + * @param[in] handle Handle of camcorder context. + * @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); + +/** + * This function creates bin of still shot sink. + * Basically, main pipeline of camcorder is composed of several bin(a bundle + * of elements). Each bin operates its own function. This bin has a roll + * writting image file with video stream. + * + * @param[in] handle Handle of camcorder context. + * @return This function returns MM_ERROR_NONE on success, or the other values on error. + * @remarks + * @see __mmcamcorder_create_preview_pipeline() + */ +int _mmcamcorder_create_stillshotsink_bin(MMHandleType handle); + +/** + * This function creates main pipeline of camcorder. + * Basically, main pipeline of camcorder is composed of several bin(a bundle + * of elements). And if the appilcation wants to make pipeline working, the + * application assemble bin that is proper to that task. + * When this function is called, bins that is needed for preview will be composed. + * + * @param[in] handle Handle of camcorder context. + * @return This function returns MM_ERROR_NONE on success, or the other values on error. + * @remarks + * @see _mmcamcorder_create_pipeline() + */ +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); +int _mmcamcorder_vframe_stablize(MMHandleType handle); +gboolean _mmcamcorder_get_device_info(MMHandleType handle); +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); + +#ifdef __cplusplus +} +#endif +#endif /* __MM_CAMCORDER_GSTCOMMON_H__ */ diff --git a/src/include/mm_camcorder_internal.h b/src/include/mm_camcorder_internal.h new file mode 100644 index 0000000..c887273 --- /dev/null +++ b/src/include/mm_camcorder_internal.h @@ -0,0 +1,1072 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_CAMCORDER_INTERNAL_H__ +#define __MM_CAMCORDER_INTERNAL_H__ + + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ +#include <malloc.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> +#include <semaphore.h> + +#include <mm_types.h> +#include <mm_attrs.h> +#include <mm_attrs_private.h> +#include <mm_message.h> +#include <mm_ta.h> +#include <sndfile.h> + +#include "mm_camcorder.h" +#include "mm_debug.h" + +/* camcorder sub module */ +#include "mm_camcorder_attribute.h" +#include "mm_camcorder_platform.h" +#include "mm_camcorder_stillshot.h" +#include "mm_camcorder_videorec.h" +#include "mm_camcorder_audiorec.h" +#include "mm_camcorder_gstcommon.h" +#include "mm_camcorder_exifinfo.h" +#include "mm_camcorder_util.h" +#include "mm_camcorder_configure.h" +#include "mm_camcorder_sound.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| MACRO DEFINITIONS | +========================================================================================*/ +#define _mmcam_dbg_verb(fmt, args...) mmf_debug(MMF_DEBUG_VERBOSE,"[%05d][%s]: " fmt "\n", __LINE__, __func__, ##args); +#define _mmcam_dbg_log(fmt, args...) mmf_debug(MMF_DEBUG_LOG,"[%05d][%s]: " fmt "\n", __LINE__, __func__, ##args); +#define _mmcam_dbg_warn(fmt, args...) mmf_debug(MMF_DEBUG_WARNING,"[%05d][%s]: " fmt "\n", __LINE__, __func__, ##args); +#define _mmcam_dbg_err(fmt, args...) mmf_debug(MMF_DEBUG_ERROR,"[%05d][%s]: " fmt "\n", __LINE__, __func__, ##args); +#define _mmcam_dbg_crit(fmt, args...) mmf_debug(MMF_DEBUG_CRITICAL,"[%05d][%s]: " fmt "\n", __LINE__, __func__, ##args); + +/** + * Macro for checking validity and debugging + */ +#define mmf_return_if_fail( expr ) \ + if( expr ){} \ + else \ + { \ + _mmcam_dbg_err( "failed [%s]", #expr); \ + return; \ + }; + +/** + * Macro for checking validity and debugging + */ +#define mmf_return_val_if_fail( expr, val ) \ + if( expr ){} \ + else \ + { \ + _mmcam_dbg_err("failed [%s]", #expr); \ + return( val ); \ + }; + +#ifndef ARRAY_SIZE +/** + * Macro for getting array size + */ +#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0])) +#endif + +/* gstreamer element creation macro */ +#define _MMCAMCORDER_PIPELINE_MAKE(sub_context, eid, name /*char* */, err) \ + if (sub_context->element[eid].gst != NULL) { \ + _mmcam_dbg_err("The element(Pipeline) 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_pipeline_new(name); \ + if (sub_context->element[eid].gst == NULL) { \ + _mmcam_dbg_err("Pipeline creation fail. element_id=[%d], name=[%s]", eid, name); \ + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; \ + goto pipeline_creation_error; \ + } else { \ + g_object_weak_ref(G_OBJECT(sub_context->element[eid].gst), (GWeakNotify)_mmcamcorder_element_release_noti, sub_context); \ + } + +#define _MMCAMCORDER_BIN_MAKE(sub_context, eid, name /*char* */, err) \ + if (sub_context->element[eid].gst != NULL) { \ + _mmcam_dbg_err("The element(Bin) 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_bin_new(name); \ + if (sub_context->element[eid].gst == NULL) { \ + _mmcam_dbg_err("Bin creation fail. element_id=[%d], name=[%s]\n", eid, name); \ + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; \ + goto pipeline_creation_error; \ + } else { \ + g_object_weak_ref(G_OBJECT(sub_context->element[eid].gst), (GWeakNotify)_mmcamcorder_element_release_noti, sub_context); \ + } + +#define _MMCAMCORDER_ELEMENT_MAKE(sub_context, eid, name /*char* */, nickname /*char* */, elist, err) \ + 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].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 { \ + 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); \ + gst_object_unref(sub_context->element[eid].gst); \ + } \ + sub_context->element[eid].id = eid; \ + g_object_get(G_OBJECT(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst), name, &(sc->element[eid].gst), NULL); \ + if (sub_context->element[eid].gst == NULL) { \ + _mmcam_dbg_err("Element get fail. element_id=[%d], name=[%s]", eid, name); \ + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; \ + goto pipeline_creation_error; \ + } else{ \ + gst_object_unref(sub_context->element[eid].gst); \ + g_object_weak_ref(G_OBJECT(sub_context->element[eid].gst), (GWeakNotify)_mmcamcorder_element_release_noti, sub_context); \ + } + +/* GStreamer element remove macro */ +#define _MMCAMCORDER_ELEMENT_REMOVE(sub_context, eid) \ + if (sub_context->element[eid].gst != NULL) { \ + gst_object_unref(sub_context->element[eid].gst); \ + } + +#define _MM_GST_ELEMENT_LINK_MANY gst_element_link_many +#define _MM_GST_ELEMENT_LINK gst_element_link +#define _MM_GST_PAD_LINK gst_pad_link + +#define _MM_GST_PAD_LINK_UNREF( srcpad, sinkpad, err, if_fail_goto ) \ +{ \ + GstPadLinkReturn ret = _MM_GST_PAD_LINK( srcpad, sinkpad ); \ + gst_object_unref( srcpad ); srcpad = NULL; \ + gst_object_unref( sinkpad ); sinkpad = NULL; \ + if (ret != GST_PAD_LINK_OK) { \ + err = MM_ERROR_CAMCORDER_GST_LINK; \ + goto if_fail_goto; \ + } \ +} + +#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; + +#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 */ + +/** + * Total level count of manual focus */ +#define _MMFCAMCORDER_FOCUS_TOTAL_LEVEL 8 + +/** + * File name length limit + */ +#define _MMCamcorder_FILENAME_LEN (512) + +/** + * Minimum integer value + */ +#define _MMCAMCORDER_MIN_INT (-2147483648) + +/** + * Maximum integer value + */ +#define _MMCAMCORDER_MAX_INT (2147483647) + +/** + * Audio timestamp margin (msec) + */ +#define _MMCAMCORDER_AUDIO_TIME_MARGIN (300) + +/** + * Functions related with LOCK and WAIT + */ +#define _MMCAMCORDER_CAST_MTSAFE(handle) (((mmf_camcorder_t*)handle)->mtsafe) + +#define _MMCAMCORDER_GET_LOCK(handle) (_MMCAMCORDER_CAST_MTSAFE(handle).lock) +#define _MMCAMCORDER_LOCK(handle) g_mutex_lock(_MMCAMCORDER_GET_LOCK(handle)) +#define _MMCAMCORDER_TRYLOCK(handle) g_mutex_trylock(_MMCAMCORDER_GET_LOCK(handle)) +#define _MMCAMCORDER_UNLOCK(handle) g_mutex_unlock(_MMCAMCORDER_GET_LOCK(handle)) + +#define _MMCAMCORDER_GET_COND(handle) (_MMCAMCORDER_CAST_MTSAFE(handle).cond) +#define _MMCAMCORDER_WAIT(handle) g_cond_wait (_MMCAMCORDER_GET_COND(handle), _MMCAMCORDER_GET_LOCK(handle)) +#define _MMCAMCORDER_TIMED_WAIT(handle, timeval) g_cond_timed_wait (_MMCAMCORDER_GET_COND(handle), _MMCAMCORDER_GET_LOCK(handle),timeval) + +#define _MMCAMCORDER_SIGNAL(handle) g_cond_signal (_MMCAMCORDER_GET_COND(handle)); +#define _MMCAMCORDER_BROADCAST(handle) g_cond_broadcast (_MMCAMCORDER_GET_COND(handle)); + +/* for command */ +#define _MMCAMCORDER_GET_CMD_LOCK(handle) (_MMCAMCORDER_CAST_MTSAFE(handle).cmd_lock) +#define _MMCAMCORDER_LOCK_CMD(handle) g_mutex_lock(_MMCAMCORDER_GET_CMD_LOCK(handle)) +#define _MMCAMCORDER_TRYLOCK_CMD(handle) g_mutex_trylock(_MMCAMCORDER_GET_CMD_LOCK(handle)) +#define _MMCAMCORDER_UNLOCK_CMD(handle) g_mutex_unlock(_MMCAMCORDER_GET_CMD_LOCK(handle)) + +/* for state change */ +#define _MMCAMCORDER_GET_STATE_LOCK(handle) (_MMCAMCORDER_CAST_MTSAFE(handle).state_lock) +#define _MMCAMCORDER_LOCK_STATE(handle) g_mutex_lock(_MMCAMCORDER_GET_STATE_LOCK(handle)) +#define _MMCAMCORDER_TRYLOCK_STATE(handle) g_mutex_trylock(_MMCAMCORDER_GET_STATE_LOCK(handle)) +#define _MMCAMCORDER_UNLOCK_STATE(handle) g_mutex_unlock(_MMCAMCORDER_GET_STATE_LOCK(handle)) + +/* for gstreamer state change */ +#define _MMCAMCORDER_GET_GST_STATE_LOCK(handle) (_MMCAMCORDER_CAST_MTSAFE(handle).gst_state_lock) +#define _MMCAMCORDER_LOCK_GST_STATE(handle) g_mutex_lock(_MMCAMCORDER_GET_GST_STATE_LOCK(handle)) +#define _MMCAMCORDER_TRYLOCK_GST_STATE(handle) g_mutex_trylock(_MMCAMCORDER_GET_GST_STATE_LOCK(handle)) +#define _MMCAMCORDER_UNLOCK_GST_STATE(handle) g_mutex_unlock(_MMCAMCORDER_GET_GST_STATE_LOCK(handle)) + +/* for setting/calling callback */ +#define _MMCAMCORDER_GET_MESSAGE_CALLBACK_LOCK(handle) (_MMCAMCORDER_CAST_MTSAFE(handle).message_cb_lock) +#define _MMCAMCORDER_LOCK_MESSAGE_CALLBACK(handle) g_mutex_lock(_MMCAMCORDER_GET_MESSAGE_CALLBACK_LOCK(handle)) +#define _MMCAMCORDER_TRYLOCK_MESSAGE_CALLBACK(handle) g_mutex_trylock(_MMCAMCORDER_GET_MESSAGE_CALLBACK_LOCK(handle)) +#define _MMCAMCORDER_UNLOCK_MESSAGE_CALLBACK(handle) g_mutex_unlock(_MMCAMCORDER_GET_MESSAGE_CALLBACK_LOCK(handle)) + +#define _MMCAMCORDER_GET_VCAPTURE_CALLBACK_LOCK(handle) (_MMCAMCORDER_CAST_MTSAFE(handle).vcapture_cb_lock) +#define _MMCAMCORDER_LOCK_VCAPTURE_CALLBACK(handle) g_mutex_lock(_MMCAMCORDER_GET_VCAPTURE_CALLBACK_LOCK(handle)) +#define _MMCAMCORDER_TRYLOCK_VCAPTURE_CALLBACK(handle) g_mutex_trylock(_MMCAMCORDER_GET_VCAPTURE_CALLBACK_LOCK(handle)) +#define _MMCAMCORDER_UNLOCK_VCAPTURE_CALLBACK(handle) g_mutex_unlock(_MMCAMCORDER_GET_VCAPTURE_CALLBACK_LOCK(handle)) + +#define _MMCAMCORDER_GET_VSTREAM_CALLBACK_LOCK(handle) (_MMCAMCORDER_CAST_MTSAFE(handle).vstream_cb_lock) +#define _MMCAMCORDER_LOCK_VSTREAM_CALLBACK(handle) g_mutex_lock(_MMCAMCORDER_GET_VSTREAM_CALLBACK_LOCK(handle)) +#define _MMCAMCORDER_TRYLOCK_VSTREAM_CALLBACK(handle) g_mutex_trylock(_MMCAMCORDER_GET_VSTREAM_CALLBACK_LOCK(handle)) +#define _MMCAMCORDER_UNLOCK_VSTREAM_CALLBACK(handle) g_mutex_unlock(_MMCAMCORDER_GET_VSTREAM_CALLBACK_LOCK(handle)) + +#define _MMCAMCORDER_GET_ASTREAM_CALLBACK_LOCK(handle) (_MMCAMCORDER_CAST_MTSAFE(handle).astream_cb_lock) +#define _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(handle) g_mutex_lock(_MMCAMCORDER_GET_ASTREAM_CALLBACK_LOCK(handle)) +#define _MMCAMCORDER_TRYLOCK_ASTREAM_CALLBACK(handle) g_mutex_trylock(_MMCAMCORDER_GET_ASTREAM_CALLBACK_LOCK(handle)) +#define _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(handle) g_mutex_unlock(_MMCAMCORDER_GET_ASTREAM_CALLBACK_LOCK(handle)) + +/** + * Caster of main handle (camcorder) + */ +#define MMF_CAMCORDER(h) (mmf_camcorder_t *)(h) + +/** + * Caster of subcontext + */ +#define MMF_CAMCORDER_SUBCONTEXT(h) (((mmf_camcorder_t *)(h))->sub_context) + +/* LOCAL CONSTANT DEFINITIONS */ +/** + * Total Numbers of Attribute values. + * 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_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*/ +#define MM_CAMCORDER_AUTO_FOCUS_NUM 5 /**< Total count of auto focus type*/ +#define MM_CAMCORDER_FOCUS_STATE_NUM 4 /**< Number of focus state */ +#define MM_CAMCORDER_ISO_NUM 10 /**< Number of ISO */ +#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_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 */ +#define MM_CAMCORDER_DETECT_MODE_NUM 2 /**< Number of detect mode type */ + + +/*======================================================================================= +| ENUM DEFINITIONS | +========================================================================================*/ +/** + * Command for Camcorder. + */ +enum { + /* Command for Video/Audio recording */ + _MMCamcorder_CMD_RECORD, + _MMCamcorder_CMD_PAUSE, + _MMCamcorder_CMD_CANCEL, + _MMCamcorder_CMD_COMMIT, + + /* Command for Image capture */ + _MMCamcorder_CMD_CAPTURE, + _MMCamcorder_CMD_CAPTURE_CANCEL, + + /* Command for Preview(Video/Image only effective) */ + _MMCamcorder_CMD_PREVIEW_START, + _MMCamcorder_CMD_PREVIEW_STOP, +}; + +/** + * Still-shot type + */ +enum { + _MMCamcorder_SINGLE_SHOT, + _MMCamcorder_MULTI_SHOT, +}; + +/** + * Enumerations for manual focus direction. + * If focusing mode is not "MM_CAMCORDER_AF_MODE_MANUAL", this value will be ignored. + */ +enum MMCamcorderMfLensDir { + MM_CAMCORDER_MF_LENS_DIR_FORWARD = 1, /**< Focus direction to forward */ + MM_CAMCORDER_MF_LENS_DIR_BACKWARD, /**< Focus direction to backward */ + MM_CAMCORDER_MF_LENS_DIR_NUM, /**< Total number of the directions */ +}; + +/** + * Camcorder Pipeline's Element name. + * @note index of element. + */ +typedef enum { + _MMCAMCORDER_NONE = (-1), + + /* Main Pipeline Element */ + _MMCAMCORDER_MAIN_PIPE = 0x00, + + /* Pipeline element of Video input */ + _MMCAMCORDER_VIDEOSRC_BIN, + _MMCAMCORDER_VIDEOSRC_SRC, + _MMCAMCORDER_VIDEOSRC_FILT, + _MMCAMCORDER_VIDEOSRC_CLS, + _MMCAMCORDER_VIDEOSRC_SCALE, + _MMCAMCORDER_VIDEOSRC_VSFLT, + _MMCAMCORDER_VIDEOSRC_TEE, + + /* Pipeline element of Audio input */ + _MMCAMCORDER_AUDIOSRC_BIN, + _MMCAMCORDER_AUDIOSRC_SRC, + _MMCAMCORDER_AUDIOSRC_FILT, + _MMCAMCORDER_AUDIOSRC_NS, + _MMCAMCORDER_AUDIOSRC_QUE, + _MMCAMCORDER_AUDIOSRC_CONV, + _MMCAMCORDER_AUDIOSRC_VOL, + _MMCAMCORDER_AUDIOSRC_ENC, + + /* Pipeline element of Video output */ + _MMCAMCORDER_VIDEOSINK_BIN, + _MMCAMCORDER_VIDEOSINK_QUE, + _MMCAMCORDER_VIDEOSINK_SCALE, + _MMCAMCORDER_VIDEOSINK_FILT, + _MMCAMCORDER_VIDEOSINK_OVERLAY, + _MMCAMCORDER_VIDEOSINK_CLS, + _MMCAMCORDER_VIDEOSINK_ROTATE, + _MMCAMCORDER_VIDEOSINK_SINK, + + /* Pipeline element of Encodebin */ + _MMCAMCORDER_ENCSINK_BIN, + _MMCAMCORDER_ENCSINK_ENCBIN, + _MMCAMCORDER_ENCSINK_AQUE, + _MMCAMCORDER_ENCSINK_CONV, + _MMCAMCORDER_ENCSINK_AENC, + _MMCAMCORDER_ENCSINK_AENC_QUE, + _MMCAMCORDER_ENCSINK_VQUE, + _MMCAMCORDER_ENCSINK_VENC, + _MMCAMCORDER_ENCSINK_VENC_QUE, + _MMCAMCORDER_ENCSINK_ITOG, + _MMCAMCORDER_ENCSINK_ICROP, + _MMCAMCORDER_ENCSINK_ISCALE, + _MMCAMCORDER_ENCSINK_IFILT, + _MMCAMCORDER_ENCSINK_IQUE, + _MMCAMCORDER_ENCSINK_IENC, + _MMCAMCORDER_ENCSINK_MUX, + _MMCAMCORDER_ENCSINK_SINK, + + /* Pipeline element of Stillshot output */ + _MMCAMCORDER_STILLSHOTSINK_BIN, + _MMCAMCORDER_STILLSHOTSINK_QUE, + _MMCAMCORDER_STILLSHOTSINK_TOGGLE, + _MMCAMCORDER_STILLSHOTSINK_CLS, + _MMCAMCORDER_STILLSHOTSINK_CROP, + _MMCAMCORDER_STILLSHOTSINK_FILT, + _MMCAMCORDER_STILLSHOTSINK_SCALE, + _MMCAMCORDER_STILLSHOTSINK_FILT2, + _MMCAMCORDER_STILLSHOTSINK_ENC, + _MMCAMCORDER_STILLSHOTSINK_SINK, + + _MMCamcorder_PIPELINE_ELEMENT_NUM, +} _MMCAMCORDER_PIPELINE_ELELMENT; + +/** + * Command type for Camcorder. + */ +typedef enum { + _MMCAMCORDER_CMD_CREATE, + _MMCAMCORDER_CMD_DESTROY, + _MMCAMCORDER_CMD_REALIZE, + _MMCAMCORDER_CMD_UNREALIZE, + _MMCAMCORDER_CMD_START, + _MMCAMCORDER_CMD_STOP, + _MMCAMCORDER_CMD_CAPTURESTART, + _MMCAMCORDER_CMD_CAPTURESTOP, + _MMCAMCORDER_CMD_RECORD, + _MMCAMCORDER_CMD_PAUSE, + _MMCAMCORDER_CMD_COMMIT, + _MMCAMCORDER_CMD_CANCEL, + _MMCAMCORDER_CMD_QUIT, +} _MMCamcorderCommandType; + +/** + * System state change cause + */ +typedef enum { + _MMCAMCORDER_STATE_CHANGE_NORMAL = 0, + _MMCAMCORDER_STATE_CHANGE_BY_ASM, +} _MMCamcorderStateChange; + + + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ +/** + * MMCamcorder Gstreamer Element + */ +typedef struct { + unsigned int id; /**< Gstreamer piplinem element name */ + GstElement *gst; /**< Gstreamer element */ +} _MMCamcorderGstElement; + +/** + * MMCamcorder information for KPI measurement + */ +typedef struct { + int current_fps; /**< current fps of this second */ + int average_fps; /**< average fps */ + unsigned int video_framecount; /**< total number of video frame */ + unsigned int last_framecount; /**< total number of video frame in last measurement */ + struct timeval init_video_time; /**< time when start to measure */ + struct timeval last_video_time; /**< last measurement time */ +} _MMCamcorderKPIMeasure; + +/** + * MMCamcorder information for Multi-Thread Safe + */ +typedef struct { + GMutex *lock; /**< Mutex (for general use) */ + GCond *cond; /**< Condition (for general use) */ + GMutex *cmd_lock; /**< Mutex (for command) */ + GMutex *state_lock; /**< Mutex (for state change) */ + GMutex *gst_state_lock; /**< Mutex (for state change) */ + GMutex *message_cb_lock; /**< Mutex (for message callback) */ + GMutex *vcapture_cb_lock; /**< Mutex (for video capture callback) */ + GMutex *vstream_cb_lock; /**< Mutex (for video stream callback) */ + GMutex *astream_cb_lock; /**< Mutex (for audio stream callback) */ +} _MMCamcorderMTSafe; + +/** + * MMCamcorder information for command loop + */ +typedef struct { + pthread_t pCommandThread; /**< Command loop handle */ + GQueue *cmd_queue; /**< Queue for Command loop */ + sem_t sema; /**< Semaphore for Command loop */ +} _MMCamcorderCommand; + +/** + * MMCamcorder command information + */ +typedef struct { + MMHandleType handle; /**< camcorder handle */ + _MMCamcorderCommandType type; /**< Type of command */ +} __MMCamcorderCmdInfo; + +/** + * 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 **/ + 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 */ + + /* 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. */ + + /* INI information */ + unsigned int fourcc; /**< Get fourcc value of camera INI file */ + void *info; /**< extra information for camcorder */ + + _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 */ +} _MMCamcorderSubContext; + +/** + * _MMCamcorderContext + */ +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. */ + + /* handles */ + 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 */ + + /* 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 */ + + /* etc */ + _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 reserved[4]; /**< reserved */ +} mmf_camcorder_t; + +/*======================================================================================= +| EXTERN GLOBAL VARIABLE | +========================================================================================*/ + +/*======================================================================================= +| GLOBAL FUNCTION PROTOTYPES | +========================================================================================*/ +/** + * This function creates camcorder for capturing still image and recording. + * + * @param[out] handle Specifies the camcorder handle + * @param[in] info Preset information of camcorder + * @return This function returns zero on success, or negative value with error code. + * @remarks When this function calls successfully, camcorder handle will be filled with a @n + * valid value and the state of the camcorder will become MM_CAMCORDER_STATE_NULL.@n + * Note that it's not ready to working camcorder. @n + * You should call mmcamcorder_realize before starting camcorder. + * @see _mmcamcorder_create + */ +int _mmcamcorder_create(MMHandleType *handle, MMCamPreset *info); + +/** + * This function destroys instance of camcorder. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @return This function returns zero on success, or negative value with error code. + * @see _mmcamcorder_create + */ +int _mmcamcorder_destroy(MMHandleType hcamcorder); + +/** + * This function allocates memory for camcorder. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @return This function returns zero on success, or negative value with error code. + * @remarks This function can be called successfully when current state is MM_CAMCORDER_STATE_NULL @n + * and the state of the camcorder will become MM_CAMCORDER_STATE_READY. @n + * Otherwise, this function will return MM_ERROR_CAMCORDER_INVALID_CONDITION. + * @see _mmcamcorder_unrealize + * @pre MM_CAMCORDER_STATE_NULL + * @post MM_CAMCORDER_STATE_READY + */ +int _mmcamcorder_realize(MMHandleType hcamcorder); + +/** + * This function free allocated memory for camcorder. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @return This function returns zero on success, or negative value with error code. + * @remarks This function release all resources which are allocated for the camcorder engine.@n + * This function can be called successfully when current state is MM_CAMCORDER_STATE_READY and @n + * the state of the camcorder will become MM_CAMCORDER_STATE_NULL. @n + * Otherwise, this function will return MM_ERROR_CAMCORDER_INVALID_CONDITION. + * @see _mmcamcorder_realize + * @pre MM_CAMCORDER_STATE_READY + * @post MM_CAMCORDER_STATE_NULL + */ +int _mmcamcorder_unrealize(MMHandleType hcamcorder); + +/** + * This function is to start previewing. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @return This function returns zero on success, or negative value with error code. + * @remarks This function can be called successfully when current state is MM_CAMCORDER_STATE_READY and @n + * the state of the camcorder will become MM_CAMCORDER_STATE_PREPARE. @n + * Otherwise, this function will return MM_ERROR_CAMCORDER_INVALID_CONDITION. + * @see _mmcamcorder_stop + */ +int _mmcamcorder_start(MMHandleType hcamcorder); + +/** + * This function is to stop previewing. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @return This function returns zero on success, or negative value with error code. + * @remarks This function can be called successfully when current state is MM_CAMCORDER_STATE_PREPARE and @n + * the state of the camcorder will become MM_CAMCORDER_STATE_READY.@n + * Otherwise, this function will return MM_ERROR_CAMCORDER_INVALID_CONDITION. + * @see _mmcamcorder_start + */ +int _mmcamcorder_stop(MMHandleType hcamcorder); + +/** + * This function to start capturing of still images. + * + * @param[in] hcamcorder Specifies the camcorder handle. + * @return This function returns zero on success, or negative value with error code. + * @remarks This function can be called successfully when current state is MM_CAMCORDER_STATE_PREPARE and @n + * the state of the camcorder will become MM_CAMCORDER_STATE_CAPTURING. @n + * Otherwise, this function will return MM_ERROR_CAMCORDER_INVALID_CONDITION. + * @see _mmcamcorder_capture_stop + */ +int _mmcamcorder_capture_start(MMHandleType hcamcorder); + +/** + * This function is to stop capturing still images. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @return This function returns zero on success, or negative value with error code. + * @remarks This function can be called successfully when current state is MM_CAMCORDER_STATE_CAPTURING and @n + * the state of the camcorder will become MM_CAMCORDER_STATE_PREPARE. @n + * Otherwise, this function will return MM_ERROR_CAMCORDER_INVALID_CONDITION. + * @see _mmcamcorder_capture_start + */ +int _mmcamcorder_capture_stop(MMHandleType hcamcorder); + +/** + * This function is to start video and audio recording. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @return This function returns zero on success, or negative value with error code. + * @remarks This function can be called successfully when current state is @n + * MM_CAMCORDER_STATE_PREPARE or MM_CAMCORDER_STATE_PAUSED and @n + * the state of the camcorder will become MM_CAMCORDER_STATE_RECORDING.@n + * Otherwise, this function will return MM_ERROR_CAMCORDER_INVALID_CONDITION. + * @see _mmcamcorder_pause + */ +int _mmcamcorder_record(MMHandleType hcamcorder); + +/** + * This function is to pause video and audio recording + * + * @param[in] hcamcorder Specifies the camcorder handle + * @return This function returns zero on success, or negative value with error code. + * @remarks This function can be called successfully when current state is MM_CAMCORDER_STATE_RECORDING and @n + * the state of the camcorder will become MM_CAMCORDER_STATE_PAUSED.@n + * Otherwise, this function will return MM_ERROR_CAMCORDER_INVALID_CONDITION.@n + * @see _mmcamcorder_record + */ +int _mmcamcorder_pause(MMHandleType hcamcorder); + +/** + * This function is to stop video and audio recording and save results. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @return This function returns zero on success, or negative value with error code. + * @remarks This function can be called successfully when current state is @n + * MM_CAMCORDER_STATE_PAUSED or MM_CAMCORDER_STATE_RECORDING and @n + * the state of the camcorder will become MM_CAMCORDER_STATE_PREPARE. @n + * Otherwise, this function will return MM_ERROR_CAMCORDER_INVALID_CONDITION + * @see _mmcamcorder_cancel + */ +int _mmcamcorder_commit(MMHandleType hcamcorder); + +/** + * This function is to stop video and audio recording and do not save results. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @return This function returns zero on success, or negative value with error code. + * @remarks This function can be called successfully when current state is @n + * MM_CAMCORDER_STATE_PAUSED or MM_CAMCORDER_STATE_RECORDING and @n + * the state of the camcorder will become MM_CAMCORDER_STATE_PREPARE. @n + * Otherwise, this function will return MM_ERROR_CAMCORDER_INVALID_CONDITION. + * @see _mmcamcorder_commit + */ +int _mmcamcorder_cancel(MMHandleType hcamcorder); + +/** + * This function calls after commiting action finished asynchronously. + * In this function, remaining process , such as state change, happens. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @return This function returns zero on success, or negative value with error code. + * @remarks This function can be called successfully when current state is @n + * MM_CAMCORDER_STATE_PAUSED or MM_CAMCORDER_STATE_RECORDING and @n + * the state of the camcorder will become MM_CAMCORDER_STATE_PREPARE. @n + * Otherwise, this function will return MM_ERROR_CAMCORDER_INVALID_CONDITION. + * @see _mmcamcorder_commit + */ +int _mmcamcorder_commit_async_end(MMHandleType hcamcorder); + +/** + * This function is to set callback for receiving messages from camcorder. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @param[in] callback Specifies the function pointer of callback function + * @param[in] user_data Specifies the user poiner for passing to callback function + * + * @return This function returns zero on success, or negative value with error code. + * @remarks typedef bool (*mm_message_callback) (int msg, mm_messageType *param, void *user_param);@n + * @n + * typedef union @n + * { @n + * int code; @n + * struct @n + * { @n + * int total; @n + * int elapsed; @n + * } time; @n + * struct @n + * { @n + * int previous; @n + * int current; @n + * } state; @n + * } mm_message_type; @n + * @n + * If a message value for mm_message_callback is MM_MESSAGE_STATE_CHANGED, @n + * state value in mm_message_type will be a mmcamcorder_state_type enum value;@n + * @n + * If a message value for mm_message_callback is MM_MESSAGE_ERROR, @n + * the code value in mm_message_type will be a mmplayer_error_type enum value; + * + * @see mm_message_type, mmcamcorder_state_type, mmcamcorder_error_type + */ +int _mmcamcorder_set_message_callback(MMHandleType hcamcorder, + MMMessageCallback callback, + void *user_data); + +/** + * This function is to set callback for video stream. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @param[in] callback Specifies the function pointer of callback function + * @param[in] user_data Specifies the user poiner for passing to callback function + * + * @return This function returns zero on success, or negative value with error code. + * @see mmcamcorder_error_type + */ +int _mmcamcorder_set_video_stream_callback(MMHandleType hcamcorder, + mm_camcorder_video_stream_callback callback, + void *user_data); + +/** + * This function is to set callback for audio stream. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @param[in] callback Specifies the function pointer of callback function + * @param[in] user_data Specifies the user poiner for passing to callback function + * + * @return This function returns zero on success, or negative value with error code. + * @see mmcamcorder_error_type + */ +int _mmcamcorder_set_audio_stream_callback(MMHandleType handle, + mm_camcorder_audio_stream_callback callback, + void *user_data); + +/** + * This function is to set callback for video capture. + * + * @param[in] hcamcorder Specifies the camcorder handle + * @param[in] callback Specifies the function pointer of callback function + * @param[in] user_data Specifies the user poiner for passing to callback function + * + * @return This function returns zero on success, or negative value with error code. + * @see mmcamcorder_error_type + */ +int _mmcamcorder_set_video_capture_callback(MMHandleType hcamcorder, + mm_camcorder_video_capture_callback callback, + void *user_data); + +/** + * This function returns current state of camcorder, or negative value with error code. + * + * @param[in] hcamcorder Specifies the camcorder handle. + * @return This function returns current state of camcorder, or negative value with error code. + * @see mmcamcorder_state_type + */ +int _mmcamcorder_get_current_state(MMHandleType hcamcorder); + +int _mmcamcorder_init_focusing(MMHandleType handle); +int _mmcamcorder_adjust_focus(MMHandleType handle, int direction); +int _mmcamcorder_adjust_manual_focus(MMHandleType handle, int direction); +int _mmcamcorder_adjust_auto_focus(MMHandleType handle); +int _mmcamcorder_stop_focusing(MMHandleType handle); + +/** + * This function gets current state of camcorder. + * + * @param void + * @return This function returns state of current camcorder context + * @remarks + * @see _mmcamcorder_set_state() + * + */ +int _mmcamcorder_streamer_init(void); + +/** + * This function gets current state of camcorder. + * + * @param void + * @return This function returns state of current camcorder context + * @remarks + * @see _mmcamcorder_set_state() + * + */ +int _mmcamcorder_display_init(void); + +/** + * This function gets current state of camcorder. + * + * @param[in] handle Handle of camcorder context. + * @return This function returns state of current camcorder context + * @remarks + * @see _mmcamcorder_set_state() + * + */ +int _mmcamcorder_get_state(MMHandleType handle); + +/** + * This function sets new state of camcorder. + * + * @param[in] handle Handle of camcorder context. + * @param[in] state setting state value of camcorder. + * @return void + * @remarks + * @see _mmcamcorder_get_state() + * + */ +void _mmcamcorder_set_state(MMHandleType handle, int state); + +/** + * This function gets asynchronous status of MSL Camcroder. + * + * @param[in] handle Handle of camcorder context. + * @param[in] target_state setting target_state value of camcorder. + * @return This function returns asynchrnous state. + * @remarks + * @see _mmcamcorder_set_async_state() + * + */ +int _mmcamcorder_get_async_state(MMHandleType handle); + +/** + * This function sets new target state of camcorder. + * + * @param[in] handle Handle of camcorder context. + * @param[in] target_state setting target_state value of camcorder. + * @return This function returns zero on success, or negative value with error code. + * @remarks + * @see _mmcamcorder_get_async_state(), _mmcamcorder_set_async_cancel() + * + */ +int _mmcamcorder_set_async_state(MMHandleType handle, int target_state); + +/** + * This function sets new target state of camcorder. + * + * @param[in] handle Handle of camcorder context. + * @return gboolean + * @remarks + * @see _mmcamcorder_set_async_cancel() + * + */ +gboolean _mmcamcorder_set_async_cancel(MMHandleType handle); + +/** + * Check whether camcorder changes its state now. + * + * @param[in] handle Handle of camcorder context. + * @return gboolean + * @remarks + * @see _mmcamcorder_set_async_state(), _mmcamcorder_set_async_cancel() + * + */ +gboolean _mmcamcorder_is_state_changing(MMHandleType handle); + +/** + * This function allocates structure of subsidiary attributes. + * + * @param[in] type Allocation type of camcorder context. + * @return This function returns structure pointer on success, NULL value on failure. + * @remarks + * @see _mmcamcorder_dealloc_subcontext() + * + */ +_MMCamcorderSubContext *_mmcamcorder_alloc_subcontext(int type); + +/** + * This function releases structure of subsidiary attributes. + * + * @param[in] sc Handle of camcorder subcontext. + * @return void + * @remarks + * @see _mmcamcorder_alloc_subcontext() + * + */ +void _mmcamcorder_dealloc_subcontext(_MMCamcorderSubContext *sc); + +/** + * This function sets command function according to the type. + * + * @param[in] handle Handle of camcorder context. + * @param[in] type Allocation type of camcorder context. + * @return This function returns MM_ERROR_NONE on success, or other values with error code. + * @remarks + * @see __mmcamcorder_video_command(), __mmcamcorder_audio_command(), __mmcamcorder_image_command() + * + */ +int _mmcamcorder_set_functions(MMHandleType handle, int type); + +/** + * This function is callback function of main pipeline. + * Once this function is registered with certain pipeline using gst_bus_add_watch(), + * this callback will be called every time when there is upcomming message from pipeline. + * Basically, this function is used as error handling function, now. + * + * @param[in] bus pointer of buf that called this function. + * @param[in] message callback message from pipeline. + * @param[in] data user data. + * @return This function returns true on success, or false value with error + * @remarks + * @see __mmcamcorder_create_preview_pipeline() + * + */ +gboolean _mmcamcorder_pipeline_cb_message(GstBus *bus, GstMessage *message, gpointer data); + +/** + * This function create main pipeline according to type. + * + * @param[in] handle Handle of camcorder context. + * @param[in] type Allocation type of camcorder context. + * @return This function returns zero on success, or negative value with error code. + * @remarks + * @see _mmcamcorder_destroy_pipeline() + * + */ +int _mmcamcorder_create_pipeline(MMHandleType handle, int type); + +/** + * This function release all element of main pipeline according to type. + * + * @param[in] handle Handle of camcorder context. + * @param[in] type Allocation type of camcorder context. + * @return void + * @remarks + * @see _mmcamcorder_create_pipeline() + * + */ +void _mmcamcorder_destroy_pipeline(MMHandleType handle, int type); + +/** + * This function sets gstreamer element status. + * If the gstreamer fails to set status or returns asynchronous mode, + * this function waits for state changed until timeout expired. + * + * @param[in] pipeline Pointer of pipeline + * @param[in] target_state newly setting status + * @return This function returns zero on success, or negative value with error code. + * @remarks + * @see + * + */ +int _mmcamcorder_gst_set_state(MMHandleType handle, GstElement *pipeline, GstState target_state); + +/** + * This function sets gstreamer element status, asynchronously. + * Regardless of processing, it returns immediately. + * + * @param[in] pipeline Pointer of pipeline + * @param[in] target_state newly setting status + * @return This function returns zero on success, or negative value with error code. + * @remarks + * @see + * + */ +int _mmcamcorder_gst_set_state_async(MMHandleType handle, GstElement *pipeline, GstState target_state); + +/* For xvimagesink */ +GstBusSyncReply __mmcamcorder_sync_callback(GstBus *bus, GstMessage *message, gulong data); + +/* For querying capabilities */ +int _mmcamcorder_read_vidsrc_info(int videodevidx, camera_conf **configure_info); + +/* for performance check */ +void _mmcamcorder_video_current_framerate_init(MMHandleType handle); +int _mmcamcorder_video_current_framerate(MMHandleType handle); +int _mmcamcorder_video_average_framerate(MMHandleType handle); + +/* command */ +void _mmcamcorder_delete_command_info(__MMCamcorderCmdInfo *cmdinfo); +int _mmcamcorder_create_command_loop(MMHandleType handle); +int _mmcamcorder_destroy_command_loop(MMHandleType handle); +int _mmcamcorder_append_command(MMHandleType handle, __MMCamcorderCmdInfo *info); +int _mmcamcorder_append_simple_command(MMHandleType handle, _MMCamcorderCommandType type); +void *_mmcamcorder_command_loop_thread(void *arg); + +#ifdef __cplusplus +} +#endif + +#endif /* __MM_CAMCORDER_INTERNAL_H__ */ diff --git a/src/include/mm_camcorder_platform.h b/src/include/mm_camcorder_platform.h new file mode 100644 index 0000000..171a9f4 --- /dev/null +++ b/src/include/mm_camcorder_platform.h @@ -0,0 +1,223 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_CAMCORDER_PLATFORM_H__ +#define __MM_CAMCORDER_PLATFORM_H__ + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ +#include <gst/gst.h> +#include <mm_types.h> + + + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| GLOBAL DEFINITIONS AND DECLARATIONS FOR CAMCORDER | +========================================================================================*/ + +/*======================================================================================= +| MACRO DEFINITIONS | +========================================================================================*/ +/* CAMERA DEFINED VALUE */ +/* WQSXGA (5M) */ +#define MMF_CAM_W2560 2560 +#define MMF_CAM_H1920 1920 + +/* QXGA (3M) */ +#define MMF_CAM_W2048 2048 +#define MMF_CAM_H1536 1536 + +/* UXGA (2M) */ +#define MMF_CAM_W1600 1600 +#define MMF_CAM_H1200 1200 + +/* WSXGA (1M) */ +#define MMF_CAM_W1280 1280 +#define MMF_CAM_H960 960 + +/* SVGA */ +#define MMF_CAM_W800 800 +#define MMF_CAM_H600 600 + +/* WVGA */ +#define MMF_CAM_W800 800 +#define MMF_CAM_H480 480 + +/* VGA */ +#define MMF_CAM_W640 640 +#define MMF_CAM_H480 480 + +/* CIF */ +#define MMF_CAM_W352 352 +#define MMF_CAM_H288 288 + +/* QVGA */ +#define MMF_CAM_W320 320 +#define MMF_CAM_H240 240 + +/* QCIF */ +#define MMF_CAM_W176 176 +#define MMF_CAM_H144 144 + +/* QQVGA */ +#define MMF_CAM_W160 160 +#define MMF_CAM_H120 120 + +/* QQCIF */ +#define MMF_CAM_W88 88 +#define MMF_CAM_H72 72 + +/* WQVGA */ +#define MMF_CAM_W400 400 +#define MMF_CAM_H240 240 + +/* RQVGA */ +#define MMF_CAM_W240 240 +#define MMF_CAM_H320 320 + +/* RWQVGA */ +#define MMF_CAM_W240 240 +#define MMF_CAM_H400 400 + +/* Non-specified */ +#define MMF_CAM_W400 400 +#define MMF_CAM_H300 300 + +/* HD */ +#define MMF_CAM_W1280 1280 +#define MMF_CAM_H720 720 + +//Zero +#define MMF_CAM_W0 0 +#define MMF_CAM_H0 0 + + +/* Capture related */ +/* High quality resolution */ +#define MMFCAMCORDER_HIGHQUALITY_WIDTH MMF_CAM_W0 /* High quality resolution is not needed, */ +#define MMFCAMCORDER_HIGHQUALITY_HEIGHT MMF_CAM_H0 /* because camsensor has a JPEG encoder inside */ + +/* VGA (1 : 0.75) */ +#define MMF_CROP_VGA_LEFT 0 +#define MMF_CROP_VGA_RIGHT 0 +#define MMF_CROP_VGA_TOP 0 +#define MMF_CROP_VGA_BOTTOM 0 + +/* QCIF (1 : 0.818) */ +#define MMF_CROP_CIF_LEFT 68 /* little bit confusing */ +#define MMF_CROP_CIF_RIGHT 68 +#define MMF_CROP_CIF_TOP 0 +#define MMF_CROP_CIF_BOTTOM 0 + +/* Camera etc */ +#define _MMCAMCORDER_CAMSTABLE_COUNT 0 /* stablize count of camsensor */ +#define _MMCAMCORDER_MINIMUM_SPACE (512*1024) /* byte */ +#define _MMCAMCORDER_MMS_MARGIN_SPACE (512) /* byte */ + +/** + * Default None value for camera sensor enumeration. + */ +#define _MMCAMCORDER_SENSOR_ENUM_NONE -255 + + +/*======================================================================================= +| ENUM DEFINITIONS | +========================================================================================*/ +/** + * Enumerations for attribute converting. + */ +typedef enum { + MM_CAMCONVERT_TYPE_INT, + MM_CAMCONVERT_TYPE_INT_RANGE, + MM_CAMCONVERT_TYPE_INT_ARRAY, + MM_CAMCONVERT_TYPE_INT_PAIR_ARRAY, + MM_CAMCONVERT_TYPE_STRING, +/* + MM_CAMCONVERT_TYPE_DOUBLE, + MM_CAMCONVERT_TYPE_DOUBLE_PAIR, +*/ + MM_CAMCONVERT_TYPE_USER, /* user define */ +} MMCamConvertingType; + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ +/** + * Structure for enumeration converting. + */ +typedef struct { + int total_enum_num; /**< total enumeration count */ + int *enum_arr; /**< enumeration array */ + int category; /**< category */ + char *keyword; /**< keyword array */ +} _MMCamcorderEnumConvert; + + +/** + * Converting table of camera configuration. + */ +typedef struct { + int type; /**< type of configuration */ + int category; /**< category of configuration */ + int attr_idx; /**< attribute index */ + int attr_idx_pair; /**< attribute index (only for 'pair' type) */ + char *keyword; + MMCamConvertingType conv_type; + _MMCamcorderEnumConvert *enum_convert; /**< converting value table */ +} _MMCamcorderInfoConverting; + +/*======================================================================================= +| CONSTANT DEFINITIONS | +========================================================================================*/ + +/*======================================================================================= +| STATIC VARIABLES | +========================================================================================*/ + +/*======================================================================================= +| EXTERN GLOBAL VARIABLE | +========================================================================================*/ + +/*======================================================================================= +| 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_set_converted_value(MMHandleType handle, _MMCamcorderEnumConvert *convert); +int _mmcamcorder_init_convert_table(MMHandleType handle); +int _mmcamcorder_init_attr_from_configure(MMHandleType handle); + +int _mmcamcorder_convert_brightness(int mslVal); +int _mmcamcorder_convert_whitebalance(int mslVal); +int _mmcamcorder_convert_colortone(int mslVal); +double _mmcamcorder_convert_volume(int mslVal); + +#ifdef __cplusplus +} +#endif + +#endif /* __MM_CAMCORDER_PLATFORM_H__ */ diff --git a/src/include/mm_camcorder_sound.h b/src/include/mm_camcorder_sound.h new file mode 100644 index 0000000..199f27c --- /dev/null +++ b/src/include/mm_camcorder_sound.h @@ -0,0 +1,103 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_CAMCORDER_SOUND_H__ +#define __MM_CAMCORDER_SOUND_H__ + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| GLOBAL DEFINITIONS AND DECLARATIONS FOR CAMCORDER | +========================================================================================*/ + +/*======================================================================================= +| MACRO DEFINITIONS | +========================================================================================*/ +#define _MMCAMCORDER_FILEPATH_CAPTURE_SND "/usr/share/sounds/mm-camcorder/capture_shutter_01.wav" +#define _MMCAMCORDER_FILEPATH_CAPTURE2_SND "/usr/share/sounds/mm-camcorder/capture_shutter_02.wav" +#define _MMCAMCORDER_FILEPATH_REC_START_SND "/usr/share/sounds/mm-camcorder/recording_start_01.wav" +#define _MMCAMCORDER_FILEPATH_REC_STOP_SND "/usr/share/sounds/mm-camcorder/recording_stop_01.wav" +#define _MMCAMCORDER_FILEPATH_AF_SUCCEED_SND "/usr/share/sounds/mm-camcorder/af_succeed.wav" +#define _MMCAMCORDER_FILEPATH_AF_FAIL_SND "/usr/share/sounds/mm-camcorder/af_fail.wav" +#define _MMCAMCORDER_FILEPATH_NO_SND "/usr/share/sounds/mm-camcorder/no_sound.wav" + +/*======================================================================================= +| ENUM DEFINITIONS | +========================================================================================*/ +typedef enum { + _MMCAMCORDER_SOUND_STATE_NONE, + _MMCAMCORDER_SOUND_STATE_INIT, + _MMCAMCORDER_SOUND_STATE_PREPARE, + _MMCAMCORDER_SOUND_STATE_PLAYING, +} _MMCamcorderSoundState; + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ +/** + * Structure of sound info + */ +typedef struct __SOUND_INFO { + SF_INFO sfinfo; + SNDFILE *infile; + short *pcm_buf; + int pcm_size; + char *filename; + + MMSoundPcmHandle_t handle; + + int thread_run; + pthread_t thread; + 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; + + _MMCamcorderSoundState state; +} SOUND_INFO; + +/*======================================================================================= +| CONSTANT DEFINITIONS | +========================================================================================*/ + + +/*======================================================================================= +| GLOBAL FUNCTION PROTOTYPES | +========================================================================================*/ +gboolean _mmcamcorder_sound_init(MMHandleType handle, char *filename); +gboolean _mmcamcorder_sound_prepare(MMHandleType handle); +gboolean _mmcamcorder_sound_play(MMHandleType handle); +gboolean _mmcamcorder_sound_finalize(MMHandleType handle); + +void _mmcamcorder_sound_solo_play(MMHandleType handle, const char *filepath, gboolean sync); + +#ifdef __cplusplus +} +#endif + +#endif /* __MM_CAMCORDER_SOUND_H__ */ diff --git a/src/include/mm_camcorder_stillshot.h b/src/include/mm_camcorder_stillshot.h new file mode 100644 index 0000000..525237a --- /dev/null +++ b/src/include/mm_camcorder_stillshot.h @@ -0,0 +1,134 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_CAMCORDER_STILLSHOT_H__ +#define __MM_CAMCORDER_STILLSHOT_H__ + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ +#include <gst/gst.h> +#include <mm_types.h> +#include <mm_sound.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| GLOBAL DEFINITIONS AND DECLARATIONS FOR CAMCORDER | +========================================================================================*/ + +/*======================================================================================= +| MACRO DEFINITIONS | +========================================================================================*/ +#define _MMCAMCORDER_CAPTURE_STOP_CHECK_INTERVAL 5000 +#define _MMCAMCORDER_CAPTURE_STOP_CHECK_COUNT 600 +#define _MNOTE_VALUE_NONE 0 + +/*======================================================================================= +| ENUM DEFINITIONS | +========================================================================================*/ + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ +/** + * MMCamcorder information for image(preview/capture) mode + */ +typedef struct { + int type; /**< Still-shot/Multi-shot */ + int count; /**< Multi-shot capture count */ + int capture_cur_count; /**< Multi-shot capture current count */ + int capture_send_count; /**< Multi-shot capture send count */ + unsigned long long next_shot_time; /**< next still capture time */ + gboolean multi_shot_stop; /**< Multi-shot stop flag */ + gboolean capturing; /**< whether MSL is on capturing */ + gboolean resolution_change; /**< whether on resolution changing for capturing. After changing to capture resolution, it sets to FALSE again. */ + int width; /**< Width of capture image */ + int height; /**< Height of capture image */ + int interval; /**< Capture interval */ +} _MMCamcorderImageInfo; + +/*======================================================================================= +| CONSTANT DEFINITIONS | +========================================================================================*/ + +/*======================================================================================= +| STATIC VARIABLES | +========================================================================================*/ + +/*======================================================================================= +| EXTERN GLOBAL VARIABLE | +========================================================================================*/ + +/*======================================================================================= +| GLOBAL FUNCTION PROTOTYPES | +========================================================================================*/ +/** + * This function add still shot bin to main pipeline. + * When application creates initial pipeline, there are only bins for preview. + * If application wants to add stil shot function, bins for stillshot should be added. + * + * @param[in] handle Handle of camcorder context. + * @return This function returns MM_ERROR_NONE on success, or the other values on error. + * @remarks + * @see __mmcamcorder_create_preview_pipeline() + */ +int _mmcamcorder_add_stillshot_pipeline(MMHandleType handle); + +/** + * This function remove still shot bin from main pipeline. + * + * @param[in] handle Handle of camcorder context. + * @return This function returns MM_ERROR_NONE on success, or the other values on error. + * @remarks + * @see __mmcamcorder_create_preview_pipeline(), __mmcamcorder_add_stillshot_pipeline() + */ +int _mmcamcorder_remove_stillshot_pipeline(MMHandleType handle); + +/** + * This function destroy image pipeline. + * + * @param[in] handle Handle of camcorder context. + * @return void + * @remarks + * @see _mmcamcorder_destroy_pipeline() + * + */ +void _mmcamcorder_destroy_image_pipeline(MMHandleType handle); +int _mmcamcorder_image_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); +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); + +#ifdef __cplusplus +} +#endif + +#endif /* __MM_CAMCORDER_STILLSHOT_H__ */ diff --git a/src/include/mm_camcorder_util.h b/src/include/mm_camcorder_util.h new file mode 100644 index 0000000..c9df689 --- /dev/null +++ b/src/include/mm_camcorder_util.h @@ -0,0 +1,246 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_CAMCORDER_UTIL_H__ +#define __MM_CAMCORDER_UTIL_H__ + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| GLOBAL DEFINITIONS AND DECLARATIONS FOR CAMCORDER | +========================================================================================*/ + +/*======================================================================================= +| MACRO DEFINITIONS | +========================================================================================*/ +#ifndef CLEAR +#define CLEAR(x) memset (&(x), 0, sizeof (x)) +#endif + +#define MMCAMCORDER_ADD_BUFFER_PROBE(x_pad, x_category, x_callback, x_hcamcorder) \ +do { \ + MMCamcorderHandlerItem *item = NULL; \ + item = (MMCamcorderHandlerItem *)g_malloc(sizeof(MMCamcorderHandlerItem)); \ + if (!item) {\ + _mmcam_dbg_err("Cannot connect buffer probe [malloc fail] \n"); \ + } else if (x_category == 0 || !(x_category & _MMCAMCORDER_HANDLER_CATEGORY_ALL)) { \ + _mmcam_dbg_err("Invalid handler category : %x \n", x_category); \ + } else { \ + item->object = G_OBJECT(x_pad); \ + item->category = x_category; \ + item->handler_id = gst_pad_add_buffer_probe(x_pad, G_CALLBACK(x_callback), x_hcamcorder); \ + x_hcamcorder->buffer_probes = g_list_append(x_hcamcorder->buffer_probes, item); \ + _mmcam_dbg_log("Adding buffer probe on [%s:%s] - [ID : %lu], [Category : %x] ", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category); \ + } \ +} while (0); + +#define MMCAMCORDER_ADD_EVENT_PROBE(x_pad, x_category, x_callback, x_hcamcorder) \ +do { \ + MMCamcorderHandlerItem *item = NULL; \ + item = (MMCamcorderHandlerItem *) g_malloc(sizeof(MMCamcorderHandlerItem)); \ + if (!item) { \ + _mmcam_dbg_err("Cannot connect buffer probe [malloc fail] \n"); \ + } \ + else if (x_category == 0 || !(x_category & _MMCAMCORDER_HANDLER_CATEGORY_ALL)) { \ + _mmcam_dbg_err("Invalid handler category : %x \n", x_category); \ + } else { \ + item->object =G_OBJECT(x_pad); \ + item->category = x_category; \ + item->handler_id = gst_pad_add_event_probe(x_pad, G_CALLBACK(x_callback), x_hcamcorder); \ + x_hcamcorder->event_probes = g_list_append(x_hcamcorder->event_probes, item); \ + _mmcam_dbg_log("Adding event probe on [%s:%s] - [ID : %lu], [Category : %x] ", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category); \ + } \ +} while (0); + +#define MMCAMCORDER_ADD_DATA_PROBE(x_pad, x_category, x_callback, x_hcamcorder) \ +do { \ + MMCamcorderHandlerItem *item = NULL; \ + item = (MMCamcorderHandlerItem *) g_malloc(sizeof(MMCamcorderHandlerItem)); \ + if (!item) { \ + _mmcam_dbg_err("Cannot connect buffer probe [malloc fail] \n"); \ + } else if (x_category == 0 || !(x_category & _MMCAMCORDER_HANDLER_CATEGORY_ALL)) { \ + _mmcam_dbg_err("Invalid handler category : %x \n", x_category); \ + } else { \ + item->object =G_OBJECT(x_pad); \ + item->category = x_category; \ + item->handler_id = gst_pad_add_data_probe(x_pad, G_CALLBACK(x_callback), x_hcamcorder); \ + x_hcamcorder->data_probes = g_list_append(x_hcamcorder->data_probes, item); \ + _mmcam_dbg_log("Adding data probe on [%s:%s] - [ID : %lu], [Category : %x] ", GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category); \ + } \ +} while (0); + +#define MMCAMCORDER_SIGNAL_CONNECT( x_object, x_category, x_signal, x_callback, x_hcamcorder) \ +do { \ + MMCamcorderHandlerItem* item = NULL; \ + item = (MMCamcorderHandlerItem *) g_malloc(sizeof(MMCamcorderHandlerItem)); \ + if (!item) { \ + _mmcam_dbg_err("Cannot connect signal [%s]\n", x_signal ); \ + } else if (x_category == 0 || !(x_category & _MMCAMCORDER_HANDLER_CATEGORY_ALL)) { \ + _mmcam_dbg_err("Invalid handler category : %x \n", x_category); \ + } else { \ + item->object = G_OBJECT(x_object); \ + item->category = x_category; \ + item->handler_id = g_signal_connect(G_OBJECT(x_object), x_signal,\ + G_CALLBACK(x_callback), x_hcamcorder ); \ + x_hcamcorder->signals = g_list_append(x_hcamcorder->signals, item); \ + _mmcam_dbg_log("Connecting signal on [%s] - [ID : %lu], [Category : %x] ", GST_OBJECT_NAME(item->object), item->handler_id, item->category); \ + } \ +} while (0); + +#define MMCAMCORDER_G_OBJECT_GET(obj, name, value) \ +do { \ + if (obj) { \ + if(g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(obj)), name)) { \ + g_object_get(G_OBJECT(obj), name, value, NULL); \ + } else { \ + _mmcam_dbg_warn ("The object doesn't have a property named(%s)", name); \ + } \ + } else { \ + _mmcam_dbg_err("Null object"); \ + } \ +} while(0); + +#define MMCAMCORDER_G_OBJECT_SET(obj, name, value) \ +do { \ + if (obj) { \ + if(g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(obj)), name)) { \ + g_object_set(G_OBJECT(obj), name, value, NULL); \ + } else { \ + _mmcam_dbg_warn ("The object doesn't have a property named(%s)", name); \ + } \ + } else { \ + _mmcam_dbg_err("Null object"); \ + } \ +} while(0); + +#define MMCAM_FOURCC(a,b,c,d) (guint32)((a)|(b)<<8|(c)<<16|(d)<<24) +#define MMCAM_FOURCC_ARGS(fourcc) \ + ((gchar)((fourcc)&0xff)), \ + ((gchar)(((fourcc)>>8)&0xff)), \ + ((gchar)(((fourcc)>>16)&0xff)), \ + ((gchar)(((fourcc)>>24)&0xff)) + +/*======================================================================================= +| ENUM DEFINITIONS | +========================================================================================*/ +/** + *Type define of util. + */ +typedef enum { + _MMCAMCORDER_HANDLER_PREVIEW = (1 << 0), + _MMCAMCORDER_HANDLER_VIDEOREC = (1 << 1), + _MMCAMCORDER_HANDLER_STILLSHOT = (1 << 2), + _MMCAMCORDER_HANDLER_AUDIOREC = (1 << 3), +} _MMCamcorderHandlerCategory; + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ + +/** + * Structure of location info + */ +typedef struct { + gint32 longitude; + gint32 latitude; + gint32 altitude; +} _MMCamcorderLocationInfo; + +/** + * Structure of handler item + */ +typedef struct { + GObject *object; + _MMCamcorderHandlerCategory category; + gulong handler_id; +} MMCamcorderHandlerItem; + +/** + * Structure of message item + */ +typedef struct { + MMHandleType handle; /**< handle */ + int id; /**< message id */ + MMMessageParamType param; /**< message parameter */ +} _MMCamcorderMsgItem; + +/*======================================================================================= +| CONSTANT DEFINITIONS | +========================================================================================*/ +#define _MMCAMCORDER_HANDLER_CATEGORY_ALL \ + (_MMCAMCORDER_HANDLER_PREVIEW | _MMCAMCORDER_HANDLER_VIDEOREC |_MMCAMCORDER_HANDLER_STILLSHOT | _MMCAMCORDER_HANDLER_AUDIOREC) + +/*======================================================================================= +| GLOBAL FUNCTION PROTOTYPES | +========================================================================================*/ +/* GStreamer */ +void _mmcamcorder_remove_buffer_probe(MMHandleType handle, _MMCamcorderHandlerCategory category); +void _mmcamcorder_remove_event_probe(MMHandleType handle, _MMCamcorderHandlerCategory category); +void _mmcamcorder_remove_data_probe(MMHandleType handle, _MMCamcorderHandlerCategory category); +void _mmcamcorder_disconnect_signal(MMHandleType handle, _MMCamcorderHandlerCategory category); +void _mmcamcorder_remove_all_handlers(MMHandleType handle, _MMCamcorderHandlerCategory category); +void _mmcamcorder_element_release_noti(gpointer data, GObject *where_the_object_was); +gboolean _mmcamcorder_add_elements_to_bin(GstBin *bin, GList *element_list); +gboolean _mmcamcorder_link_elements(GList *element_list); + +/* Message */ +gboolean _mmcamcroder_msg_callback(void *data); +gboolean _mmcamcroder_send_message(MMHandleType handle, _MMCamcorderMsgItem *data); +void _mmcamcroder_remove_message_all(MMHandleType handle); + +/* Pixel format */ +int _mmcamcorder_get_pixel_format(GstBuffer *buffer); +int _mmcamcorder_get_pixtype(unsigned int fourcc); +unsigned int _mmcamcorder_get_fourcc(int pixtype, int codectype, int use_zero_copy_format); + +/* JPEG encode */ +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); + +/* 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); +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); + +/* File system */ +int _mmcamcorder_get_freespace(const gchar *path, guint64 *free_space); +int _mmcamcorder_get_file_size(const char *filename, guint64 *size); + +/* Debug */ +void _mmcamcorder_err_trace_write(char *str_filename, char *func_name, int line_num, char *fmt, ...); + +#ifdef __cplusplus +} +#endif + +#endif /* __MM_CAMCORDER_UTIL_H__ */ diff --git a/src/include/mm_camcorder_videorec.h b/src/include/mm_camcorder_videorec.h new file mode 100644 index 0000000..e5018d5 --- /dev/null +++ b/src/include/mm_camcorder_videorec.h @@ -0,0 +1,139 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_CAMCORDER_VIDEOREC_H__ +#define __MM_CAMCORDER_VIDEOREC_H__ + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ +#include <mm_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/*======================================================================================= +| GLOBAL DEFINITIONS AND DECLARATIONS FOR CAMCORDER | +========================================================================================*/ + +/*======================================================================================= +| MACRO DEFINITIONS | +========================================================================================*/ + +/*======================================================================================= +| ENUM DEFINITIONS | +========================================================================================*/ + +/*======================================================================================= +| STRUCTURE DEFINITIONS | +========================================================================================*/ +/** + * MMCamcorder information for video(preview/recording) mode + */ +typedef struct { + gboolean b_commiting; /**< Is it commiting now? */ + char *filename; /**< recorded filename */ + gint multiple_fps; /**< fps for high speed recording(slow motion recording) */ + guint64 video_frame_count; /**< current video frame */ + guint64 audio_frame_count; /**< current audio frame */ + guint64 filesize; /**< current file size */ + guint64 max_time; /**< max recording time */ + int fileformat; /**< recording file format */ +/* + guint checker_id; + guint checker_count; +*/ +} _MMCamcorderVideoInfo; + +/*======================================================================================= +| CONSTANT DEFINITIONS | +========================================================================================*/ + +/*======================================================================================= +| STATIC VARIABLES | +========================================================================================*/ + +/*======================================================================================= +| EXTERN GLOBAL VARIABLE | +========================================================================================*/ + +/*======================================================================================= +| GLOBAL FUNCTION PROTOTYPES | +========================================================================================*/ +/** + * This function add recorder bin to main pipeline. + * When application creates initial pipeline, there are only bins for preview. + * If application wants to add recording function, bins for recording should be added. + * + * @param[in] handle Handle of camcorder context. + * @return This function returns MM_ERROR_NONE on success, or the other values on error. + * @remarks + * @see __mmcamcorder_create_preview_pipeline() + */ +int _mmcamcorder_add_recorder_pipeline(MMHandleType handle); + +/** + * This function remove recorder bin from main pipeline. + * + * @param[in] handle Handle of camcorder context. + * @return This function returns MM_ERROR_NONE on success, or the other values on error. + * @remarks + * @see __mmcamcorder_create_preview_pipeline(), __mmcamcorder_add_recorder_pipeline() + */ +int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle); + +/** + * This function destroy video pipeline. + * + * @param[in] handle Handle of camcorder context. + * @return void + * @remarks + * @see _mmcamcorder_destroy_pipeline() + */ +void _mmcamcorder_destroy_video_pipeline(MMHandleType handle); + +/** + * This function operates each command on video mode. + * + * @param[in] handle Handle of camcorder context. + * @param[in] command command type received from Multimedia Framework. + * @return This function returns MM_ERROR_NONE on success, or the other values on error. + * @remarks + * @see _mmcamcorder_set_functions() + */ +int _mmcamcorder_video_command(MMHandleType handle, int command); + +/** + * This function handles EOS(end of stream) when commit video recording. + * + * @param[in] handle Handle of camcorder context. + * @return This function returns TRUE on success, or FALSE on failure. + * @remarks + * @see _mmcamcorder_set_functions() + */ +int _mmcamcorder_video_handle_eos(MMHandleType handle); + +#ifdef __cplusplus +} +#endif + +#endif /* __MM_CAMCORDER_VIDEOREC_H__ */ diff --git a/src/mm_camcorder.c b/src/mm_camcorder.c new file mode 100644 index 0000000..2514355 --- /dev/null +++ b/src/mm_camcorder.c @@ -0,0 +1,428 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* ============================================================================== +| INCLUDE FILES | +===============================================================================*/ +#include <stdio.h> +#include <string.h> + + +#include <mm_error.h> +#include <mm_ta.h> + +#include <mm_attrs_private.h> +#include "mm_camcorder.h" +#include "mm_camcorder_internal.h" + + +/*=============================================================================== +| FUNCTION DEFINITIONS | +===============================================================================*/ +/*------------------------------------------------------------------------------- +| GLOBAL FUNCTION DEFINITIONS: | +-------------------------------------------------------------------------------*/ +int mm_camcorder_create(MMHandleType *camcorder, MMCamPreset *info) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + mmf_return_val_if_fail((void *)info, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_err(""); + + MMTA_INIT() ; + + __ta__("_mmcamcorder_create", + error = _mmcamcorder_create(camcorder, info); + ); + + _mmcam_dbg_err("END"); + + return error; +} + + +int mm_camcorder_destroy(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_err(""); + + __ta__("_mmcamcorder_destroy", + error = _mmcamcorder_destroy(camcorder); + ); + + MMTA_ACUM_ITEM_SHOW_RESULT_TO(MMTA_SHOW_FILE); + MMTA_RELEASE(); + + _mmcam_dbg_err("END!!!"); + + return error; +} + + +int mm_camcorder_realize(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_err(""); + + if(((mmf_camcorder_t *)camcorder)->sync_state_change) { + __ta__("_mmcamcorder_realize", + error = _mmcamcorder_realize(camcorder); + ); + } else { + /* After sending command, this function just return immediately. */ + error = _mmcamcorder_append_simple_command(camcorder, _MMCAMCORDER_CMD_REALIZE); + } + + _mmcam_dbg_err("END"); + + return error; +} + + +int mm_camcorder_unrealize(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_err(""); + + if(((mmf_camcorder_t *)camcorder)->sync_state_change) { + __ta__("_mmcamcorder_unrealize", + error = _mmcamcorder_unrealize(camcorder); + ); + } else { + /* After sending command, this function just return immediately. */ + error = _mmcamcorder_append_simple_command(camcorder, _MMCAMCORDER_CMD_UNREALIZE); + } + + _mmcam_dbg_err("END"); + + return error; +} + + +int mm_camcorder_start(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_err(""); + + if(((mmf_camcorder_t *)camcorder)->sync_state_change) { + __ta__("_mmcamcorder_start", + error = _mmcamcorder_start(camcorder); + ); + } else { + /* After sending command, this function just return immediately. */ + error = _mmcamcorder_append_simple_command(camcorder, _MMCAMCORDER_CMD_START); + } + + _mmcam_dbg_err("END"); + + return error; +} + + +int mm_camcorder_stop(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_err(""); + + if(((mmf_camcorder_t *)camcorder)->sync_state_change) { + __ta__("_mmcamcorder_stop", + error = _mmcamcorder_stop(camcorder); + ); + } else { + /* After sending command, this function just return immediately. */ + error = _mmcamcorder_append_simple_command(camcorder, _MMCAMCORDER_CMD_STOP); + } + + _mmcam_dbg_err("END"); + + return error; +} + + +int mm_camcorder_capture_start(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_err(""); + + __ta__("_mmcamcorder_capture_start", + error = _mmcamcorder_capture_start(camcorder); + ); + + _mmcam_dbg_err("END"); + + return error; +} + + +int mm_camcorder_capture_stop(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_err(""); + + __ta__("_mmcamcorder_capture_stop", + error = _mmcamcorder_capture_stop(camcorder); + ); + + _mmcam_dbg_err("END"); + + return error; +} + + +int mm_camcorder_record(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void*)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_err(""); + + __ta__("_mmcamcorder_record", + error = _mmcamcorder_record(camcorder); + ); + + _mmcam_dbg_err("END"); + + return error; +} + + +int mm_camcorder_pause(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_err(""); + + __ta__("_mmcamcorder_pause", + error = _mmcamcorder_pause(camcorder); + ); + + _mmcam_dbg_err("END"); + + return error; +} + + +int mm_camcorder_commit(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_err(""); + + MMTA_ACUM_ITEM_BEGIN("Real Commit Time", 0); + + if(((mmf_camcorder_t *)camcorder)->sync_state_change) { + __ta__("_mmcamcorder_stop", + error = _mmcamcorder_commit(camcorder); + ); + } else { + /* After sending command, this function just return immediately. */ + error = _mmcamcorder_append_simple_command(camcorder, _MMCAMCORDER_CMD_COMMIT); + } + + _mmcam_dbg_err("END"); + + return error; +} + + +int mm_camcorder_cancel(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_err(""); + + __ta__("_mmcamcorder_cancel", + error = _mmcamcorder_cancel(camcorder); + ); + + _mmcam_dbg_err("END"); + + return error; +} + + +int mm_camcorder_set_message_callback(MMHandleType camcorder, MMMessageCallback callback, void *user_data) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + error = _mmcamcorder_set_message_callback(camcorder, callback, user_data); + + return error; +} + + +int mm_camcorder_set_video_stream_callback(MMHandleType camcorder, mm_camcorder_video_stream_callback callback, void* user_data) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + error = _mmcamcorder_set_video_stream_callback(camcorder, callback, user_data); + + return error; +} + + +int mm_camcorder_set_audio_stream_callback(MMHandleType camcorder, mm_camcorder_audio_stream_callback callback, void* user_data) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + error = _mmcamcorder_set_audio_stream_callback(camcorder, callback, user_data); + + return error; +} + + +int mm_camcorder_set_video_capture_callback(MMHandleType camcorder, mm_camcorder_video_capture_callback callback, void* user_data) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT ); + + error = _mmcamcorder_set_video_capture_callback(camcorder, callback, user_data); + + return error; +} + + +int mm_camcorder_get_state(MMHandleType camcorder, MMCamcorderStateType *status) +{ + int ret = MM_ERROR_NONE; + + if (!camcorder) { + _mmcam_dbg_warn("Empty handle."); + return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + } + + *status = _mmcamcorder_get_state(camcorder); + + return ret; + +} + + +int mm_camcorder_get_attributes(MMHandleType camcorder, char **err_attr_name, const char *attribute_name, ...) +{ + va_list var_args; + int ret = MM_ERROR_NONE; + + return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); + + va_start(var_args, attribute_name); + ret = _mmcamcorder_get_attributes(camcorder, err_attr_name, attribute_name, var_args); + va_end (var_args); + + return ret; +} + + +int mm_camcorder_set_attributes(MMHandleType camcorder, char **err_attr_name, const char *attribute_name, ...) +{ + va_list var_args; + int ret = MM_ERROR_NONE; + + return_val_if_fail(attribute_name, MM_ERROR_COMMON_INVALID_ARGUMENT); + + va_start (var_args, attribute_name); + ret = _mmcamcorder_set_attributes(camcorder, err_attr_name, attribute_name, var_args); + va_end (var_args); + + return ret; +} + + +int mm_camcorder_get_attribute_info(MMHandleType camcorder, const char *attribute_name, MMCamAttrsInfo *info) +{ + return _mmcamcorder_get_attribute_info(camcorder, attribute_name, info); +} + + +int mm_camcorder_init_focusing(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + error = _mmcamcorder_init_focusing(camcorder); + + return error; +} + + +int mm_camcorder_start_focusing( MMHandleType camcorder ) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + /* TODO : Add direction parameter */ + + error = _mmcamcorder_adjust_focus(camcorder, MM_CAMCORDER_MF_LENS_DIR_FORWARD); + + return error; +} + + +int mm_camcorder_stop_focusing(MMHandleType camcorder) +{ + int error = MM_ERROR_NONE; + + mmf_return_val_if_fail((void *)camcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + error = _mmcamcorder_stop_focusing(camcorder); + + return error; +} + diff --git a/src/mm_camcorder_attribute.c b/src/mm_camcorder_attribute.c new file mode 100644 index 0000000..f9df6d7 --- /dev/null +++ b/src/mm_camcorder_attribute.c @@ -0,0 +1,3882 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include "mm_camcorder_internal.h" + +#include <gst/interfaces/colorbalance.h> +#include <gst/interfaces/cameracontrol.h> +#include <gst/interfaces/xoverlay.h> + + +/*--------------------------------------------------------------------------------------- +| 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, + MM_CAMCORDER_STROBE_MODE_ON, + MM_CAMCORDER_STROBE_MODE_AUTO, + MM_CAMCORDER_STROBE_MODE_REDEYE_REDUCTION, + MM_CAMCORDER_STROBE_MODE_SLOW_SYNC, + MM_CAMCORDER_STROBE_MODE_FRONT_CURTAIN, + MM_CAMCORDER_STROBE_MODE_REAR_CURTAIN, + MM_CAMCORDER_STROBE_MODE_PERMANENT}; + +int tag_enable_values[] = { 0, 1 }; + +int tag_orientation_values[] = +{ + 1, /*The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.*/ + 2, /*the 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.*/ + 3, /*the 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.*/ + 4, /*the 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.*/ + 5, /*the 0th row is the visual left-hand side of the image, and the 0th column is the visual top.*/ + 6, /*the 0th row is the visual right-hand side of the image, and the 0th column is the visual top.*/ + 7, /*the 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.*/ + 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 + { + MM_CAM_MODE, /* ID */ + "mode", /* Name */ + MMF_VALUE_TYPE_INT, /* Type */ + MM_ATTRS_FLAG_RW, /* Flag */ + (void*)MM_CAMCORDER_MODE_IMAGE, /* 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, ...) */ + NULL, /* Runtime setting function of the attribute */ + }, + // 1 + { + MM_CAM_AUDIO_DEVICE, + "audio-device", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_AUDIO_DEVICE_MIC, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + MM_AUDIO_DEVICE_NUM-1, + NULL, + }, + // 2 + { + MM_CAM_CAMERA_DEVICE, + "camera-device", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_VIDEO_DEVICE_NONE, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_VIDEO_DEVICE_NONE, + MM_VIDEO_DEVICE_NUM-1, + NULL, + }, + // 3 + { + MM_CAM_AUDIO_ENCODER, + "audio-encoder", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_AUDIO_CODEC_AMR, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + (int)NULL, + 0, + NULL, + }, + // 4 + { + MM_CAM_VIDEO_ENCODER, + "video-encoder", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_VIDEO_CODEC_MPEG4, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + (int)NULL, + 0, + NULL, + }, + //5 + { + MM_CAM_IMAGE_ENCODER, + "image-encoder", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_IMAGE_CODEC_JPEG, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + (int)NULL, + 0, + NULL, + }, + //6 + { + MM_CAM_FILE_FORMAT, + "file-format", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_FILE_FORMAT_MP4, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + (int)NULL, + 0, + NULL, + }, + //7 + { + MM_CAM_CAMERA_DEVICE_NAME, + "camera-device-name", + MMF_VALUE_TYPE_STRING, + MM_ATTRS_FLAG_RW, + (void*)NULL, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0, + NULL, + }, + //8 + { + MM_CAM_AUDIO_SAMPLERATE, + "audio-samplerate", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)8000, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + NULL, + }, + //9 + { + MM_CAM_AUDIO_FORMAT, + "audio-format", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + (int)depth, + ARRAY_SIZE(depth), + NULL, + }, + //10 + { + MM_CAM_AUDIO_CHANNEL, + "audio-channel", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)2, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 1, + 2, + NULL, + }, + //11 + { + MM_CAM_AUDIO_VOLUME, + "audio-volume", + MMF_VALUE_TYPE_DOUBLE, + MM_ATTRS_FLAG_RW, + (void*)1, + MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, + 0, + 10.0, + _mmcamcorder_commit_audio_volume, + }, + //12 + { + MM_CAM_AUDIO_INPUT_ROUTE, + "audio-input-route", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_AUDIOROUTE_USE_EXTERNAL_SETTING, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_AUDIOROUTE_USE_EXTERNAL_SETTING, + MM_AUDIOROUTE_CAPTURE_STEREOMIC_ONLY, + _mmcamcorder_commit_audio_input_route, + }, + //13 + { + MM_CAM_FILTER_SCENE_MODE, + "filter-scene-mode", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_filter_scene_mode, + }, + //14 + { + MM_CAM_FILTER_BRIGHTNESS, + "filter-brightness", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)1, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_filter, + }, + //15 + { + MM_CAM_FILTER_CONTRAST, + "filter-contrast", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_filter, + }, + //16 + { + MM_CAM_FILTER_WB, + "filter-wb", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_filter, + }, + //17 + { + MM_CAM_FILTER_COLOR_TONE, + "filter-color-tone", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_filter, + }, + //18 + { + MM_CAM_FILTER_SATURATION, + "filter-saturation", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_filter, + }, + //19 + { + MM_CAM_FILTER_HUE, + "filter-hue", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_filter, + }, + //20 + { + MM_CAM_FILTER_SHARPNESS, + "filter-sharpness", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_filter, + }, + //21 + { + MM_CAM_CAMERA_FORMAT, + "camera-format", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_PIXEL_FORMAT_YUYV, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + NULL, + }, + //22 + { + MM_CAM_CAMERA_SLOW_MOTION_FPS, + "camera-slow-motion-fps", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + NULL, + }, + //23 + { + MM_CAM_CAMERA_FPS, + "camera-fps", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)30, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_fps, + }, + //24 + { + MM_CAM_CAMERA_WIDTH, + "camera-width", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)320, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_width, + }, + //25 + { + MM_CAM_CAMERA_HEIGHT, + "camera-height", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)240, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_height, + }, + //26 + { + MM_CAM_CAMERA_DIGITAL_ZOOM, + "camera-digital-zoom", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)10, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_camera_zoom, + }, + //27 + { + MM_CAM_CAMERA_OPTICAL_ZOOM, + "camera-optical-zoom", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_camera_zoom, + }, + //28 + { + MM_CAM_CAMERA_FOCUS_MODE, + "camera-focus-mode", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_CAMCORDER_FOCUS_MODE_NONE, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_focus_mode, + }, + //29 + { + MM_CAM_CAMERA_AF_SCAN_RANGE, + "camera-af-scan-range", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_af_scan_range, + }, + //30 + { + MM_CAM_CAMERA_EXPOSURE_MODE, + "camera-exposure-mode", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_capture_mode, + }, + //31 + { + MM_CAM_CAMERA_EXPOSURE_VALUE, + "camera-exposure-value", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_camera_capture_mode, + }, + //32 + { + MM_CAM_CAMERA_F_NUMBER, + "camera-f-number", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_capture_mode, + }, + //33 + { + MM_CAM_CAMERA_SHUTTER_SPEED, + "camera-shutter-speed", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_capture_mode, + }, + //34 + { + MM_CAM_CAMERA_ISO, + "camera-iso", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_capture_mode, + }, + //35 + { + MM_CAM_CAMERA_WDR, + "camera-wdr", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_wdr, + }, + //36 + { + MM_CAM_CAMERA_ANTI_HANDSHAKE, + "camera-anti-handshake", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_camera_anti_handshake, + }, + //37 + { + MM_CAM_CAMERA_FPS_AUTO, + "camera-fps-auto", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)FALSE, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 1, + NULL, + }, + //38 + { + MM_CAM_CAMERA_HOLD_AF_AFTER_CAPTURING, + "camera-hold-af-after-capturing", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 1, + _mmcamcorder_commit_camera_hold_af_after_capturing, + }, + //39 + { + MM_CAM_CAMERA_DELAY_ATTR_SETTING, + "camera-delay-attr-setting", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)FALSE, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 1, + NULL, + }, + //40 + { + MM_CAM_AUDIO_ENCODER_BITRATE, + "audio-encoder-bitrate", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + NULL, + }, + //41 + { + MM_CAM_VIDEO_ENCODER_BITRATE, + "video-encoder-bitrate", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + NULL, + }, + //42 + { + MM_CAM_IMAGE_ENCODER_QUALITY, + "image-encoder-quality", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)95, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_image_encoder_quality, + }, + //43 + { + MM_CAM_CAPTURE_FORMAT, + "capture-format", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_PIXEL_FORMAT_ENCODED, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + NULL, + }, + //44 + { + MM_CAM_CAPTURE_WIDTH, + "capture-width", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)1600, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_capture_width , + }, + //45 + { + MM_CAM_CAPTURE_HEIGHT, + "capture-height", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)1200, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_capture_height, + }, + //46 + { + MM_CAM_CAPTURE_COUNT, + "capture-count", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)1, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_capture_count, + }, + //47 + { + MM_CAM_CAPTURE_INTERVAL, + "capture-interval", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + NULL, + }, + //48 + { + MM_CAM_CAPTURE_BREAK_CONTINUOUS_SHOT, + "capture-break-cont-shot", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)FALSE, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 1, + _mmcamcorder_commit_capture_break_cont_shot, + }, + //49 + { + MM_CAM_DISPLAY_HANDLE, + "display-handle", + MMF_VALUE_TYPE_DATA, + MM_ATTRS_FLAG_RW, + (void*)NULL, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0, + _mmcamcorder_commit_display_handle, + }, + //50 + { + MM_CAM_DISPLAY_DEVICE, + "display-device", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_DISPLAY_DEVICE_MAINLCD, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + NULL, + }, + //51 + { + MM_CAM_DISPLAY_SURFACE, + "display-surface", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_DISPLAY_SURFACE_X, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + NULL, + }, + //52 + { + MM_CAM_DISPLAY_RECT_X, + "display-rect-x", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + _mmcamcorder_commit_display_rect, + }, + //53 + { + MM_CAM_DISPLAY_RECT_Y, + "display-rect-y", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + _mmcamcorder_commit_display_rect, + }, + //54 + { + MM_CAM_DISPLAY_RECT_WIDTH, + "display-rect-width", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + _mmcamcorder_commit_display_rect, + }, + //55 + { + MM_CAM_DISPLAY_RECT_HEIGHT, + "display-rect-height", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + _mmcamcorder_commit_display_rect, + }, + //56 + { + MM_CAM_DISPLAY_SOURCE_X, + "display-src-x", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + NULL, + }, + //57 + { + MM_CAM_DISPLAY_SOURCE_Y, + "display-src-y", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + NULL, + }, + //58 + { + MM_CAM_DISPLAY_SOURCE_WIDTH, + "display-src-width", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + NULL, + }, + //59 + { + MM_CAM_DISPLAY_SOURCE_HEIGHT, + "display-src-height", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + NULL, + }, + //60 + { + MM_CAM_DISPLAY_ROTATION, + "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), + _mmcamcorder_commit_display_rotation, + }, + //61 + { + MM_CAM_DISPLAY_VISIBLE, + "display-visible", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)1, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + (int)visible_values, + ARRAY_SIZE(visible_values), + _mmcamcorder_commit_display_visible, + }, + //62 + { + MM_CAM_DISPLAY_SCALE, + "display-scale", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_DISPLAY_SCALE_DEFAULT, + MM_DISPLAY_SCALE_TRIPLE_LENGTH, + _mmcamcorder_commit_display_scale, + }, + //63 + { + MM_CAM_DISPLAY_GEOMETRY_METHOD, + "display-geometry-method", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_DISPLAY_METHOD_LETTER_BOX, + MM_DISPLAY_METHOD_CUSTOM_ROI, + _mmcamcorder_commit_display_geometry_method, + }, + //64 + { + MM_CAM_TARGET_FILENAME, + "target-filename", + MMF_VALUE_TYPE_STRING, + MM_ATTRS_FLAG_RW, + (void*)"/tmp/CAM-NONAME", + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0, + _mmcamcorder_commit_target_filename, + }, + //65 + { + MM_CAM_TARGET_MAX_SIZE, + "target-max-size", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + NULL, + }, + //66 + { + MM_CAM_TARGET_TIME_LIMIT, + "target-time-limit", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + NULL, + }, + //67 + { + MM_CAM_TAG_ENABLE, + "tag-enable", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, +// (void*)tag_enable_values[0], + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 1, + NULL, + }, + //68 + { + MM_CAM_TAG_IMAGE_DESCRIPTION, + "tag-image-description", + MMF_VALUE_TYPE_STRING, + MM_ATTRS_FLAG_RW, + (void*)NULL, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0, + NULL, + }, + //69 + { + MM_CAM_TAG_ORIENTATION, + "tag-orientation", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, +// (void*)tag_orientation_values[0], + (void*)1, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + (int)tag_orientation_values, + ARRAY_SIZE(tag_orientation_values), + NULL, + }, + //70 + { + MM_CAM_TAG_SOFTWARE, + "tag-software", + MMF_VALUE_TYPE_STRING, + MM_ATTRS_FLAG_RW, + (void*)NULL, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0, + NULL, + }, + //71 + { + MM_CAM_TAG_LATITUDE, + "tag-latitude", + MMF_VALUE_TYPE_DOUBLE, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, + -360, + 360, + NULL, + }, + //72 + { + MM_CAM_TAG_LONGITUDE, + "tag-longitude", + MMF_VALUE_TYPE_DOUBLE, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, + -360, + 360, + NULL, + }, + //73 + { + MM_CAM_TAG_ALTITUDE, + "tag-altitude", + MMF_VALUE_TYPE_DOUBLE, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, + -999999, + 999999, + NULL, + }, + //74 + { + MM_CAM_STROBE_CONTROL, + "strobe-control", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_strobe, + }, + //75 + { + MM_CAM_STROBE_CAPABILITIES, + "strobe-capabilities", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_strobe, + }, + //76 + { + MM_CAM_STROBE_MODE, + "strobe-mode", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + (int)strobe_mode, + ARRAY_SIZE(strobe_mode), + _mmcamcorder_commit_strobe, + }, + //77 + { + MM_CAM_DETECT_MODE, + "detect-mode", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_detect, + }, + //78 + { + MM_CAM_DETECT_NUMBER, + "detect-number", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_detect, + }, + //79 + { + MM_CAM_DETECT_FOCUS_SELECT, + "detect-focus-select", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_detect, + }, + //80 + { + MM_CAM_DETECT_SELECT_NUMBER, + "detect-select-number", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + -1, + _mmcamcorder_commit_detect, + }, + //81 + { + MM_CAM_DETECT_STATUS, + "detect-status", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_ARRAY, + 0, + 0, + _mmcamcorder_commit_detect, + }, + //82 + { + MM_CAM_CAPTURE_ZERO_SYSTEMLAG, + "capture-zero-systemlag", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)FALSE, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 1, + NULL, + }, + //83 + { + MM_CAM_CAMERA_AF_TOUCH_X, + "camera-af-touch-x", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + _mmcamcorder_commit_camera_af_touch_area, + }, + //84 + { + MM_CAM_CAMERA_AF_TOUCH_Y, + "camera-af-touch-y", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + _mmcamcorder_commit_camera_af_touch_area, + }, + //85 + { + MM_CAM_CAMERA_AF_TOUCH_WIDTH, + "camera-af-touch-width", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + _mmcamcorder_commit_camera_af_touch_area, + }, + //86 + { + MM_CAM_CAMERA_AF_TOUCH_HEIGHT, + "camera-af-touch-height", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + _MMCAMCORDER_MAX_INT, + _mmcamcorder_commit_camera_af_touch_area, + }, + //87 + { + MM_CAM_CAMERA_FOCAL_LENGTH, + "camera-focal-length", + MMF_VALUE_TYPE_DOUBLE, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_DOUBLE_RANGE, + 0, + 1000, + _mmcamcorder_commit_camera_capture_mode, + }, + //88 + { + MM_CAM_RECOMMEND_PREVIEW_FORMAT_FOR_CAPTURE, + "recommend-preview-format-for-capture", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_PIXEL_FORMAT_YUYV, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_PIXEL_FORMAT_NV12, + MM_PIXEL_FORMAT_ENCODED, + NULL, + }, + //89 + { + MM_CAM_RECOMMEND_PREVIEW_FORMAT_FOR_RECORDING, + "recommend-preview-format-for-recording", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_PIXEL_FORMAT_NV12, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_PIXEL_FORMAT_NV12, + MM_PIXEL_FORMAT_ENCODED, + NULL, + }, + //90 + { + MM_CAM_CAPTURE_THUMBNAIL, + "capture-thumbnail", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)TRUE, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0, + NULL, + }, + //91 + { + MM_CAM_TAG_GPS_ENABLE, + "tag-gps-enable", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)TRUE, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 1, + NULL, + }, + //92 + { + MM_CAM_TAG_GPS_TIME_STAMP, + "tag-gps-time-stamp", + MMF_VALUE_TYPE_DOUBLE, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0, + NULL, + }, + //93 + { + MM_CAM_TAG_GPS_DATE_STAMP, + "tag-gps-date-stamp", + MMF_VALUE_TYPE_STRING, + MM_ATTRS_FLAG_RW, + NULL, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0, + NULL, + }, + //94 + { + MM_CAM_TAG_GPS_PROCESSING_METHOD, + "tag-gps-processing-method", + MMF_VALUE_TYPE_STRING, + MM_ATTRS_FLAG_RW, + NULL, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0, + NULL, + }, + //95 + { + MM_CAM_CAMERA_ROTATION, + "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), + _mmcamcorder_commit_camera_rotate, + }, + //96 + { + MM_CAM_ENABLE_CONVERTED_STREAM_CALLBACK, + "enable-converted-stream-callback", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)0, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 1, + NULL, + }, + //97 + { + MM_CAM_CAPTURED_SCREENNAIL, + "captured-screennail", + MMF_VALUE_TYPE_DATA, + MM_ATTRS_FLAG_RW, + (void*)NULL, + MM_ATTRS_VALID_TYPE_NONE, + 0, + 0, + NULL, + }, + //98 + { + MM_CAM_CAPTURE_SOUND_ENABLE, + "capture-sound-enable", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)FALSE, + MM_ATTRS_VALID_TYPE_INT_RANGE, + 0, + 1, + NULL, + }, + //99 + { + MM_CAM_RECOMMEND_DISPLAY_ROTATION, + "recommend-display-rotation", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_DISPLAY_ROTATION_270, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_DISPLAY_ROTATION_NONE, + MM_DISPLAY_ROTATION_FLIP_VERT, + NULL, + }, + //100 + { + MM_CAM_CAMCORDER_ROTATION, + "camcorder-rotation", + MMF_VALUE_TYPE_INT, + MM_ATTRS_FLAG_RW, + (void*)MM_VIDEO_INPUT_ROTATION_NONE, + MM_ATTRS_VALID_TYPE_INT_RANGE, + MM_VIDEO_INPUT_ROTATION_NONE, + MM_VIDEO_INPUT_ROTATION_270, + _mmcamcorder_commit_camcorder_rotate, + }, +}; + + +/*--------------------------------------------------------------------------- +| 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, + MM_CAM_CAMERA_DEVICE_NAME, + MM_CAM_CAMERA_SHUTTER_SPEED, + MM_CAM_RECOMMEND_PREVIEW_FORMAT_FOR_CAPTURE, + MM_CAM_RECOMMEND_PREVIEW_FORMAT_FOR_RECORDING, + MM_CAM_CAPTURED_SCREENNAIL, + MM_CAM_RECOMMEND_DISPLAY_ROTATION, +}; + +/*--------------------------------------------------------------------------- +| 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 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: | +---------------------------------------------------------------------------*/ +MMHandleType +_mmcamcorder_alloc_attribute( MMHandleType handle, MMCamPreset *info ) +{ + _mmcam_dbg_log( "" ); + + MMHandleType attrs = 0; + 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; + } + + //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." ); + 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?" ); + 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; + } + + /* Camcorder Attributes */ + _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 ); + + free(attrs_const_info); + attrs_const_info = NULL; + + if( attrs == 0 ) + { + _mmcam_dbg_err( "Fail to alloc attribute handle" ); + return 0; + } + + __mmcamcorder_set_conf_to_valid_info(handle); + + for (idx = 0; idx < attr_count; idx++) + { +/* _mmcam_dbg_log("Valid type [%s:%d, %d, %d]", cam_attrs_const_info[idx].name, cam_attrs_const_info[idx].validity_type + , cam_attrs_const_info[idx].validity_value1, cam_attrs_const_info[idx].validity_value2); +*/ + mmf_attrs_set_valid_type (attrs, idx, cam_attrs_const_info[idx].validity_type); + + 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); + 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); + 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); + 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); + break; + case MM_ATTRS_VALID_TYPE_NONE: + break; + case MM_ATTRS_VALID_TYPE_INVALID: + default: + _mmcam_dbg_err("Valid type error."); + break; + } + } + + return attrs; +} + + +void +_mmcamcorder_dealloc_attribute(MMHandleType attrs) +{ + _mmcam_dbg_log(""); + + if (attrs) + { + mmf_attrs_free(attrs); + + _mmcam_dbg_log("released attribute"); + } +} + + +int +_mmcamcorder_get_attributes(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list var_args) +{ + MMHandleType attrs = 0; + int ret = MM_ERROR_NONE; + + mmf_return_val_if_fail( handle, MM_ERROR_CAMCORDER_INVALID_ARGUMENT ); +// mmf_return_val_if_fail( err_attr_name, MM_ERROR_CAMCORDER_INVALID_ARGUMENT ); + + 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); + + return ret; +} + + +int +_mmcamcorder_set_attributes(MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list var_args) +{ + MMHandleType attrs = 0; + int ret = MM_ERROR_NONE; + + mmf_return_val_if_fail( handle, MM_ERROR_CAMCORDER_INVALID_ARGUMENT ); +// mmf_return_val_if_fail( err_attr_name, MM_ERROR_CAMCORDER_INVALID_ARGUMENT ); + + attrs = MMF_CAMCORDER_ATTRS(handle); + mmf_return_val_if_fail( attrs, MM_ERROR_CAMCORDER_NOT_INITIALIZED ); + + __ta__( "__mmcamcorder_check_valid_pair", + 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); + } + + return ret; +} + + +int +_mmcamcorder_get_attribute_info(MMHandleType handle, const char *attr_name, MMCamAttrsInfo *info) +{ + MMHandleType attrs = 0; + MMAttrsInfo attrinfo; + int ret = MM_ERROR_NONE; + + mmf_return_val_if_fail( handle, MM_ERROR_CAMCORDER_INVALID_ARGUMENT ); + 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); + mmf_return_val_if_fail( attrs, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + ret = mm_attrs_get_info_by_name(attrs, attr_name, (MMAttrsInfo*)&attrinfo); + + if (ret == MM_ERROR_NONE) + { + memset(info, 0x00, sizeof(MMCamAttrsInfo)); + info->type = attrinfo.type; + info->flag = attrinfo.flag; + info->validity_type= attrinfo.validity_type; + + switch(attrinfo.validity_type) + { + case MM_ATTRS_VALID_TYPE_INT_ARRAY: + info->int_array.array = attrinfo.int_array.array; + info->int_array.count = attrinfo.int_array.count; + info->int_array.def = 0; + 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; + 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; + 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; + break; + case MM_ATTRS_VALID_TYPE_NONE: + break; + case MM_ATTRS_VALID_TYPE_INVALID: + default: + break; + } + } + + return ret; +} + + +//attribute commiter +void +__mmcamcorder_print_attrs (const char *attr_name, const mmf_value_t *value, char* cmt_way) +{ + switch(value->type) + { + case MMF_VALUE_TYPE_INT: + _mmcam_dbg_log("%s :(%s:%d)", cmt_way, attr_name, value->value.i_val); + break; + case MMF_VALUE_TYPE_DOUBLE: + _mmcam_dbg_log("%s :(%s:%f)", cmt_way, attr_name, value->value.d_val); + break; + case MMF_VALUE_TYPE_STRING: + _mmcam_dbg_log("%s :(%s:%s)", cmt_way, attr_name, value->value.s_val); + break; + case MMF_VALUE_TYPE_DATA: + _mmcam_dbg_log("%s :(%s:%p)", cmt_way, attr_name, value->value.p_val); + break; + } + + return; +} + +bool +_mmcamcorder_commit_camcorder_attrs (int attr_idx, const char *attr_name, const mmf_value_t *value, void *commit_param) +{ + bool bret = FALSE; + + mmf_return_val_if_fail(commit_param, FALSE); + mmf_return_val_if_fail(attr_idx >= 0, FALSE); + mmf_return_val_if_fail(attr_name, FALSE); + mmf_return_val_if_fail(value, FALSE); + + if (cam_attrs_const_info[attr_idx].attr_commit) + { +// _mmcam_dbg_log("Dynamic commit:(%s)", attr_name); + __mmcamcorder_print_attrs(attr_name, value, "Dynamic"); + bret = cam_attrs_const_info[attr_idx].attr_commit((MMHandleType)commit_param, attr_idx, value); + } + else + { +// _mmcam_dbg_log("Static commit:(%s)", attr_name); + __mmcamcorder_print_attrs(attr_name, value, "Static"); + bret = TRUE; + } + + return bret; +} + + +int +__mmcamcorder_set_conf_to_valid_info(MMHandleType handle) +{ + //mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + int *format = NULL; + int total_count = 0; + + /* Audio encoder */ + total_count = _mmcamcorder_get_available_format(handle, CONFIGURE_CATEGORY_MAIN_AUDIO_ENCODER, &format); + cam_attrs_const_info[MM_CAM_AUDIO_ENCODER].validity_value1 = (int)format; + cam_attrs_const_info[MM_CAM_AUDIO_ENCODER].validity_value2 = (int)total_count; + + /* Video encoder */ + total_count = _mmcamcorder_get_available_format(handle, CONFIGURE_CATEGORY_MAIN_VIDEO_ENCODER, &format); + cam_attrs_const_info[MM_CAM_VIDEO_ENCODER].validity_value1 = (int)format; + cam_attrs_const_info[MM_CAM_VIDEO_ENCODER].validity_value2 = (int)total_count; + + /* Image encoder */ + total_count = _mmcamcorder_get_available_format(handle, CONFIGURE_CATEGORY_MAIN_IMAGE_ENCODER, &format); + cam_attrs_const_info[MM_CAM_IMAGE_ENCODER].validity_value1 = (int)format; + cam_attrs_const_info[MM_CAM_IMAGE_ENCODER].validity_value2 = (int)total_count; + + /* File format */ + total_count = _mmcamcorder_get_available_format(handle, CONFIGURE_CATEGORY_MAIN_MUX, &format); + cam_attrs_const_info[MM_CAM_FILE_FORMAT].validity_value1 = (int)format; + cam_attrs_const_info[MM_CAM_FILE_FORMAT].validity_value2 = (int)total_count; + + return MM_ERROR_NONE; +} + + +bool _mmcamcorder_commit_capture_width (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + MMHandleType attr = 0; + int current_state = MM_CAMCORDER_STATE_NONE; + + attr = MMF_CAMCORDER_ATTRS(handle); + mmf_return_val_if_fail(attr, FALSE); + + _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 ) ) + { + int flags = MM_ATTRS_FLAG_NONE; + int capture_width, capture_height; + MMCamAttrsInfo info; + + mm_camcorder_get_attribute_info(handle, MMCAM_CAPTURE_HEIGHT, &info); + flags = info.flag; + + if (!(flags & MM_ATTRS_FLAG_MODIFIED)) + { + mm_camcorder_get_attributes(handle, NULL, MMCAM_CAPTURE_HEIGHT, &capture_height, NULL); + capture_width = value->value.i_val; + + /* Check whether they are valid pair */ + return __mmcamcorder_set_capture_resolution(handle, capture_width, capture_height); + } + + return TRUE; + } + else + { + _mmcam_dbg_log("Capture resolution can't be set.(state=%d)", current_state); + return FALSE; + } +} + + +bool _mmcamcorder_commit_capture_height (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_NULL + || current_state == MM_CAMCORDER_STATE_READY + || 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 + { + _mmcam_dbg_log("Capture resolution can't be set.(state=%d)", current_state); + return FALSE; + } +} + + +bool _mmcamcorder_commit_capture_break_cont_shot (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + int current_state = _mmcamcorder_get_state( handle); + int ivalue = value->value.i_val; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + GstCameraControl *control = NULL; + type_element *VideosrcElement = NULL; + + 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 ); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + return TRUE; + + if( ivalue && current_state == MM_CAMCORDER_STATE_CAPTURING ) + { + if( !strcmp( videosrc_name, "avsysvideosrc" ) || !strcmp( videosrc_name, "camerasrc" ) ) + { + 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; + } + + control = GST_CAMERA_CONTROL( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst ); + + gst_camera_control_set_capture_command( control, GST_CAMERA_CONTROL_CAPTURE_COMMAND_STOP_MULTISHOT ); + + _mmcam_dbg_warn( "Commit Break continuous shot : Set command OK. current state[%d]", current_state ); + } + else + { + _mmcam_dbg_warn( "Another videosrc plugin[%s] is not supported yet.", videosrc_name ); + } + } + else + { + _mmcam_dbg_warn( "Commit Break continuous shot : No effect. value[%d],current state[%d]", ivalue, current_state ); + } + + return TRUE; +} + + +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; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + mmf_return_val_if_fail(hcamcorder, FALSE); + + cap_count = value->value.i_val; + + 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("Capture Count(%d)", cap_count); + + return TRUE; +} + + +bool _mmcamcorder_commit_audio_volume (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + int current_state = MM_CAMCORDER_STATE_NONE; + _MMCamcorderSubContext *sc = NULL; + bool bret = FALSE; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + return TRUE; + + current_state = _mmcamcorder_get_state( handle); + + if ((current_state == MM_CAMCORDER_STATE_RECORDING)||(current_state == MM_CAMCORDER_STATE_PAUSED)) + { + double mslNewVal = 0; + mslNewVal = value->value.d_val; + + if (sc->element[_MMCAMCORDER_AUDIOSRC_VOL].gst) + { + if(mslNewVal == 0.0) + { + //Because data probe of audio src do the same job, it doesn't need to set mute here. Already null raw data. +// MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_AUDIOSRC_VOL].gst, "mute", TRUE); + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_AUDIOSRC_VOL].gst, "volume", 1.0); + } + else + { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_AUDIOSRC_VOL].gst, "mute", FALSE); + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_AUDIOSRC_VOL].gst, "volume", mslNewVal); + } + } + + _mmcam_dbg_log("Commit : volume(%f)", mslNewVal); + bret = TRUE; + } + else + { + _mmcam_dbg_log("Commit : nothing to commit. status(%d)", current_state); + bret = TRUE; + } + return bret; + +} + + +bool _mmcamcorder_commit_camera_fps (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + _mmcam_dbg_log("FPS(%d)", value->value.i_val); + return TRUE; +} + + +bool _mmcamcorder_commit_camera_width (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + MMHandleType attr = 0; + int current_state = MM_CAMCORDER_STATE_NONE; + int width, height; + + attr = MMF_CAMCORDER_ATTRS(handle); + mmf_return_val_if_fail(attr, FALSE); + + _mmcam_dbg_log("Width(%d)", value->value.i_val); + + current_state = _mmcamcorder_get_state( handle); + + if ((current_state > MM_CAMCORDER_STATE_READY) || _mmcamcorder_is_state_changing( handle ) ) { + _mmcam_dbg_log("Resolution can't be changed.(state=%d)", current_state); + return FALSE; + } else { + int flags = MM_ATTRS_FLAG_NONE; + MMCamAttrsInfo info; + mm_camcorder_get_attribute_info(handle, MMCAM_CAMERA_HEIGHT, &info); + flags = info.flag; + + if (!(flags & MM_ATTRS_FLAG_MODIFIED)) { + mm_camcorder_get_attributes(handle, NULL, MMCAM_CAMERA_HEIGHT, &height, NULL); + width = value->value.i_val; + //This means that width is changed while height isn't changed. So call _mmcamcorder_commit_camera_height forcely. + _mmcam_dbg_log("Call _mmcamcorder_commit_camera_height"); + return __mmcamcorder_set_camera_resolution(handle, width, height); + } + return TRUE; + } +} + + +bool _mmcamcorder_commit_camera_height (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + int width, height; + int current_state = MM_CAMCORDER_STATE_NONE; + MMHandleType attr = 0; + + attr = MMF_CAMCORDER_ATTRS(handle); + mmf_return_val_if_fail(attr, FALSE); + + _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 )) { + _mmcam_dbg_log("Resolution can't be changed.(state=%d)", current_state); + return FALSE; + } else { + height = value->value.i_val; + mm_camcorder_get_attributes(handle, NULL, MMCAM_CAMERA_WIDTH, &width, NULL); + return __mmcamcorder_set_camera_resolution(handle, width, height); + } +} + + +bool _mmcamcorder_commit_camera_zoom (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + _MMCamcorderSubContext *sc = NULL; + int current_state = MM_CAMCORDER_STATE_NONE; + GstCameraControl *control = NULL; + int zoom_level = value->value.i_val; + int zoom_type; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, TRUE); + + _mmcam_dbg_log("(%d)", attr_idx); + + current_state = _mmcamcorder_get_state(handle); + + if (current_state < MM_CAMCORDER_STATE_PREPARE) { + return TRUE; + } + + if (attr_idx == MM_CAM_CAMERA_OPTICAL_ZOOM) { + zoom_type = GST_CAMERA_CONTROL_OPTICAL_ZOOM; + } else { + zoom_type = GST_CAMERA_CONTROL_DIGITAL_ZOOM; + } + + if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) { + int ret = FALSE; + + 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); + + __ta__(" gst_camera_control_set_zoom", + ret = gst_camera_control_set_zoom(control, zoom_type, zoom_level); + ); + + if (ret) { + _mmcam_dbg_log("Succeed in operating Zoom[%d].", zoom_level); + return TRUE; + } else { + _mmcam_dbg_warn("Failed to operate Zoom. Type[%d],Level[%d]", zoom_type, zoom_level); + } + } else { + _mmcam_dbg_log("pointer of video src is null"); + } + + return FALSE; +} + + +bool _mmcamcorder_commit_camera_focus_mode (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + MMHandleType attr = 0; + int current_state = MM_CAMCORDER_STATE_NONE; + _MMCamcorderSubContext *sc = NULL; + GstCameraControl *control = NULL; + int mslVal; + int mode, cur_focus_mode, cur_focus_range; + + attr = MMF_CAMCORDER_ATTRS(handle); + mmf_return_val_if_fail(attr, FALSE); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + return TRUE; + + _mmcam_dbg_log("Focus mode(%d)", value->value.i_val); + + current_state = _mmcamcorder_get_state( handle); + + if (current_state < MM_CAMCORDER_STATE_READY) { + _mmcam_dbg_log("Focus mode will be changed later.(state=%d)", current_state); + return TRUE; + } + + if( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst ) + { + int flags = MM_ATTRS_FLAG_NONE; + MMCamAttrsInfo info; + + 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); + + mslVal = value->value.i_val; + mode = _mmcamcorder_convert_msl_to_sensor( attr_idx, mslVal ); + + mm_camcorder_get_attribute_info(handle, MMCAM_CAMERA_AF_SCAN_RANGE, &info); + flags = info.flag; + + if (!(flags & MM_ATTRS_FLAG_MODIFIED)) + { + if( gst_camera_control_get_focus( control, &cur_focus_mode, &cur_focus_range ) ) + { + if( mode != cur_focus_mode ) + { + MMTA_ACUM_ITEM_BEGIN(" gst_camera_control_set_focus", 0); + 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 ); + return TRUE; + } + else + { + _mmcam_dbg_warn( "Failed to set AF mode[%d]", mslVal ); + } + MMTA_ACUM_ITEM_END(" gst_camera_control_set_focus", 0); + } + else + { + //_mmcam_dbg_log( "No need to set AF mode. Current[%d]", mslVal ); + return TRUE; + } + } + else + { + _mmcam_dbg_warn( "Failed to get AF mode, so do not set new AF mode[%d]", mslVal ); + } + } + } + else + { + _mmcam_dbg_log("pointer of video src is null"); + } + return TRUE; +} + + +bool _mmcamcorder_commit_camera_af_scan_range (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + _MMCamcorderSubContext *sc = NULL; + GstCameraControl *control = NULL; + int current_state = MM_CAMCORDER_STATE_NONE; + int mslVal, newVal; + int cur_focus_mode = 0; + int cur_focus_range = 0; + int msl_mode = MM_CAMCORDER_FOCUS_MODE_NONE; + int converted_mode = 0; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + return TRUE; + + _mmcam_dbg_log("(%d)", attr_idx); + + current_state = _mmcamcorder_get_state( handle); + + mslVal = value->value.i_val; + newVal = _mmcamcorder_convert_msl_to_sensor( attr_idx, mslVal ); + + 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)) + { + _mmcam_dbg_log("Can't cast Video source into camera control."); + 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 ); + + if( gst_camera_control_get_focus( control, &cur_focus_mode, &cur_focus_range ) ) + { + + if (( newVal != cur_focus_range ) || ( converted_mode != cur_focus_mode )) + { + MMTA_ACUM_ITEM_BEGIN(" gst_camera_control_set_focus", 0); + if( gst_camera_control_set_focus( control, converted_mode, newVal ) ) + { + MMTA_ACUM_ITEM_END(" gst_camera_control_set_focus", 0); + //_mmcam_dbg_log( "Succeed in setting AF mode[%d]", mslVal ); + return TRUE; + } + else + { + MMTA_ACUM_ITEM_END(" gst_camera_control_set_focus", 0); + _mmcam_dbg_warn( "Failed to set AF mode[%d]", mslVal ); + } + } + else + { + //_mmcam_dbg_log( "No need to set AF mode. Current[%d]", mslVal ); + return TRUE; + } + } + else + { + _mmcam_dbg_warn( "Failed to get AF mode, so do not set new AF mode[%d]", mslVal ); + } + } + else + { + _mmcam_dbg_log("pointer of video src is null"); + } + return FALSE; +} + +bool _mmcamcorder_commit_camera_af_touch_area (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + _MMCamcorderSubContext *sc = NULL; + GstCameraControl *control = NULL; + GstCameraControlRectType set_area = { 0, 0, 0, 0 }, get_area = { 0, 0, 0, 0 }; + + int current_state = MM_CAMCORDER_STATE_NONE; + int ret = FALSE; + int focus_mode = MM_CAMCORDER_FOCUS_MODE_NONE; + + gboolean do_set = FALSE; + + MMCamAttrsInfo info_y, info_w, info_h; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + return TRUE; + + _mmcam_dbg_log("(%d)", attr_idx); + + 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; + } + + ret = mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAMERA_FOCUS_MODE, &focus_mode, + NULL); + if( ret != MM_ERROR_NONE ) + { + _mmcam_dbg_warn( "Failed to get FOCUS MODE.[%x]", ret ); + return FALSE; + } + + if ((focus_mode != MM_CAMCORDER_FOCUS_MODE_TOUCH_AUTO ) && (focus_mode != MM_CAMCORDER_FOCUS_MODE_CONTINUOUS)) + { + _mmcam_dbg_warn( "Focus mode is NOT TOUCH AUTO or CONTINUOUS(current[%d]). return FALSE", focus_mode ); + 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; + } + + switch( attr_idx ) + { + case MM_CAM_CAMERA_AF_TOUCH_X: + mm_camcorder_get_attribute_info(handle, MMCAM_CAMERA_AF_TOUCH_Y, &info_y); + mm_camcorder_get_attribute_info(handle, MMCAM_CAMERA_AF_TOUCH_WIDTH, &info_w); + mm_camcorder_get_attribute_info(handle, MMCAM_CAMERA_AF_TOUCH_HEIGHT, &info_h); + if( !( (info_y.flag|info_w.flag|info_h.flag) & MM_ATTRS_FLAG_MODIFIED) ) + { + set_area.x = value->value.i_val; + mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAMERA_AF_TOUCH_Y, &set_area.y, + MMCAM_CAMERA_AF_TOUCH_WIDTH, &set_area.width, + MMCAM_CAMERA_AF_TOUCH_HEIGHT, &set_area.height, + NULL); + do_set = TRUE; + } + else + { + _mmcam_dbg_log( "Just store AF area[x:%d]", value->value.i_val ); + return TRUE; + } + break; + case MM_CAM_CAMERA_AF_TOUCH_Y: + mm_camcorder_get_attribute_info(handle, MMCAM_CAMERA_AF_TOUCH_WIDTH, &info_w); + mm_camcorder_get_attribute_info(handle, MMCAM_CAMERA_AF_TOUCH_HEIGHT, &info_h); + if( !( (info_w.flag|info_h.flag) & MM_ATTRS_FLAG_MODIFIED) ) + { + set_area.y = value->value.i_val; + mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAMERA_AF_TOUCH_X, &set_area.x, + MMCAM_CAMERA_AF_TOUCH_WIDTH, &set_area.width, + MMCAM_CAMERA_AF_TOUCH_HEIGHT, &set_area.height, + NULL); + do_set = TRUE; + } + else + { + _mmcam_dbg_log( "Just store AF area[y:%d]", value->value.i_val ); + return TRUE; + } + break; + case MM_CAM_CAMERA_AF_TOUCH_WIDTH: + mm_camcorder_get_attribute_info(handle, MMCAM_CAMERA_AF_TOUCH_HEIGHT, &info_h); + if( !( info_h.flag & MM_ATTRS_FLAG_MODIFIED) ) + { + set_area.width = value->value.i_val; + mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAMERA_AF_TOUCH_X, &set_area.x, + MMCAM_CAMERA_AF_TOUCH_Y, &set_area.y, + MMCAM_CAMERA_AF_TOUCH_HEIGHT, &set_area.height, + NULL); + do_set = TRUE; + } + else + { + _mmcam_dbg_log( "Just store AF area[width:%d]", value->value.i_val ); + return TRUE; + } + break; + case MM_CAM_CAMERA_AF_TOUCH_HEIGHT: + set_area.height = value->value.i_val; + mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAMERA_AF_TOUCH_X, &set_area.x, + MMCAM_CAMERA_AF_TOUCH_Y, &set_area.y, + MMCAM_CAMERA_AF_TOUCH_WIDTH, &set_area.width, + NULL); + do_set = TRUE; + break; + default: + break; + } + + if( do_set ) + { + control = GST_CAMERA_CONTROL (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); + + __ta__( " gst_camera_control_get_focus_area", + ret = gst_camera_control_get_auto_focus_area( control, &get_area ); + ); + if( !ret ) + { + _mmcam_dbg_warn( "Failed to get AF area" ); + return FALSE; + } + + if( get_area.x == set_area.x && get_area.y == set_area.y ) + // width and height are not supported now. + // get_area.width == set_area.width && get_area.height == set_area.height + { + _mmcam_dbg_log( "No need to set AF area[x,y:%d,%d]", get_area.x, get_area.y ); + return TRUE; + } + + __ta__( " gst_camera_control_set_focus_area", + ret = gst_camera_control_set_auto_focus_area( control, set_area ); + ); + if( ret ) + { + _mmcam_dbg_log( "Succeed to set AF area[%d,%d,%dx%d]", set_area.x, set_area.y, set_area.width, set_area.height ); + return TRUE; + } + else + { + _mmcam_dbg_warn( "Failed to set AF area[%d,%d,%dx%d]", set_area.x, set_area.y, set_area.width, set_area.height ); + } + } + } + else + { + _mmcam_dbg_log("pointer of video src is null"); + } + + return FALSE; +} + + +bool _mmcamcorder_commit_camera_capture_mode (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + GstCameraControl *control = NULL; + 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; + + int scene_mode = MM_CAMCORDER_SCENE_MODE_NORMAL; + gboolean check_scene_mode = FALSE; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + return TRUE; + + current_state = _mmcamcorder_get_state( handle); + + if (current_state < MM_CAMCORDER_STATE_READY) { + return TRUE; + } + + if (attr_idx == MM_CAM_CAMERA_F_NUMBER) { + exposure_type = GST_CAMERA_CONTROL_F_NUMBER; + mslVal1 = newVal1 = MM_CAMCORDER_GET_NUMERATOR( ivalue ); + mslVal2 = newVal2 = MM_CAMCORDER_GET_DENOMINATOR( ivalue ); + } else if (attr_idx == MM_CAM_CAMERA_SHUTTER_SPEED) { + exposure_type = GST_CAMERA_CONTROL_SHUTTER_SPEED; + mslVal1 = newVal1 = MM_CAMCORDER_GET_NUMERATOR( ivalue ); + mslVal2 = newVal2 = MM_CAMCORDER_GET_DENOMINATOR( ivalue ); + } 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); + 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); + } 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 ); + } + + if (check_scene_mode) { + mm_camcorder_get_attributes(handle, NULL, MMCAM_FILTER_SCENE_MODE, &scene_mode, NULL); + if (scene_mode != MM_CAMCORDER_SCENE_MODE_NORMAL) { + _mmcam_dbg_warn("can not set [%d] when scene mode is NOT normal.", attr_idx); + 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); + 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; + } + } else { + _mmcam_dbg_warn( "Failed to get exposure. Type[%d]", exposure_type ); + } + } else { + _mmcam_dbg_log("pointer of video src is null"); + } + + return FALSE; +} + + +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 cur_value = 0; + _MMCamcorderSubContext *sc = NULL; + int current_state = MM_CAMCORDER_STATE_NONE; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + 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 ) + { + 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 ); + return TRUE; + } + 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 ); + return TRUE; + } + } + else + { + _mmcam_dbg_warn( "Failed to get WDR." ); + } + } + else + { + _mmcam_dbg_log("pointer of video src is null"); + } + + return FALSE; +} + + +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) + return TRUE; + + 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; + } + + 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_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"); + } + + return FALSE; +} + + +bool _mmcamcorder_commit_camera_hold_af_after_capturing (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + _MMCamcorderSubContext *sc = NULL; + int current_state = MM_CAMCORDER_STATE_NONE; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + return TRUE; + + 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; + } + + if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) + { + _mmcam_dbg_log("Commit : value of Hold af after capturing is %d", value->value.i_val); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", value->value.i_val); + } + else + _mmcam_dbg_warn("Commit : Hold af after capturing cannot be set"); + + return TRUE; +} + + +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); + + 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); + return FALSE; + } else { + 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) +{ + _mmcam_dbg_log("Image encoder quality(%d)", value->value.i_val); + return TRUE; +} + + +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; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + 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); + } + + 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."); + } + return TRUE; +} + + + + +bool _mmcamcorder_commit_filter (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + GstColorBalance *balance = NULL; + GstColorBalanceChannel *Colorchannel = NULL; + const GList *controls = NULL; + 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; + + int scene_mode = MM_CAMCORDER_SCENE_MODE_NORMAL; + gboolean check_scene_mode = FALSE; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + return TRUE; + + current_state = _mmcamcorder_get_state(handle); + + //status check + if (current_state < MM_CAMCORDER_STATE_PREPARE) { + //_mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); + return TRUE; + } + + if (value->type != MM_ATTRS_TYPE_INT) { + _mmcam_dbg_warn("Mismatched value type (%d)", value->type); + return FALSE; + } else { + mslNewVal = value->value.i_val; + } + + 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_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_SATURATION: + control_label = "saturation"; + check_scene_mode = TRUE; + break; + + case MM_CAM_FILTER_HUE: + control_label = "hue"; + break; + + case MM_CAM_FILTER_SHARPNESS: + control_label = "sharpness"; + check_scene_mode = TRUE; + break; + } + + if (check_scene_mode) { + mm_camcorder_get_attributes(handle, NULL, MMCAM_FILTER_SCENE_MODE, &scene_mode, NULL); + if (scene_mode != MM_CAMCORDER_SCENE_MODE_NORMAL) { + _mmcam_dbg_warn("can not set %s when scene mode is NOT normal.", control_label); + return FALSE; + } + } + + newVal = _mmcamcorder_convert_msl_to_sensor(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)) + { + _mmcam_dbg_log("Can't cast Video source into color balance."); + return TRUE; + } + + 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) + { + Colorchannel = item->data; + //_mmcam_dbg_log("Getting name of CID=(%s), input CID=(%s)", Colorchannel->label, control_label); + + if (strcmp(Colorchannel->label, control_label) == 0) + { + break; + } + else + Colorchannel = NULL; + } + } + } + + if (Colorchannel== NULL) { + _mmcam_dbg_log("There is no data in the colorbalance controls(%d)", attr_idx); + 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 ); + + 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); + } + + return TRUE; +} + + +bool _mmcamcorder_commit_filter_scene_mode (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_FILTER_SCENE_MODE, mslVal ); + int cur_program_mode = MM_CAMCORDER_SCENE_MODE_NORMAL; + _MMCamcorderSubContext *sc = NULL; + int current_state = MM_CAMCORDER_STATE_NONE; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + 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) { + 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]])); + } + } + } + + 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; + } + } else { + _mmcam_dbg_warn( "Failed to get program mode, so do not set new program mode[%d]", mslVal ); + } + } else { + _mmcam_dbg_warn("pointer of video src is null"); + } + + return FALSE; +} + + +bool _mmcamcorder_commit_filter_flip (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + _mmcam_dbg_warn("Filter Flip(%d)", value->value.i_val); + return TRUE; +} + + +bool _mmcamcorder_commit_camcorder_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("camcorder-rotation(%d)", value->value.i_val); + current_state = _mmcamcorder_get_state( handle); + bstate_changing = _mmcamcorder_is_state_changing( handle); + + 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; + } else { + return TRUE; + } +} + + +bool _mmcamcorder_commit_audio_input_route (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + _mmcam_dbg_log("Commit : Do nothing. this attr will be removed soon."); + + return TRUE; +} + + +bool _mmcamcorder_commit_display_handle (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + _MMCamcorderSubContext *sc = NULL; + + char* videosink_name = NULL; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + 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) +{ + mmf_camcorder_t *hcamcorder = NULL; + _MMCamcorderSubContext *sc = NULL; + int current_state = MM_CAMCORDER_STATE_NONE; + + hcamcorder = MMF_CAMCORDER(handle); + if(!hcamcorder) + return TRUE; + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + return TRUE; + + current_state = _mmcamcorder_get_state( 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 ); + } else { + _mmcam_dbg_warn( "Current Mode is AUDIO only mode." ); + return FALSE; + } + } else { + _mmcam_dbg_err("display rotation change failed.(state=%d)", current_state); + return FALSE; + } +} + + +bool _mmcamcorder_commit_display_visible (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER( handle); + _MMCamcorderSubContext *sc = NULL; + + int is_visible = 0; + 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( 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; + + if( !strcmp( videosink_name, "xvimagesink" ) + || !strcmp( videosink_name, "avsysvideosink" ) ) + { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, + "visible", is_visible); + + _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; + } + } + else + { + _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); + bret = TRUE; + } + return bret; +} + + +bool _mmcamcorder_commit_display_geometry_method (MMHandleType handle, int attr_idx, const mmf_value_t *value) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER( handle); + _MMCamcorderSubContext *sc = NULL; + + int newattrs = 0; + 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 ); + + 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; + } + } + else + { + _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); + bret = TRUE; + } + + return bret; +} + + +bool _mmcamcorder_commit_display_rect (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 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 ); + + 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; + } + + 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; + + 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; + } + + 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; + } + else + { + _mmcam_dbg_log("Videosink element is null"); + bret = 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) +{ + 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; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + return TRUE; + current_state = _mmcamcorder_get_state( handle); + + 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); + + _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); + + _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); + + _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; + } + } + else + { + _mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); + bret = TRUE; + } + + return bret; +} + + +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; + + sc = MMF_CAMCORDER_SUBCONTEXT( handle ); + if (!sc) + return TRUE; + + _mmcam_dbg_log( "Commit : strobe attribute(%d)", attr_idx ); + + //status check + current_state = _mmcamcorder_get_state( handle); + + if (current_state < MM_CAMCORDER_STATE_PREPARE || + current_state == MM_CAMCORDER_STATE_CAPTURING) { + //_mmcam_dbg_log("It doesn't need to change dynamically.(state=%d)", current_state); + return TRUE; + } + + 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; + } + } + + GstCameraControl *control = NULL; + 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 ); + + 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 ); + bret = FALSE; + } + } + 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 ); + bret = FALSE; + } + } + + return bret; +} + + +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; + GstCameraControl *control = NULL; + int current_state = MM_CAMCORDER_STATE_NONE; + + sc = MMF_CAMCORDER_SUBCONTEXT( handle ); + if (!sc) + return TRUE; + + _mmcam_dbg_log( "Commit : detect attribute(%d)", attr_idx); + + //status 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; + } + } + + mslVal = value->value.i_val; + newVal = _mmcamcorder_convert_msl_to_sensor( attr_idx, mslVal ); + + + 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 ); + + 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 ); + 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 ); + bret = FALSE; + } + else + { + _mmcam_dbg_log( "Set detect success. Type[%d],value[%d]", detect_type, mslVal ); + bret = TRUE; + } + } + } + else + { + _mmcam_dbg_warn( "Get detect failed. Type[%d]", detect_type ); + bret = FALSE; + } + } + + return bret; +} + + +static bool +__mmcamcorder_attrs_is_supported(MMHandleType handle, int idx) +{ + mmf_attrs_t *attr = (mmf_attrs_t*)handle; + int flag; + + if (mm_attrs_get_flags(handle, idx, &flag) == MM_ERROR_NONE) { + if (flag == MM_ATTRS_FLAG_NONE) { + return FALSE; + } + } else { + return FALSE; + } + + if (attr->items[idx].value_spec.type == MM_ATTRS_VALID_TYPE_INT_RANGE) { + int min, max; + mm_attrs_get_valid_range((MMHandleType)attr, idx, &min, &max); + if (max < min) { + return FALSE; + } + } else if (attr->items[idx].value_spec.type == MM_ATTRS_VALID_TYPE_INT_ARRAY) { + int count; + int *array; + mm_attrs_get_valid_array((MMHandleType)attr, idx, &count, &array); + if (count == 0) { + return FALSE; + } + } + + return TRUE; +} + + +bool +_mmcamcorder_set_attribute_to_camsensor(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + mmf_attrs_t *attr = NULL; + + int scene_mode = MM_CAMCORDER_SCENE_MODE_NORMAL; + + int i = 0 ; + int ret = TRUE; + 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[] = { + MM_CAM_CAMERA_ISO + , MM_CAM_FILTER_BRIGHTNESS + , MM_CAM_FILTER_WB + , MM_CAM_FILTER_SATURATION + , MM_CAM_FILTER_SHARPNESS + }; + + mmf_return_val_if_fail(hcamcorder, FALSE); + + _mmcam_dbg_log("Set all attribute again."); + + MMTA_ACUM_ITEM_BEGIN(" _mmcamcorder_set_attribute_to_camsensor", 0); + + attr = (mmf_attrs_t *)MMF_CAMCORDER_ATTRS(handle); + if (attr == NULL) { + _mmcam_dbg_err("Get attribute handle failed."); + return FALSE; + } else { + /* Get Scene mode */ + mm_camcorder_get_attributes(handle, NULL, MMCAM_FILTER_SCENE_MODE, &scene_mode, NULL); + + _mmcam_dbg_log("attribute count(%d)", attr->count); + + for (i = 0 ; i < ARRAY_SIZE(attr_idxs_default) ; i++) { + if (__mmcamcorder_attrs_is_supported((MMHandleType)attr, attr_idxs_default[i])) { + mmf_attribute_set_modified(&(attr->items[attr_idxs_default[i]])); + } + } + + /* Set extra if scene mode is NORMAL */ + if (scene_mode == MM_CAMCORDER_SCENE_MODE_NORMAL) { + for (i = 0 ; i < ARRAY_SIZE(attr_idxs_extra) ; i++) { + if (__mmcamcorder_attrs_is_supported((MMHandleType)attr, attr_idxs_extra[i])) { + mmf_attribute_set_modified(&(attr->items[attr_idxs_extra[i]])); + } + } + } else { + /* Set scene mode if scene mode is NOT NORMAL */ + if (__mmcamcorder_attrs_is_supported((MMHandleType)attr, MM_CAM_FILTER_SCENE_MODE)) { + mmf_attribute_set_modified(&(attr->items[MM_CAM_FILTER_SCENE_MODE])); + } + } + + if (mmf_attrs_commit((MMHandleType)attr) == -1) { + ret = FALSE; + } else { + ret = TRUE; + } + } + + MMTA_ACUM_ITEM_END(" _mmcamcorder_set_attribute_to_camsensor", 0); + + _mmcam_dbg_log("Done."); + + return ret; +} + + +int _mmcamcorder_lock_readonly_attributes(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + int table_size = 0; + int i = 0; + mmf_attrs_t *attr = NULL; + int nerror = MM_ERROR_NONE ; + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + attr = (mmf_attrs_t*) MMF_CAMCORDER_ATTRS(handle); + mmf_return_val_if_fail(attr, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log(""); + + table_size = ARRAY_SIZE(readonly_attributes); + _mmcam_dbg_log("%d", table_size); + for (i = 0; i < table_size; i++) + { + int sCategory = readonly_attributes[i]; + + mmf_attribute_set_readonly(&(attr->items[sCategory])); + } + + return nerror; +} + + +int _mmcamcorder_set_disabled_attributes(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + //int table_size = 0; + int i = 0; + mmf_attrs_t *attr = NULL; + type_string_array * disabled_attr = NULL; + int cnt_str = 0; + int nerror = MM_ERROR_NONE ; + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + attr = (mmf_attrs_t*) MMF_CAMCORDER_ATTRS(handle); + mmf_return_val_if_fail(attr, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log(""); + + /* add gst_param */ + _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++) { + int idx = 0; + _mmcam_dbg_log("[%d]%s", i, disabled_attr->value[i] ); + nerror = mm_attrs_get_index((MMHandleType)attr, disabled_attr->value[i], &idx); + if (nerror == MM_ERROR_NONE) { + mmf_attribute_set_disabled(&(attr->items[idx])); + } else { + _mmcam_dbg_warn("No ATTR named %s[%d]",disabled_attr->value[i], i); + } + } + } + + return nerror; +} + + +/*--------------------------------------------------------------------------------------- +| INTERNAL FUNCTION DEFINITIONS: | +---------------------------------------------------------------------------------------*/ +static bool __mmcamcorder_set_capture_resolution(MMHandleType handle, int width, int height) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + int current_state = MM_CAMCORDER_STATE_NULL; + + mmf_return_val_if_fail(hcamcorder, FALSE); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc && sc->info, TRUE); + + current_state = _mmcamcorder_get_state(handle); + + if (sc->element && sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) { + if (current_state <= MM_CAMCORDER_STATE_PREPARE) { + _mmcam_dbg_log("set capture width and height [%dx%d] to camera plugin", width, height); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-width", width); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-height", height); + } else { + _mmcam_dbg_warn("invalid state[%d]", current_state); + return FALSE; + } + } else { + _mmcam_dbg_log("element is not created yet"); + } + + return TRUE; +} + + +static bool __mmcamcorder_set_camera_resolution(MMHandleType handle, int width, int height) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + int fps, slow_fps; + _MMCamcorderSubContext *sc = NULL; + GstCaps *caps = NULL; + int set_width, set_height; + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + if (!sc) + return TRUE; + + mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAMERA_FPS, &fps, + "camera-slow-motion-fps", &slow_fps, + NULL); + + if (hcamcorder->type == MM_CAMCORDER_MODE_VIDEO) { + if(slow_fps > 0) { + sc->is_slow = TRUE; + 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); + gst_caps_unref(caps); + + return TRUE; +} + +static int +__mmcamcorder_check_valid_pair( MMHandleType handle, char **err_attr_name, const char *attribute_name, va_list var_args ) +{ + #define INIT_VALUE -1 + #define CHECK_COUNT 2 + #define CAMERA_RESOLUTION 0 + #define CAPTURE_RESOLUTION 1 + + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + MMHandleType attrs = 0; + + int ret = MM_ERROR_NONE; + int i = 0, j = 0; + char *name = NULL; + char *check_pair_name[2][3] = { + { MMCAM_CAMERA_WIDTH, MMCAM_CAMERA_HEIGHT, "MMCAM_CAMERA_WIDTH and HEIGHT" }, + { MMCAM_CAPTURE_WIDTH, MMCAM_CAPTURE_HEIGHT, "MMCAM_CAPTURE_WIDTH and HEIGHT" }, + }; + + int check_pair_value[2][2] = { + { INIT_VALUE, INIT_VALUE }, + { INIT_VALUE, INIT_VALUE }, + }; + + if( hcamcorder == NULL || attribute_name == NULL ) + { + _mmcam_dbg_warn( "handle[%p] or attribute_name[%p] is NULL.", + hcamcorder, attribute_name ); + return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + } + + if( err_attr_name ) + *err_attr_name = NULL; + + //_mmcam_dbg_log( "ENTER" ); + + attrs = MMF_CAMCORDER_ATTRS(handle); + + name = (char*)attribute_name; + + while( name ) + { + int idx = -1; + MMAttrsType attr_type = MM_ATTRS_TYPE_INVALID; + + /*_mmcam_dbg_log( "NAME : %s", name );*/ + + /* attribute name check */ + if ((ret = mm_attrs_get_index(attrs, name, &idx)) != MM_ERROR_NONE) + { + if (err_attr_name) + *err_attr_name = strdup(name); + + if (ret == MM_ERROR_COMMON_OUT_OF_ARRAY) //to avoid confusing + return MM_ERROR_COMMON_ATTR_NOT_EXIST; + else + return ret; + } + + /* type check */ + if ((ret = mm_attrs_get_type(attrs, idx, &attr_type)) != MM_ERROR_NONE) + return ret; + + switch (attr_type) + { + case MM_ATTRS_TYPE_INT: + { + gboolean matched = FALSE; + for( i = 0 ; i < CHECK_COUNT ; i++ ) { + for( j = 0 ; j < 2 ; j++ ) { + if( !strcmp( name, check_pair_name[i][j] ) ) + { + check_pair_value[i][j] = va_arg( (var_args), int ); + _mmcam_dbg_log( "%s : %d", check_pair_name[i][j], check_pair_value[i][j] ); + matched = TRUE; + break; + } + } + if( matched ) + break; + } + if( matched == FALSE ) + { + va_arg ((var_args), int); + } + break; + } + case MM_ATTRS_TYPE_DOUBLE: + va_arg ((var_args), double); + break; + case MM_ATTRS_TYPE_STRING: + va_arg ((var_args), char*); /* string */ + va_arg ((var_args), int); /* size */ + break; + case MM_ATTRS_TYPE_DATA: + va_arg ((var_args), void*); /* data */ + va_arg ((var_args), int); /* size */ + break; + case MM_ATTRS_TYPE_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); + if (err_attr_name) + *err_attr_name = strdup(name); + return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + } + + /* next name */ + name = va_arg (var_args, char*); + } + + for( i = 0 ; i < CHECK_COUNT ; i++ ) + { + if( check_pair_value[i][0] != INIT_VALUE || check_pair_value[i][1] != INIT_VALUE ) + { + gboolean check_result = FALSE; + char *err_name = NULL; + MMCamAttrsInfo attr_info_0, attr_info_1; + + if( check_pair_value[i][0] == INIT_VALUE ) + { + mm_attrs_get_int_by_name( attrs, check_pair_name[i][0], &check_pair_value[i][0] ); + err_name = strdup(check_pair_name[i][1]); + } + else if( check_pair_value[i][1] == INIT_VALUE ) + { + mm_attrs_get_int_by_name( attrs, check_pair_name[i][1], &check_pair_value[i][1] ); + err_name = strdup(check_pair_name[i][0]); + } + else + { + err_name = strdup(check_pair_name[i][2]); + } + + mm_camcorder_get_attribute_info(handle, check_pair_name[i][0], &attr_info_0); + mm_camcorder_get_attribute_info(handle, check_pair_name[i][1], &attr_info_1); + + check_result = FALSE; + + for( j = 0 ; j < attr_info_0.int_array.count ; j++ ) { + if( attr_info_0.int_array.array[j] == check_pair_value[i][0] + && attr_info_1.int_array.array[j] == check_pair_value[i][1] ) + { + _mmcam_dbg_log( "Valid Pair[%s,%s] existed %dx%d[index:%d]", + check_pair_name[i][0], check_pair_name[i][1], + check_pair_value[i][0], check_pair_value[i][1], i ); + check_result = TRUE; + break; + } + } + + if( check_result == FALSE ) + { + _mmcam_dbg_err( "INVALID pair[%s,%s] %dx%d", + check_pair_name[i][0], check_pair_name[i][1], + check_pair_value[i][0], check_pair_value[i][1] ); + if (err_attr_name) + *err_attr_name = err_name; + + return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + } + } + } + + /*_mmcam_dbg_log("DONE");*/ + + return MM_ERROR_NONE; +} diff --git a/src/mm_camcorder_audiorec.c b/src/mm_camcorder_audiorec.c new file mode 100644 index 0000000..b810fe7 --- /dev/null +++ b/src/mm_camcorder_audiorec.c @@ -0,0 +1,1050 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include "mm_camcorder_internal.h" +#include "mm_camcorder_audiorec.h" +#include <math.h> + +/*--------------------------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------------------*/ +#define MM_CAMCORDER_START_CHANGE_STATE _MMCamcorderStartHelperFunc((void *)hcamcorder) +#define MM_CAMCORDER_STOP_CHANGE_STATE _MMCamcorderStopHelperFunc((void *)hcamcorder) +/*--------------------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------------------*/ +#define RESET_PAUSE_TIME 0 +#define _MMCAMCORDER_AUDIO_MINIMUM_SPACE (100*1024) +#define _MMCAMCORDER_AUDIO_MARGIN_SPACE (1*1024) +#define _MMCAMCORDER_RETRIAL_COUNT 10 +#define _MMCAMCORDER_FRAME_WAIT_TIME 20000 /* micro second */ +#define _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL 10 +/*--------------------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------------------*/ +/* STATIC INTERNAL FUNCTION */ +static gboolean __mmcamcorder_audio_dataprobe_voicerecorder(GstPad *pad, GstBuffer *buffer, gpointer u_data); +static gboolean __mmcamcorder_audio_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data); +static int __mmcamcorder_create_audiop_with_encodebin(MMHandleType handle); +static void __mmcamcorder_audiorec_pad_added_cb(GstElement *element, GstPad *pad, MMHandleType handle); + +/*======================================================================================= +| FUNCTION DEFINITIONS | +=======================================================================================*/ + +/*--------------------------------------------------------------------------------------- +| GLOBAL FUNCTION DEFINITIONS: | +---------------------------------------------------------------------------------------*/ + + +static int __mmcamcorder_create_audiop_with_encodebin(MMHandleType handle) +{ + int err = MM_ERROR_NONE; + char *aenc_name = NULL; + char *mux_name = NULL; + + GstBus *bus = NULL; + GstPad *srcpad = NULL; + GstPad *sinkpad = NULL; + GList *element_list = NULL; + + _MMCamcorderAudioInfo *info = NULL; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + type_element *aenc_elem = NULL; + type_element *mux_elem = 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); + + info = (_MMCamcorderAudioInfo *)sc->info; + + _mmcam_dbg_log(""); + + mux_elem = _mmcamcorder_get_type_element(handle, MM_CAM_FILE_FORMAT); + err = _mmcamcorder_conf_get_value_element_name( mux_elem, &mux_name ); + + if (!mux_name || !strcmp( mux_name, "wavenc" ) ) /* IF MUX in not chosen then record in raw amr file */ + { + //But shoud we support non-mux recording?? + _mmcam_dbg_log("Record without muxing."); + info->bMuxing = FALSE; + } + else + { + _mmcam_dbg_log("Record with mux."); + info->bMuxing = TRUE; + } + + //Create gstreamer element + //Main pipeline + __ta__(" camcorder_pipeline", + _MMCAMCORDER_PIPELINE_MAKE(sc, _MMCAMCORDER_MAIN_PIPE, "camcorder_pipeline", err); + ); + + __ta__(" __mmcamcorder_create_audiosrc_bin", + err = _mmcamcorder_create_audiosrc_bin(handle); + ); + if (err != MM_ERROR_NONE) { + return err; + } + + if (info->bMuxing) { + /* Muxing. can use encodebin. */ + __ta__(" _mmcamcorder_create_encodesink_bin", + err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder); + ); + if (err != MM_ERROR_NONE ) { + return err; + } + } else { + /* without muxing. can't use encodebin. */ + aenc_elem = _mmcamcorder_get_type_element(handle, MM_CAM_AUDIO_ENCODER); + if (!aenc_elem) + { + _mmcam_dbg_err("Fail to get type element"); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + err = _mmcamcorder_conf_get_value_element_name(aenc_elem, &aenc_name); + + if ((!err) || (!aenc_name)) + { + _mmcam_dbg_err("Fail to get element name"); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + __ta__(" audiopipeline_audioqueue", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_AQUE, "queue", NULL, element_list, err); + ); + + if( strcmp( aenc_name, "wavenc" ) != 0 ) + { + __ta__(" audiopipeline_audioconvertor", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_CONV, "audioconvert", NULL, element_list, err); + ); + } + + __ta__(" audiopipeline_audioencoder", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_AENC, aenc_name, NULL, element_list, err); + ); + + __ta__(" audiopipeline_filesink", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_SINK, "filesink", NULL, element_list, err); + ); + + /* audio encoder attribute setting */ + if(strcmp(aenc_name,"ari_amrnbenc") == 0) //ari_armnbenc supports attatching amr header + { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "write-header", TRUE); + } + + } + + //Set basic infomation + + if (info->bMuxing) /* IF MUX is indicated create MUX */ + { + gst_bin_add_many(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), + sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, + sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, + NULL); + + 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); + } + else /* IF MUX in not chosen then record in raw amr file */ + { + if( !strcmp( aenc_name, "wavenc" ) ) + { + gst_bin_add_many( GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), + sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, + sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, + sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, + sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, + NULL ); + + if (!_MM_GST_ELEMENT_LINK_MANY( sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, + sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, + sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, + sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, + NULL )) + { + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + } + else + { + gst_bin_add_many( GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), + sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, + sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, + sc->element[_MMCAMCORDER_ENCSINK_CONV].gst, + sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, + sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, + NULL ); + + if (!_MM_GST_ELEMENT_LINK_MANY( sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, + sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, + sc->element[_MMCAMCORDER_ENCSINK_CONV].gst, + sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, + sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, + NULL )) + { + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + } + } + + + //set data probe function + srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src"); + MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_AUDIOREC, + __mmcamcorder_audio_dataprobe_voicerecorder, hcamcorder); + gst_object_unref(srcpad); + srcpad = NULL; + + if(info->bMuxing) + { + MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, + _MMCAMCORDER_HANDLER_AUDIOREC, + "pad-added", + __mmcamcorder_audiorec_pad_added_cb, + hcamcorder); + } + else + { + srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "src"); + MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_AUDIOREC, + __mmcamcorder_audio_dataprobe_record, hcamcorder); + gst_object_unref(srcpad); + srcpad = NULL; + } + + /* + * To get the message callback from the gstreamer. + * This can be used to make the API calls asynchronous + * as per LiMO compliancy + */ + bus = gst_pipeline_get_bus(GST_PIPELINE(sc->element[_MMCAMCORDER_MAIN_PIPE].gst)); + hcamcorder->pipeline_cb_event_id = gst_bus_add_watch( bus, (GstBusFunc)_mmcamcorder_pipeline_cb_message, hcamcorder ); + gst_bus_set_sync_handler(bus, gst_bus_sync_signal_handler, hcamcorder); + gst_object_unref(bus); + + return MM_ERROR_NONE; + +pipeline_creation_error: + return err; +} + + +int +_mmcamcorder_create_audio_pipeline(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, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + return __mmcamcorder_create_audiop_with_encodebin(handle); +} + + +/** + * This function destroy audio pipeline. + * + * @param[in] handle Handle of camcorder. + * @return void + * @remarks + * @see _mmcamcorder_destroy_pipeline() + * + */ +void +_mmcamcorder_destroy_audio_pipeline(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + _MMCamcorderAudioInfo* info = NULL; + mmf_return_if_fail(hcamcorder); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + + mmf_return_if_fail(sc); + mmf_return_if_fail(sc->element); + + info = sc->info; + + _mmcam_dbg_log(""); + + if(sc->element[_MMCAMCORDER_MAIN_PIPE].gst) + { + _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_NULL); + + _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_CATEGORY_ALL); + + if( info->bMuxing) + { + GstPad *reqpad = NULL; + //release request pad + /* FIXME */ + /* + The ref_count of mux is always # of streams in here, i don't know why it happens. + So, i unref the mux manually + */ + reqpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio"); + gst_element_release_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad); + gst_object_unref(reqpad); + + if(GST_IS_ELEMENT(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst) && \ + GST_OBJECT_REFCOUNT_VALUE(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst) > 1) + gst_object_unref(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst); + } + gst_object_unref(sc->element[_MMCAMCORDER_MAIN_PIPE].gst); +// sc->element[_MMCAMCORDER_MAIN_PIPE].gst = NULL; + } + +} + + +/** + * This function operates each command on audio mode. + * + * @param c [in] Handle of camcorder context. + * @param command [in] command type received from Multimedia Framework. + * + * @return This function returns MM_ERROR_NONE on success, or the other values + * on error. + * @remark + * @see _mmcamcorder_set_functions() + * + */ + /* ADDED BY SISO */ + + +void* _MMCamcorderStartHelperFunc(void *handle) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + _mmcamcorder_set_state((MMHandleType)hcamcorder, hcamcorder->target_state); + + return NULL; +} + +void* _MMCamcorderStopHelperFunc(void *handle) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + _mmcamcorder_set_state((MMHandleType)hcamcorder, hcamcorder->target_state); + + return NULL; +} + + +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 *err_attr_name = 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); + pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; + info = sc->info; + + _mmcam_dbg_log(""); + + pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; + audioSrc = sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst; + switch(cmd) + { + case _MMCamcorder_CMD_RECORD: + //check status for resume case + if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) + { + guint imax_time = 0; + char *temp_filename = NULL; + + if(sc->pipeline_time) { + gst_pipeline_set_new_stream_time(GST_PIPELINE(pipeline), sc->pipeline_time); + } + sc->pipeline_time = RESET_PAUSE_TIME; + + ret = mm_camcorder_get_attributes(handle, &err_attr_name, + MMCAM_TARGET_TIME_LIMIT, &imax_time, + MMCAM_FILE_FORMAT, &(info->fileformat), + MMCAM_TARGET_FILENAME, &temp_filename, &size, + NULL); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_warn("failed to get attribute. (%s:%x)", err_attr_name, ret); + SAFE_FREE (err_attr_name); + goto _ERR_CAMCORDER_AUDIO_COMMAND; + } + + info->filename = strdup(temp_filename); + if (!info->filename) + { + _mmcam_dbg_err("STRDUP was failed"); + goto _ERR_CAMCORDER_AUDIO_COMMAND; + } + + _mmcam_dbg_log("Record start : set file name using attribute - %s\n ",info->filename); + + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename); + + sc->ferror_send = FALSE; + sc->ferror_count = 0; + sc->bget_eos = FALSE; + info->filesize =0; + + /* set max time */ + if (imax_time <= 0) { + info->max_time = 0; /* do not check */ + } else { + info->max_time = ((guint64)imax_time) * 1000; /* to millisecond */ + } + +/* + //set data probe function + gst_pad_add_buffer_probe(gst_element_get_pad(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src"), + G_CALLBACK(__mmcamcorder_audio_dataprobe_voicerecorder), + hcamcorder); +*/ +/* TODO : check free space before recording start, need to more discussion */ +#if 1 + dir_name = g_path_get_dirname(info->filename); + err = _mmcamcorder_get_freespace(dir_name, &free_space); + if((err == -1) || free_space <= (_MMCAMCORDER_AUDIO_MINIMUM_SPACE+(5*1024))) + { + _mmcam_dbg_err("No more space for recording - %s : [%" G_GUINT64_FORMAT "]\n ", dir_name, free_space); + if(dir_name) + { + g_free(dir_name); + dir_name = NULL; + } + return MM_MESSAGE_CAMCORDER_NO_FREE_SPACE; + } + if(dir_name) + { + g_free(dir_name); + dir_name = NULL; + } +#endif + } + + ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); + if(ret<0) { + goto _ERR_CAMCORDER_AUDIO_COMMAND; + } + break; + + case _MMCamcorder_CMD_PAUSE: + { + GstClock *clock = NULL; + int count = 0; + + if (info->b_commiting) + { + _mmcam_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd); + return MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + } + + for(count=0; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) + { + if(info->filesize > 0) + { + break; + } + else if(count == _MMCAMCORDER_RETRIAL_COUNT) + { + _mmcam_dbg_err("Pause fail, we are waiting for 100 milisecond, but still file size is %" G_GUINT64_FORMAT "", + info->filesize); + return MM_ERROR_CAMCORDER_INVALID_CONDITION; + } + else + { + _mmcam_dbg_warn("Pause is Waiting for enough audio frame, retrial count[%d], file size is %" G_GUINT64_FORMAT "", + count, info->filesize); + } + usleep(_MMCAMCORDER_FRAME_WAIT_TIME); + } + + ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED); + if(ret<0) { + goto _ERR_CAMCORDER_AUDIO_COMMAND; + } + //fixed me. consider delay. + clock = gst_pipeline_get_clock(GST_PIPELINE(pipeline)); + sc->pipeline_time = gst_clock_get_time(clock) - gst_element_get_base_time(GST_ELEMENT(sc->element[_MMCAMCORDER_MAIN_PIPE].gst)); + } + break; + + case _MMCamcorder_CMD_CANCEL: + if (info->b_commiting) + { + _mmcam_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd); + return MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + } + +// ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_NULL); + ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY); + if(ret<0) { + goto _ERR_CAMCORDER_AUDIO_COMMAND; + } + + if(info->bMuxing) + { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); + } + else + { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", FALSE); + } + + _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, GST_STATE_NULL); + + sc->pipeline_time = 0; + sc->pause_time = 0; + sc->isMaxsizePausing = FALSE; + sc->isMaxtimePausing = FALSE; + + if(info->filename) + { + _mmcam_dbg_log("file delete(%s)", info->filename); + unlink(info->filename); + g_free(info->filename); + info->filename = NULL; + } + + break; + case _MMCamcorder_CMD_COMMIT: + { + int count = 0; + g_print("\n\n _MMCamcorder_CMD_COMMIT\n\n"); + + if (info->b_commiting) + { + _mmcam_dbg_warn("now on commiting previous file!!(cmd : %d)", cmd); + return MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + } + else + { + _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start"); + info->b_commiting = TRUE; + } + + for(count=0; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) + { + if(info->filesize > 0) + { + break; + } + else if(count == _MMCAMCORDER_RETRIAL_COUNT) + { + _mmcam_dbg_err("Commit fail, we are waiting for 100 milisecond, but still file size is %" G_GUINT64_FORMAT "", + info->filesize); + info->b_commiting = FALSE; + return MM_ERROR_CAMCORDER_INVALID_CONDITION; + } + else + { + _mmcam_dbg_warn("Commit is Waiting for enough audio frame, retrial count[%d], file size is %" G_GUINT64_FORMAT "", + count, info->filesize); + } + usleep(_MMCAMCORDER_FRAME_WAIT_TIME); + } + + if (audioSrc) { + GstPad *pad = gst_element_get_static_pad (audioSrc, "src"); +// gst_pad_push_event (pad, gst_event_new_eos()); + ret = gst_element_send_event(audioSrc, gst_event_new_eos()); + gst_object_unref(pad); + pad = NULL; + if (_mmcamcorder_get_state((MMHandleType)hcamcorder) == MM_CAMCORDER_STATE_PAUSED) // for pause -> commit case + { + ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); + if(ret<0) { + goto _ERR_CAMCORDER_AUDIO_COMMAND; + } + } + + } + + //wait until finishing EOS + _mmcam_dbg_log("Start to wait EOS"); + if ((ret =_mmcamcorder_get_eos_message(handle)) != MM_ERROR_NONE) + { + goto _ERR_CAMCORDER_AUDIO_COMMAND; + } +/* + while ((!sc->get_eos)&&((retry_cnt--) > 0)) { + if ((gMessage = gst_bus_timed_pop (bus, timeout)) != NULL) + { + if (GST_MESSAGE_TYPE(gMessage) ==GST_MESSAGE_EOS) + { + _mmcam_dbg_log("Get a EOS message"); + gst_message_unref(gMessage); + break; + } + else + { + _mmcam_dbg_log("Get another message(%x). Post this message to bus again.", GST_MESSAGE_TYPE(gMessage)); + gst_bus_post(bus, gMessage); + } + } + else + { + _mmcam_dbg_log("timeout of gst_bus_timed_pop()"); + break; + } + + usleep(100); //To Prevent busy waiting + } + + _mmcamcorder_audio_handle_eos((MMHandleType)hcamcorder); +*/ + + + } + break; + + case _MMCamcorder_CMD_PREVIEW_START: + // MM_CAMCORDER_START_CHANGE_STATE; + break; + case _MMCamcorder_CMD_PREVIEW_STOP: + // MM_CAMCORDER_STOP_CHANGE_STATE; + //void + break; + + default: + ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + break; + } + +_ERR_CAMCORDER_AUDIO_COMMAND: + return ret; + +} + +int +_mmcamcorder_audio_handle_eos(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + _MMCamcorderAudioInfo *info = NULL; + GstElement *pipeline = NULL; + _MMCamcorderMsgItem msg; + MMCamRecordingReport * report; + + int err = MM_ERROR_NONE; + + mmf_return_val_if_fail(hcamcorder, FALSE); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + + mmf_return_val_if_fail(sc, FALSE); + mmf_return_val_if_fail(sc->info, FALSE); + + _mmcam_dbg_err(""); + + info = sc->info; + + //changing pipeline for display + pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; + + + __ta__(" _MMCamcorder_CMD_COMMIT:GST_STATE_READY", + err = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY); + ); + + if( err != MM_ERROR_NONE ) + { + _mmcam_dbg_warn( "Failed:_MMCamcorder_CMD_COMMIT:GST_STATE_READY. err[%x]", err ); + } + +// __ta__(" _MMCamcorder_CMD_COMMIT:GST_STATE_NULL", +// _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_NULL); +// ) + + //Send message + //Send recording report to application + msg.id = MM_MESSAGE_CAMCORDER_CAPTURED; + + report = (MMCamRecordingReport*) malloc(sizeof(MMCamRecordingReport)); //who free this? + if (!report) + { + //think more. + _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename); + return FALSE; + } + + report->recording_filename = strdup(info->filename); + msg.param.data= report; + + _mmcamcroder_send_message(handle, &msg); + + + if(info->bMuxing) + { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); + } + else + { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_AQUE].gst, "empty-buffers", FALSE); + } + _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, GST_STATE_NULL); + + sc->pipeline_time = 0; + sc->pause_time = 0; + sc->isMaxsizePausing = FALSE; + sc->isMaxtimePausing = FALSE; + + g_free(info->filename); + info->filename = NULL; + + _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end"); + + info->b_commiting = FALSE; + + return TRUE; +} + + +static float +__mmcamcorder_get_decibel(unsigned char* raw, int size, MMCamcorderAudioFormat format) +{ + #define MAX_AMPLITUDE_MEAN_16BIT 23170.115738161934 + #define MAX_AMPLITUDE_MEAN_08BIT 89.803909382810 + + int i = 0; + int depthByte = 0; + int count = 0; + + short* pcm16 = 0; + char* pcm8 = 0; + + float db = 0.0; + float rms = 0.0; + unsigned long long square_sum = 0; + + if (format == MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE) + depthByte = 2; + else //MM_CAMCORDER_AUDIO_FORMAT_PCM_U8 + depthByte = 1; + + for( ; i < size ; i += (depthByte<<1) ) + { + if (depthByte == 1) + { + pcm8 = (char *)(raw + i); + square_sum += (*pcm8)*(*pcm8); + } + else //2byte + { + pcm16 = (short*)(raw + i); + square_sum += (*pcm16)*(*pcm16); + } + + count++; + } + + rms = sqrt( square_sum/count ); + + if (depthByte == 1) + db = 20 * log10( rms/MAX_AMPLITUDE_MEAN_08BIT ); + else + db = 20 * log10( rms/MAX_AMPLITUDE_MEAN_16BIT ); + + /* + _mmcam_dbg_log("size[%d],depthByte[%d],count[%d],rms[%f],db[%f]", + size, depthByte, count, rms, db); + */ + + return db; +} + + +static gboolean +__mmcamcorder_audio_dataprobe_voicerecorder(GstPad *pad, GstBuffer *buffer, gpointer u_data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); + double volume = 0.0; + int format = 0; + int channel = 0; + float curdcb = 0.0; + _MMCamcorderMsgItem msg; + int err = MM_ERROR_UNKNOWN; + char *err_name = NULL; + + mmf_return_val_if_fail(hcamcorder, FALSE); + + /* Set volume to audio input */ + err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name, + MMCAM_AUDIO_VOLUME, &volume, + MMCAM_AUDIO_FORMAT, &format, + MMCAM_AUDIO_CHANNEL, &channel, + NULL); + if (err < 0) + { + _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err); + SAFE_FREE (err_name); + return err; + } + + if(volume == 0) //mute + memset (GST_BUFFER_DATA(buffer), 0, GST_BUFFER_SIZE(buffer)); + + /* Get current volume level of real input stream */ +// currms = __mmcamcorder_get_RMS(GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer), depth); + __ta__( "__mmcamcorder_get_decibel", + curdcb = __mmcamcorder_get_decibel(GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer), format); + ); + + msg.id = MM_MESSAGE_CAMCORDER_CURRENT_VOLUME; + msg.param.rec_volume_dB = curdcb; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + + /* CALL audio stream callback */ + if ((hcamcorder->astream_cb) && buffer && GST_BUFFER_DATA(buffer)) + { + MMCamcorderAudioStreamDataType stream; + + if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) + { + _mmcam_dbg_warn("Not ready for stream callback"); + return TRUE; + } + + /* + _mmcam_dbg_log("Call audio steramCb, data[%p], format[%d], channel[%d], length[%d], volume_dB[%f]", + GST_BUFFER_DATA(buffer), format, channel, GST_BUFFER_SIZE(buffer), curdcb); + */ + + stream.data = (void *)GST_BUFFER_DATA(buffer); + stream.format = format; + stream.channel = channel; + stream.length = GST_BUFFER_SIZE(buffer); + stream.timestamp = (unsigned int)(GST_BUFFER_TIMESTAMP(buffer)/1000000); //nano -> msecond + stream.volume_dB = curdcb; + + _MMCAMCORDER_LOCK_ASTREAM_CALLBACK( hcamcorder ); + + if(hcamcorder->astream_cb) + { + hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param); + } + + _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK( hcamcorder ); + } + + return TRUE; +} + + +static void +__mmcamcorder_audiorec_pad_added_cb(GstElement *element, GstPad *pad, MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + + _mmcam_dbg_log("ENTER(%s)", GST_PAD_NAME(pad)); + //FIXME : the name of audio sink pad of wavparse, oggmux doesn't have 'audio'. How could I handle the name? + if((strstr(GST_PAD_NAME(pad), "audio")) || (strstr(GST_PAD_NAME(pad), "sink"))) + { + MMCAMCORDER_ADD_BUFFER_PROBE(pad, _MMCAMCORDER_HANDLER_AUDIOREC, + __mmcamcorder_audio_dataprobe_record, hcamcorder); + } + else + { + _mmcam_dbg_warn("Unknow pad is added, check it : [%s]", GST_PAD_NAME(pad)); + } + + return; +} + + +static gboolean __mmcamcorder_audio_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data) +{ + static int count = 0; + guint64 rec_pipe_time = 0; + guint64 free_space = 0; + guint64 buffer_size = 0; + guint64 trailer_size = 0; + char *filename = NULL; + + _MMCamcorderSubContext *sc = NULL; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); + _MMCamcorderAudioInfo *info = NULL; + _MMCamcorderMsgItem msg; + + mmf_return_val_if_fail(hcamcorder, FALSE); + mmf_return_val_if_fail(buffer, FALSE); + + sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + mmf_return_val_if_fail(sc && sc->info, FALSE); + info = sc->info; + + if (sc->isMaxtimePausing || sc->isMaxsizePausing) { + _mmcam_dbg_warn("isMaxtimePausing[%d],isMaxsizePausing[%d]", + sc->isMaxtimePausing, sc->isMaxsizePausing); + return FALSE; + } + + buffer_size = (guint64)GST_BUFFER_SIZE(buffer); + + if (info->filesize == 0) { + if (info->fileformat == MM_FILE_FORMAT_WAV) { + info->filesize += 44; /* wave header size */ + } else if (info->fileformat == MM_FILE_FORMAT_AMR) { + info->filesize += 6; /* amr header size */ + } + + info->filesize += buffer_size; + return TRUE; + } + + if (sc->ferror_send) { + _mmcam_dbg_warn("file write error, drop frames"); + return FALSE; + } + + /* 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); + /*_mmcam_dbg_log("trailer_size %d", trailer_size);*/ + } else { + trailer_size = 0; /* no trailer */ + } + + filename = info->filename; + + /* to minimizing free space check overhead */ + count = count % _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL; + if (count++ == 0) { + gint free_space_ret = _mmcamcorder_get_freespace(filename, &free_space); + + /*_mmcam_dbg_log("check free space for recording");*/ + + switch (free_space_ret) { + case -2: /* file not exist */ + case -1: /* failed to get free space */ + _mmcam_dbg_err("Error occured. [%d]", free_space_ret); + if (sc->ferror_count == 2 && sc->ferror_send == FALSE) { + sc->ferror_send = TRUE; + msg.id = MM_MESSAGE_CAMCORDER_ERROR; + if (free_space_ret == -2) { + msg.param.code = MM_ERROR_FILE_NOT_FOUND; + } else { + msg.param.code = MM_ERROR_FILE_READ; + } + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + } else { + sc->ferror_count++; + } + + return FALSE; /* skip this buffer */ + + default: /* succeeded to get free space */ + /* check free space for recording */ + if (free_space < (guint64)(_MMCAMCORDER_AUDIO_MINIMUM_SPACE + buffer_size + trailer_size)) { + _mmcam_dbg_warn("No more space for recording!!!"); + _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], file size : [%" G_GUINT64_FORMAT "]", + free_space, info->filesize); + + 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); + } + + sc->isMaxsizePausing = TRUE; + msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + + return FALSE; /* skip this buffer */ + } + break; + } + } + + if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_TIMESTAMP(buffer))) { + _mmcam_dbg_err("Buffer timestamp is invalid, check it"); + return FALSE; + } + + rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer)); + + /* 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 "]", \ + rec_pipe_time, info->max_time); + + 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); + } + + sc->isMaxtimePausing = TRUE; + msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + + /* skip this buffer */ + return FALSE; + } + + /* send message for recording time and recorded file size */ + if (info->b_commiting == FALSE) { + 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); + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + + return TRUE; + } else { + /* skip this buffer if commit process has been started */ + return FALSE; + } +} diff --git a/src/mm_camcorder_configure.c b/src/mm_camcorder_configure.c new file mode 100644 index 0000000..ae4e205 --- /dev/null +++ b/src/mm_camcorder_configure.c @@ -0,0 +1,3276 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*=========================================================================================== +| | +| INCLUDE FILES | +| | +========================================================================================== */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "mm_camcorder_internal.h" +#include "mm_camcorder_configure.h" + +/*--------------------------------------------------------------------------- +| MACRO DEFINITIONS: | +---------------------------------------------------------------------------*/ +#define CONFIGURE_PATH "/opt/etc" +#define CONFIGURE_PATH_RETRY "/usr/etc" + +/*--------------------------------------------------------------------------- +| GLOBAL 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, }; + +static conf_info_table* conf_main_info_table[CONFIGURE_CATEGORY_MAIN_NUM] = { NULL, }; +static conf_info_table* conf_ctrl_info_table[CONFIGURE_CATEGORY_CTRL_NUM] = { NULL, }; + +/* + * Videosrc element default value + */ +static type_element _videosrc_element_default = { + "VideosrcElement", + "videotestsrc", + NULL, + 0, + NULL, + 0, +}; + +/* + * Audiosrc element default value + */ +static type_int ___audiosrc_default_channel = { "Channel", 1 }; +static type_int ___audiosrc_default_bitrate = { "BitRate", 8000 }; +static type_int ___audiosrc_default_depth = { "Depth", 16 }; +static type_int ___audiosrc_default_blocksize = { "BlockSize", 1280 }; +static type_int* __audiosrc_default_int_array[] = { + &___audiosrc_default_channel, + &___audiosrc_default_bitrate, + &___audiosrc_default_depth, + &___audiosrc_default_blocksize, +}; +static type_string ___audiosrc_default_device = { "Device", "default" }; +static type_string* __audiosrc_default_string_array[] = { + &___audiosrc_default_device, +}; +static type_element _audiosrc_element_default = { + "AudiosrcElement", + "audiotestsrc", + __audiosrc_default_int_array, + sizeof( __audiosrc_default_int_array ) / sizeof( type_int* ), + __audiosrc_default_string_array, + sizeof( __audiosrc_default_string_array ) / sizeof( type_string* ), +}; + +static type_element _audiomodemsrc_element_default = { + "AudiomodemsrcElement", + "audiotestsrc", + __audiosrc_default_int_array, + sizeof( __audiosrc_default_int_array ) / sizeof( type_int* ), + __audiosrc_default_string_array, + sizeof( __audiosrc_default_string_array ) / sizeof( type_string* ), +}; + + +/* + * Videosink element default value + */ +static type_int ___videosink_default_display_id = { "display-id", 3 }; +static type_int ___videosink_default_x = { "x", 0 }; +static type_int ___videosink_default_y = { "y", 0 }; +static type_int ___videosink_default_width = { "width", 800 }; +static type_int ___videosink_default_height = { "height", 480 }; +static type_int ___videosink_default_rotation = { "rotation", 1 }; +static type_int* __videosink_default_int_array[] = { + &___videosink_default_display_id, + &___videosink_default_x, + &___videosink_default_y, + &___videosink_default_width, + &___videosink_default_height, + &___videosink_default_rotation, +}; +static type_string* __videosink_default_string_array[] = { NULL }; +static type_element _videosink_element_x_default = { + "VideosinkElementX", + "xvimagesink", + __videosink_default_int_array, + sizeof( __videosink_default_int_array ) / sizeof( type_int* ), + __videosink_default_string_array, + sizeof( __videosink_default_string_array ) / sizeof( type_string* ), +}; +static type_element _videosink_element_evas_default = { + "VideosinkElementEvas", + "evasimagesink", + __videosink_default_int_array, + sizeof( __videosink_default_int_array ) / sizeof( type_int* ), + __videosink_default_string_array, + sizeof( __videosink_default_string_array ) / sizeof( type_string* ), +}; +static type_element _videosink_element_gl_default = { + "VideosinkElementGL", + "glimagesink", + __videosink_default_int_array, + sizeof( __videosink_default_int_array ) / sizeof( type_int* ), + __videosink_default_string_array, + sizeof( __videosink_default_string_array ) / sizeof( type_string* ), +}; +static type_element _videosink_element_null_default = { + "VideosinkElementNull", + "fakesink", + __videosink_default_int_array, + sizeof( __videosink_default_int_array ) / sizeof( type_int* ), + __videosink_default_string_array, + sizeof( __videosink_default_string_array ) / sizeof( type_string* ), +}; + +/* + * Videoscale element default value + */ +static type_element _videoscale_element_default = { + "VideoscaleElement", + "videoscale", + NULL, + 0, + NULL, + 0, +}; + +/* + * Record sink element default value + */ +static type_element _recordsink_element_default = { + "RecordsinkElement", + "fakesink", + NULL, + 0, + NULL, + 0, +}; + +/* + * H263 element default value + */ +static type_element _h263_element_default = { + "H263", + "ffenc_h263", + NULL, + 0, + NULL, + 0, +}; + +/* + * H264 element default value + */ +static type_element _h264_element_default = { + "H264", + "savsenc_h264", + NULL, + 0, + NULL, + 0, +}; + +/* + * H26L element default value + */ +static type_element _h26l_element_default = { + "H26L", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * MPEG4 element default value + */ +static type_element _mpeg4_element_default = { + "MPEG4", + "ffenc_mpeg4", + NULL, + 0, + NULL, + 0, +}; + +/* + * MPEG1 element default value + */ +static type_element _mpeg1_element_default = { + "MPEG1", + "ffenc_mpeg1video", + NULL, + 0, + NULL, + 0, +}; + +/* + * THEORA element default value + */ +static type_element _theora_element_default = { + "THEORA", + "theoraenc", + NULL, + 0, + NULL, + 0, +}; + +/* + * AMR element default value + */ +static type_element _amr_element_default = { + "AMR", + "secenc_amr", + NULL, + 0, + NULL, + 0, +}; + +/* + * G723_1 element default value + */ +static type_element _g723_1_element_default = { + "G723_1", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * MP3 element default value + */ +static type_element _mp3_element_default = { + "MP3", + "lame", + NULL, + 0, + NULL, + 0, +}; + +/* + * AAC element default value + */ +static type_element _aac_element_default = { + "AAC", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * MMF element default value + */ +static type_element _mmf_element_default = { + "MMF", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * ADPCM element default value + */ +static type_element _adpcm_element_default = { + "ADPCM", + "ffenc_adpcm_ima_qt", + NULL, + 0, + NULL, + 0, +}; + +/* + * WAVE element default value + */ +static type_element _wave_element_default = { + "WAVE", + "wavenc", + NULL, + 0, + NULL, + 0, +}; + +static type_element _vorbis_element_default = { + "VORBIS", + "vorbisenc", + NULL, + 0, + NULL, + 0, +}; + +/* + * MIDI element default value + */ +static type_element _midi_element_default = { + "MIDI", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * IMELODY element default value + */ +static type_element _imelody_element_default = { + "IMELODY", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * JPEG element default value + */ +static type_element _jpeg_element_default = { + "JPEG", + "secjpeg_enc", + NULL, + 0, + NULL, + 0, +}; + +/* + * PNG element default value + */ +static type_element _png_element_default = { + "PNG", + "pngenc", + NULL, + 0, + NULL, + 0, +}; + +/* + * BMP element default value + */ +static type_element _bmp_element_default = { + "BMP", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * WBMP element default value + */ +static type_element _wbmp_element_default = { + "WBMP", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * TIFF element default value + */ +static type_element _tiff_element_default = { + "TIFF", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * PCX element default value + */ +static type_element _pcx_element_default = { + "PCX", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * GIF element default value + */ +static type_element _gif_element_default = { + "GIF", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * ICO element default value + */ +static type_element _ico_element_default = { + "ICO", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * RAS element default value + */ +static type_element _ras_element_default = { + "RAS", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * TGA element default value + */ +static type_element _tga_element_default = { + "TGA", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * XBM element default value + */ +static type_element _xbm_element_default = { + "XBM", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * XPM element default value + */ +static type_element _xpm_element_default = { + "XPM", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * 3GP element default value + */ +static type_element _3gp_element_default = { + "3GP", + "ffmux_3gp", + NULL, + 0, + NULL, + 0, +}; + +/* + * AMR mux element default value + */ +static type_element _amrmux_element_default = { + "AMR", + "ffmux_amr", + NULL, + 0, + NULL, + 0, +}; + +/* + * MP4 element default value + */ +static type_element _mp4_element_default = { + "MP4", + "ffmux_mp4", + NULL, + 0, + NULL, + 0, +}; + +/* + * AAC mux element default value + */ +static type_element _aacmux_element_default = { + "AAC", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * MP3 mux element default value + */ +static type_element _mp3mux_element_default = { + "MP3", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * OGG element default value + */ +static type_element _ogg_element_default = { + "OGG", + "oggmux", + NULL, + 0, + NULL, + 0, +}; + +/* + * WAV element default value + */ +static type_element _wav_element_default = { + "WAV", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * AVI element default value + */ +static type_element _avi_element_default = { + "AVI", + "avimux", + NULL, + 0, + NULL, + 0, +}; + +/* + * WMA element default value + */ +static type_element _wma_element_default = { + "WMA", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * WMV element default value + */ +static type_element _wmv_element_default = { + "WMV", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * MID element default value + */ +static type_element _mid_element_default = { + "MID", + NULL, + NULL, + 0, + NULL, + 0, +}; + +/* + * MMF mux element default value + */ +static type_element _mmfmux_element_default = { + "MMF", + "ffmux_mmf", + NULL, + 0, + NULL, + 0, +}; + +/* + * MATROSKA element default value + */ +static type_element _matroska_element_default = { + "MATROSKA", + "matroskamux", + NULL, + 0, + NULL, + 0, +}; + +/* + * [General] matching table + */ +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} }, +}; + +/* + * [VideoInput] matching 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} }, + { "UseVideoscale", CONFIGURE_VALUE_INT, {0} }, + { "VideoscaleElement", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_videoscale_element_default} }, + { "UseZeroCopyFormat", CONFIGURE_VALUE_INT, {0} }, +}; + +/* + * [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} }, +}; + +/* + * [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} }, + { "UseVideoscale", CONFIGURE_VALUE_INT, {0} }, + { "VideoscaleElement", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_videoscale_element_default} }, +}; + +/* + * [Capture] matching 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} }, +}; + +/* + * [Record] matching table + */ +static conf_info_table conf_main_record_table[] = { + { "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} }, + { "VideoAutoColorSpace", CONFIGURE_VALUE_INT, {0} }, + { "AudioProfile", CONFIGURE_VALUE_INT, {0} }, + { "AudioAutoAudioConvert", CONFIGURE_VALUE_INT, {0} }, + { "AudioAutoAudioResample", CONFIGURE_VALUE_INT, {0} }, + { "AudioAutoColorSpace", CONFIGURE_VALUE_INT, {0} }, + { "ImageProfile", CONFIGURE_VALUE_INT, {0} }, + { "ImageAutoAudioConvert", CONFIGURE_VALUE_INT, {0} }, + { "ImageAutoAudioResample", CONFIGURE_VALUE_INT, {0} }, + { "ImageAutoColorSpace", CONFIGURE_VALUE_INT, {0} }, + { "RecordsinkElement", CONFIGURE_VALUE_ELEMENT, {(type_element*)&_recordsink_element_default} }, + { "UseNoiseSuppressor", CONFIGURE_VALUE_INT, {0} }, + { "DropVideoFrame", CONFIGURE_VALUE_INT, {0} }, + { "PassFirstVideoFrame", CONFIGURE_VALUE_INT, {0} }, +}; + +/* + * [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} }, +}; + +/* + * [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} }, +}; + +/* + * [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} }, +}; + +/* + * [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} }, +}; + + +/******************* + * Camera control * + *******************/ + +/* + * [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} }, + { "RecommendDisplayRotation", CONFIGURE_VALUE_INT, {3} }, + { "RecommendPreviewFormatCapture", CONFIGURE_VALUE_INT, {MM_PIXEL_FORMAT_YUYV} }, + { "RecommendPreviewFormatRecord", CONFIGURE_VALUE_INT, {MM_PIXEL_FORMAT_NV12} }, +}; + +/* + * [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} }, +}; + +/* + * [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} }, +}; + +/* + * [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} }, +}; + +/* + * [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} }, + { "SensorEncodedCapture", CONFIGURE_VALUE_INT, {1} }, +}; + +/* + * [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} }, +}; + + + +char* +get_new_string( char* src_string ) +{ + return strdup(src_string); +} + +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..." ); + + 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; + conf_main_info_table[CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT] = conf_main_video_output_table; + conf_main_info_table[CONFIGURE_CATEGORY_MAIN_CAPTURE] = conf_main_capture_table; + conf_main_info_table[CONFIGURE_CATEGORY_MAIN_RECORD] = conf_main_record_table; + conf_main_info_table[CONFIGURE_CATEGORY_MAIN_VIDEO_ENCODER] = conf_main_video_encoder_table; + conf_main_info_table[CONFIGURE_CATEGORY_MAIN_AUDIO_ENCODER] = conf_main_audio_encoder_table; + conf_main_info_table[CONFIGURE_CATEGORY_MAIN_IMAGE_ENCODER] = conf_main_image_encoder_table; + conf_main_info_table[CONFIGURE_CATEGORY_MAIN_MUX] = conf_main_mux_table; + + conf_main_category_size[CONFIGURE_CATEGORY_MAIN_GENERAL] = sizeof( conf_main_general_table ) / info_table_size; + conf_main_category_size[CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT] = sizeof( conf_main_video_input_table ) / info_table_size; + conf_main_category_size[CONFIGURE_CATEGORY_MAIN_AUDIO_INPUT] = sizeof( conf_main_audio_input_table ) / info_table_size; + conf_main_category_size[CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT] = sizeof( conf_main_video_output_table ) / info_table_size; + conf_main_category_size[CONFIGURE_CATEGORY_MAIN_CAPTURE] = sizeof( conf_main_capture_table ) / info_table_size; + conf_main_category_size[CONFIGURE_CATEGORY_MAIN_RECORD] = sizeof( conf_main_record_table ) / info_table_size; + conf_main_category_size[CONFIGURE_CATEGORY_MAIN_VIDEO_ENCODER] = sizeof( conf_main_video_encoder_table ) / info_table_size; + conf_main_category_size[CONFIGURE_CATEGORY_MAIN_AUDIO_ENCODER] = sizeof( conf_main_audio_encoder_table ) / info_table_size; + conf_main_category_size[CONFIGURE_CATEGORY_MAIN_IMAGE_ENCODER] = sizeof( conf_main_image_encoder_table ) / info_table_size; + conf_main_category_size[CONFIGURE_CATEGORY_MAIN_MUX] = sizeof( conf_main_mux_table ) / info_table_size; + + (*configure_info)->info = (conf_info**)g_malloc0( sizeof( conf_info* ) * CONFIGURE_CATEGORY_MAIN_NUM ); + + for( i = 0 ; i < CONFIGURE_CATEGORY_MAIN_NUM ; i++ ) + { + (*configure_info)->info[i] = NULL; + } + } + 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; + conf_ctrl_info_table[CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH] = conf_ctrl_photograph_table; + conf_ctrl_info_table[CONFIGURE_CATEGORY_CTRL_CAPTURE] = conf_ctrl_capture_table; + conf_ctrl_info_table[CONFIGURE_CATEGORY_CTRL_DETECT] = conf_ctrl_detect_table; + + conf_ctrl_category_size[CONFIGURE_CATEGORY_CTRL_CAMERA] = sizeof( conf_ctrl_camera_table ) / info_table_size; + conf_ctrl_category_size[CONFIGURE_CATEGORY_CTRL_STROBE] = sizeof( conf_ctrl_strobe_table ) / info_table_size; + conf_ctrl_category_size[CONFIGURE_CATEGORY_CTRL_EFFECT] = sizeof( conf_ctrl_effect_table ) / info_table_size; + conf_ctrl_category_size[CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH] = sizeof( conf_ctrl_photograph_table ) / info_table_size; + conf_ctrl_category_size[CONFIGURE_CATEGORY_CTRL_CAPTURE] = sizeof( conf_ctrl_capture_table ) / info_table_size; + conf_ctrl_category_size[CONFIGURE_CATEGORY_CTRL_DETECT] = sizeof( conf_ctrl_detect_table ) / info_table_size; + + (*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; + } + } + + _mmcam_dbg_log( "Done." ); + +} + + +int +_mmcamcorder_conf_get_info( int type, char* ConfFile, camera_conf** configure_info ) +{ + int ret = MM_ERROR_NONE; + FILE* fd = NULL; + char* conf_path = NULL; + + _mmcam_dbg_log( "Opening...[%s]", ConfFile ); + + mmf_return_val_if_fail( ConfFile, FALSE ); + + conf_path = (char*)malloc( strlen(ConfFile)+strlen(CONFIGURE_PATH)+3 ); + + if( conf_path == NULL ) + { + _mmcam_dbg_err( "malloc failed." ); + return MM_ERROR_CAMCORDER_LOW_MEMORY; + } + + snprintf( conf_path, strlen(ConfFile)+strlen(CONFIGURE_PATH)+2, "%s/%s", CONFIGURE_PATH, ConfFile ); + _mmcam_dbg_log( "Try open Configure File[%s]", conf_path ); + + fd = fopen( conf_path, "r" ); + if( fd == NULL ) + { + _mmcam_dbg_warn( "File open failed.[%s] retry...", conf_path ); + snprintf( conf_path, strlen(ConfFile)+strlen(CONFIGURE_PATH_RETRY)+2, "%s/%s", CONFIGURE_PATH_RETRY, ConfFile ); + _mmcam_dbg_log( "Try open Configure File[%s]", conf_path ); + fd = fopen( conf_path, "r" ); + if( fd == NULL ) + { + _mmcam_dbg_warn( "File open failed.[%s] But keep going... All value will be returned as default.Type[%d]", + conf_path, type ); + } + } + + if( fd != NULL ) + { + ret = _mmcamcorder_conf_parse_info( type, fd, configure_info ); + fclose( fd ); + } + else + { + ret = MM_ERROR_CAMCORDER_CREATE_CONFIGURE; + } + + if( conf_path != NULL ) + { + free( conf_path ); + conf_path = NULL; + } + + _mmcam_dbg_log( "Leave..." ); + + return ret; +} + +int +_mmcamcorder_conf_parse_info( int type, FILE* fd, camera_conf** configure_info ) +{ + const unsigned int BUFFER_NUM_DETAILS = 256; + const unsigned int BUFFER_NUM_TOKEN = 20; + size_t BUFFER_LENGTH_STRING = 256; + const char* delimiters = " |=,\t\n"; + + int category = 0; + int count_main_category = 0; + int count_details = 0; + int length_read = 0; + int count_token = 0; + int read_main = 0; + + char *buffer_string = (char*)g_malloc0(sizeof(char)*BUFFER_LENGTH_STRING); + char *buffer_details[BUFFER_NUM_DETAILS]; + char *buffer_token[BUFFER_NUM_TOKEN]; + char *token = NULL; + char *category_name = NULL; + char *detail_string = NULL; + char *user_ptr = NULL; + + _mmcam_dbg_log( "" ); + + camera_conf* new_conf = (camera_conf*)g_malloc0(sizeof(camera_conf)); + + if( new_conf == NULL ) + { + _mmcam_dbg_err( "Failed to create new configure structure.type[%d]", type ); + *configure_info = NULL; + + return MM_ERROR_CAMCORDER_LOW_MEMORY; + } + + new_conf->type = type; + *configure_info = new_conf; + + _mmcamcorder_conf_init( type, &new_conf ); + + mmf_return_val_if_fail( fd > 0, MM_ERROR_CAMCORDER_INVALID_ARGUMENT ); + + read_main = 0; + count_main_category = 0; + + while( !feof( fd ) ) + { + if( read_main == 0 ) + { + length_read = getline( &buffer_string, &BUFFER_LENGTH_STRING, fd ); + /*_mmcam_dbg_log( "Read Line : [%s]", buffer_string );*/ + + count_token = 0; + token = strtok_r( buffer_string, delimiters, &user_ptr ); + + if ((token) && (token[0] == ';')) + { + /*_mmcam_dbg_log( "Comment - Nothing to do" );*/ + continue; + } + + while( token ) + { + /*_mmcam_dbg_log( "token : [%s]", token );*/ + buffer_token[count_token] = token; + count_token++; + token = strtok_r( NULL, delimiters, &user_ptr ); + } + + if( count_token == 0 ) + { + continue; + } + } + + read_main = 0; + + /* Comment */ + if( *buffer_token[0] == ';' ) + { + /*_mmcam_dbg_log( "Comment - Nothing to do" );*/ + } + /* Main Category */ + else if( *buffer_token[0] == '[' ) + { + category_name = get_new_string( buffer_token[0] ); + + count_main_category++; + count_details = 0; + + while( !feof( fd ) ) + { + length_read = getline( &buffer_string, &BUFFER_LENGTH_STRING, fd ); + /*_mmcam_dbg_log( "Read Detail Line : [%s], read length : [%d]", buffer_string, length_read );*/ + + detail_string = get_new_string( buffer_string ); + + token = strtok_r( buffer_string, delimiters, &user_ptr ); + + if( token && token[0] != ';' && length_read > -1 ) + { + /*_mmcam_dbg_log( "token : [%s]", token );*/ + if( token[0] == '[' ) + { + read_main = 1; + buffer_token[0] = token; + SAFE_FREE( detail_string ); + break; + } + + buffer_details[count_details++] = detail_string; + } + else + { + SAFE_FREE( detail_string ); + } + } + + _mmcam_dbg_log( "type : %d, category_name : %s, count : [%d]", type, category_name, count_details ); + + if( count_details == 0 ) + { + _mmcam_dbg_warn( "category %s has no detail value... skip this category...", category_name ); + continue; + } + + category = -1; + + /* Details */ + if( type == CONFIGURE_TYPE_MAIN ) + { + if( !strcmp( "[General]", category_name ) ) + { + category = CONFIGURE_CATEGORY_MAIN_GENERAL; + } + else if( !strcmp( "[VideoInput]", category_name ) ) + { + category = CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT; + } + else if( !strcmp( "[AudioInput]", category_name ) ) + { + category = CONFIGURE_CATEGORY_MAIN_AUDIO_INPUT; + } + else if( !strcmp( "[VideoOutput]", category_name ) ) + { + category = CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT; + } + else if( !strcmp( "[Capture]", category_name ) ) + { + category = CONFIGURE_CATEGORY_MAIN_CAPTURE; + } + else if( !strcmp( "[Record]", category_name ) ) + { + category = CONFIGURE_CATEGORY_MAIN_RECORD; + } + else if( !strcmp( "[VideoEncoder]", category_name ) ) + { + category = CONFIGURE_CATEGORY_MAIN_VIDEO_ENCODER; + } + else if( !strcmp( "[AudioEncoder]", category_name ) ) + { + category = CONFIGURE_CATEGORY_MAIN_AUDIO_ENCODER; + } + else if( !strcmp( "[ImageEncoder]", category_name ) ) + { + category = CONFIGURE_CATEGORY_MAIN_IMAGE_ENCODER; + } + else if( !strcmp( "[Mux]", category_name ) ) + { + category = CONFIGURE_CATEGORY_MAIN_MUX; + } + } + else + { + if( !strcmp( "[Camera]", category_name ) ) + { + category = CONFIGURE_CATEGORY_CTRL_CAMERA; + } + else if( !strcmp( "[Strobe]", category_name ) ) + { + category = CONFIGURE_CATEGORY_CTRL_STROBE; + } + else if( !strcmp( "[Effect]", category_name ) ) + { + category = CONFIGURE_CATEGORY_CTRL_EFFECT; + } + else if( !strcmp( "[Photograph]", category_name ) ) + { + category = CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH; + } + else if( !strcmp( "[Capture]", category_name ) ) + { + category = CONFIGURE_CATEGORY_CTRL_CAPTURE; + } + else if( !strcmp( "[Detect]", category_name ) ) + { + category = CONFIGURE_CATEGORY_CTRL_DETECT; + } + } + + if( category != -1 ) + { + _mmcamcorder_conf_add_info( type, &(new_conf->info[category]), + buffer_details, category, count_details ); + } + else + { + _mmcam_dbg_warn( "No matched category[%s],type[%d]... check it.", category_name, type ); + } + + // Free memory + { + int i; + + for( i = 0 ; i < count_details ; i++ ) + { + SAFE_FREE( buffer_details[i] ); + } + } + } + + if( category_name ) + { + SAFE_FREE( category_name ); + } + } + + //(*configure_info) = new_conf; + + SAFE_FREE( buffer_string ); + + _mmcam_dbg_log( "Done." ); + + return MM_ERROR_NONE; +} + + +void +_mmcamcorder_conf_release_info( camera_conf** configure_info ) +{ + int i, j, k, type, count, category_num; + camera_conf* temp_conf = (*configure_info); + + type_int* temp_int; + type_int_range* temp_int_range; + type_int_array* temp_int_array; + type_int_pair_array* temp_int_pair_array; + type_string* temp_string; + type_string_array* temp_string_array; + type_element* temp_element; + + _mmcam_dbg_log( "Entered..." ); + + mmf_return_if_fail( temp_conf ); + + if( (*configure_info)->type == CONFIGURE_TYPE_MAIN ) + { + category_num = CONFIGURE_CATEGORY_MAIN_NUM; + } + else + { + category_num = CONFIGURE_CATEGORY_CTRL_NUM; + } + + for( i = 0 ; i < category_num ; i++ ) + { + if( temp_conf->info[i] ) + { + for( j = 0 ; j < temp_conf->info[i]->count ; j++ ) + { + if( temp_conf->info[i]->detail_info[j] == NULL ) + { + continue; + } + + if( _mmcamcorder_conf_get_value_type( temp_conf->type, i, ((type_element*)(temp_conf->info[i]->detail_info[j]))->name, &type ) ) + { + switch( type ) + { + case CONFIGURE_VALUE_INT: + { + temp_int = (type_int*)(temp_conf->info[i]->detail_info[j]); + SAFE_FREE( temp_int->name ); + } + break; + case CONFIGURE_VALUE_INT_RANGE: + { + temp_int_range = (type_int_range*)(temp_conf->info[i]->detail_info[j]); + SAFE_FREE( temp_int_range->name ); + } + break; + case CONFIGURE_VALUE_INT_ARRAY: + { + temp_int_array = (type_int_array*)(temp_conf->info[i]->detail_info[j]); + SAFE_FREE( temp_int_array->name ); + SAFE_FREE( temp_int_array->value ); + } + break; + case CONFIGURE_VALUE_INT_PAIR_ARRAY: + { + temp_int_pair_array = (type_int_pair_array*)(temp_conf->info[i]->detail_info[j]); + SAFE_FREE( temp_int_pair_array->name ); + SAFE_FREE( temp_int_pair_array->value[0] ); + SAFE_FREE( temp_int_pair_array->value[1] ); + } + break; + case CONFIGURE_VALUE_STRING: + { + temp_string = (type_string*)(temp_conf->info[i]->detail_info[j]); + SAFE_FREE( temp_string->name ); + SAFE_FREE( temp_string->value ); + } + break; + case CONFIGURE_VALUE_STRING_ARRAY: + { + temp_string_array = (type_string_array*)(temp_conf->info[i]->detail_info[j]); + SAFE_FREE( temp_string_array->name ); + + count = temp_string_array->count; + for( k = 0 ; k < count ; k++ ) + { + SAFE_FREE( temp_string_array->value[k] ); + } + SAFE_FREE( temp_string_array->value ); + + SAFE_FREE( temp_string_array->default_value ); + } + break; + case CONFIGURE_VALUE_ELEMENT: + { + temp_element = (type_element*)(temp_conf->info[i]->detail_info[j]); + SAFE_FREE( temp_element->name ); + SAFE_FREE( temp_element->element_name ); + + count = temp_element->count_int; + for( k = 0 ; k < count ; k++ ) + { + SAFE_FREE( temp_element->value_int[k]->name ); + SAFE_FREE( temp_element->value_int[k] ); + } + SAFE_FREE( temp_element->value_int ); + + count = temp_element->count_string; + for( k = 0 ; k < count ; k++ ) + { + SAFE_FREE( temp_element->value_string[k]->name ); + SAFE_FREE( temp_element->value_string[k]->value ); + SAFE_FREE( temp_element->value_string[k] ); + } + SAFE_FREE( temp_element->value_string ); + } + break; + } + } + + SAFE_FREE( temp_conf->info[i]->detail_info[j] ); + temp_conf->info[i]->detail_info[j] = NULL; + } + + SAFE_FREE( temp_conf->info[i]->detail_info ); + temp_conf->info[i]->detail_info = NULL; + + SAFE_FREE( temp_conf->info[i] ); + temp_conf->info[i] = NULL; + } + } + + SAFE_FREE( (*configure_info)->info ); + SAFE_FREE( (*configure_info) ); + + _mmcam_dbg_log( "Done." ); +} + +int +_mmcamcorder_conf_get_value_type( int type, int category, char* name, int* value_type ) +{ + int i = 0; + int count_value = 0; + + /*_mmcam_dbg_log( "Entered..." );*/ + + mmf_return_val_if_fail( name, FALSE ); + + if( !_mmcamcorder_conf_get_category_size( type, category, &count_value ) ) + { + _mmcam_dbg_warn( "No matched category... check it... categoty[%d]", category ); + return FALSE; + } + + /*_mmcam_dbg_log( "Number of value : [%d]", count_value );*/ + + if( type == CONFIGURE_TYPE_MAIN ) + { + for( i = 0 ; i < count_value ; i++ ) + { + if( !strcmp( conf_main_info_table[category][i].name, name ) ) + { + *value_type = conf_main_info_table[category][i].value_type; + /*_mmcam_dbg_log( "Category[%d],Name[%s],Type[%d]", category, name, *value_type );*/ + return TRUE; + } + } + } + else + { + for( i = 0 ; i < count_value ; i++ ) + { + if( !strcmp( conf_ctrl_info_table[category][i].name, name ) ) + { + *value_type = conf_ctrl_info_table[category][i].value_type; + /*_mmcam_dbg_log( "Category[%d],Name[%s],Type[%d]", category, name, *value_type );*/ + return TRUE; + } + } + } + + return FALSE; +} + + +int +_mmcamcorder_conf_add_info( int type, conf_info** info, char** buffer_details, int category, int count_details ) +{ + const int BUFFER_NUM_TOKEN = 256; + + int i = 0; + int j = 0; + int count_token; + int value_type; + char *token = NULL; + char *buffer_token[BUFFER_NUM_TOKEN]; + char *user_ptr = NULL; + + const char *delimiters = " |=,\t\n"; + const char *delimiters_sub = " |\t\n"; + const char *delimiters_3rd = "|\n"; + + mmf_return_val_if_fail( buffer_details, FALSE ); + + (*info) = (conf_info*)g_malloc0( sizeof(conf_info) ); + (*info)->detail_info = (void**)g_malloc0(sizeof(void*) * count_details); + (*info)->count = count_details; + + for ( i = 0 ; i < count_details ; i++ ) { + /*_mmcam_dbg_log("Read line\"%s\"", buffer_details[i]);*/ + count_token = 0; + token = strtok_r( buffer_details[i], delimiters, &user_ptr ); + + if (token) { + buffer_token[count_token] = token; + count_token++; + } else { + (*info)->detail_info[i] = NULL; + _mmcam_dbg_warn( "No token... check it.[%s]", buffer_details[i] ); + continue; + } + + if (!_mmcamcorder_conf_get_value_type(type, category, buffer_token[0], &value_type)) { + (*info)->detail_info[i] = NULL; + _mmcam_dbg_warn( "Failed to get value type... check it. Category[%d],Name[%s]", category, buffer_token[0] ); + continue; + } + + if (value_type != CONFIGURE_VALUE_STRING && value_type != CONFIGURE_VALUE_STRING_ARRAY) { + token = strtok_r( NULL, delimiters, &user_ptr ); + while (token) { + buffer_token[count_token] = token; + /*_mmcam_dbg_log("token : [%s]", buffer_token[count_token]);*/ + count_token++; + token = strtok_r( NULL, delimiters, &user_ptr ); + } + + if (count_token < 2) { + (*info)->detail_info[i] = NULL; + _mmcam_dbg_warn( "Number of token is too small... check it.[%s]", buffer_details[i] ); + continue; + } + } else { /* CONFIGURE_VALUE_STRING or CONFIGURE_VALUE_STRING_ARRAY */ + /* skip "=" */ + strtok_r( NULL, delimiters_sub, &user_ptr ); + + if (value_type == CONFIGURE_VALUE_STRING_ARRAY) { + token = strtok_r( NULL, delimiters_sub, &user_ptr ); + while (token) { + buffer_token[count_token] = token; + /*_mmcam_dbg_log("token : [%s]", buffer_token[count_token]);*/ + count_token++; + token = strtok_r( NULL, delimiters_sub, &user_ptr ); + } + } else { /* CONFIGURE_VALUE_STRING */ + token = strtok_r( NULL, delimiters_3rd, &user_ptr ); + if (token) { + g_strchug( token ); + buffer_token[count_token] = token; + /*_mmcam_dbg_log("token : [%s]", buffer_token[count_token]);*/ + count_token++; + } + } + + if (count_token < 2) { + (*info)->detail_info[i] = NULL; + _mmcam_dbg_warn( "No string value... check it.[%s]", buffer_details[i] ); + continue; + } + } + + switch (value_type) + { + case CONFIGURE_VALUE_INT: + { + type_int* new_int; + + new_int = (type_int*)g_malloc0( sizeof(type_int) ); + new_int->name = get_new_string( buffer_token[0] ); + new_int->value = atoi( buffer_token[1] ); + (*info)->detail_info[i] = (void*)new_int; + /*_mmcam_dbg_log("INT - name[%s],value[%d]", new_int->name, new_int->value);*/ + break; + } + case CONFIGURE_VALUE_INT_RANGE: + { + type_int_range* new_int_range; + + new_int_range = (type_int_range*)g_malloc0( sizeof(type_int_range) ); + new_int_range->name = get_new_string( buffer_token[0] ); + new_int_range->min = atoi( buffer_token[1] ); + new_int_range->max = atoi( buffer_token[2] ); + new_int_range->default_value = atoi( buffer_token[3] ); + (*info)->detail_info[i] = (void*)new_int_range; + /* + _mmcam_dbg_log("INT RANGE - name[%s],min[%d],max[%d],default[%d]", + new_int_range->name, + new_int_range->min, + new_int_range->max, + new_int_range->default_value); + */ + break; + } + case CONFIGURE_VALUE_INT_ARRAY: + { + int count_value = count_token - 2; + type_int_array* new_int_array; + + new_int_array = (type_int_array*)g_malloc0( sizeof(type_int_array) ); + new_int_array->name = get_new_string( buffer_token[0] ); + new_int_array->value = (int*)g_malloc0( sizeof(int)*count_value ); + new_int_array->count = count_value; + + /*_mmcam_dbg_log("INT ARRAY - name[%s]", new_int_array->name);*/ + for ( j = 0 ; j < count_value ; j++ ) { + new_int_array->value[j] = atoi( buffer_token[j+1] ); + /*_mmcam_dbg_log(" index[%d] - value[%d]", j, new_int_array->value[j]);*/ + } + + new_int_array->default_value = atoi( buffer_token[count_token-1] ); + /*_mmcam_dbg_log(" default value[%d]", new_int_array->default_value);*/ + + (*info)->detail_info[i] = (void*)new_int_array; + break; + } + case CONFIGURE_VALUE_INT_PAIR_ARRAY: + { + int count_value = ( count_token - 3 ) >> 1; + type_int_pair_array* new_int_pair_array; + + new_int_pair_array = (type_int_pair_array*)g_malloc0( sizeof(type_int_pair_array) ); + new_int_pair_array->name = get_new_string( buffer_token[0] ); + new_int_pair_array->value[0] = (int*)g_malloc( sizeof(int)*(count_value) ); + new_int_pair_array->value[1] = (int*)g_malloc( sizeof(int)*(count_value) ); + new_int_pair_array->count = count_value; + + /*_mmcam_dbg_log("INT PAIR ARRAY - name[%s],count[%d]", new_int_pair_array->name, count_value);*/ + for ( j = 0 ; j < count_value ; j++ ) { + new_int_pair_array->value[0][j] = atoi( buffer_token[(j<<1)+1] ); + new_int_pair_array->value[1][j] = atoi( buffer_token[(j<<1)+2] ); + /* + _mmcam_dbg_log(" index[%d] - value[%d,%d]", j, + new_int_pair_array->value[0][j], + new_int_pair_array->value[1][j]); + */ + } + + new_int_pair_array->default_value[0] = atoi( buffer_token[count_token-2] ); + new_int_pair_array->default_value[1] = atoi( buffer_token[count_token-1] ); + /* + _mmcam_dbg_log(" default value[%d,%d]", + new_int_pair_array->default_value[0], + new_int_pair_array->default_value[1]); + */ + (*info)->detail_info[i] = (void*)new_int_pair_array; + break; + } + case CONFIGURE_VALUE_STRING: + { + type_string* new_string; + + new_string = (type_string*)g_malloc0( sizeof(type_string) ); + new_string->name = get_new_string( buffer_token[0] ); + new_string->value = get_new_string( buffer_token[1] ); + (*info)->detail_info[i] = (void*)new_string; + + /*_mmcam_dbg_log("STRING - name[%s],value[%s]", new_string->name, new_string->value);*/ + break; + } + case CONFIGURE_VALUE_STRING_ARRAY: + { + int count_value = count_token - 2; + type_string_array* new_string_array; + + new_string_array = (type_string_array*)g_malloc0( sizeof(type_string_array) ); + new_string_array->name = get_new_string( buffer_token[0] ); + new_string_array->count = count_value; + new_string_array->value = (char**)g_malloc0( sizeof(char*)*count_value );; + + /*_mmcam_dbg_log("STRING ARRAY - name[%s]", new_string_array->name);*/ + for ( j = 0 ; j < count_value ; j++ ) { + new_string_array->value[j] = get_new_string( buffer_token[j+1] ); + /*_mmcam_dbg_log(" index[%d] - value[%s]", j, new_string_array->value[j]);*/ + } + + new_string_array->default_value = get_new_string( buffer_token[count_token-1] ); + /*_mmcam_dbg_log(" default value[%s]", new_string_array->default_value);*/ + (*info)->detail_info[i] = (void*)new_string_array; + break; + } + case CONFIGURE_VALUE_ELEMENT: + { + type_element* new_element; + + new_element = (type_element*)g_malloc0( sizeof(type_element) ); + new_element->name = get_new_string( buffer_token[0] ); + new_element->element_name = get_new_string( buffer_token[1] ); + new_element->count_int = atoi( buffer_token[2] ); + new_element->value_int = NULL; + new_element->count_string = atoi( buffer_token[3] ); + new_element->value_string = NULL; + /* + _mmcam_dbg_log("Element - name[%s],element_name[%s],count_int[%d],count_string[%d]", + new_element->name, new_element->element_name, new_element->count_int, new_element->count_string); + */ + + /* add int values */ + if ( new_element->count_int > 0 ) { + new_element->value_int = (type_int**)g_malloc0( sizeof(type_int*)*(new_element->count_int) ); + + for ( j = 0 ; j < new_element->count_int ; j++ ) { + new_element->value_int[j] = (type_int*)g_malloc( sizeof(type_int) ); + new_element->value_int[j]->name = get_new_string( buffer_token[4+(j<<1)] ); + new_element->value_int[j]->value = atoi( buffer_token[5+(j<<1)] ); + /* + _mmcam_dbg_log(" Element INT[%d] - name[%s],value[%d]", + j, new_element->value_int[j]->name, new_element->value_int[j]->value); + */ + } + } + else + { + new_element->value_int = NULL; + } + + /* add string values */ + if ( new_element->count_string > 0 ) { + new_element->value_string = (type_string**)g_malloc0( sizeof(type_string*)*(new_element->count_string) ); + for ( ; j < new_element->count_string + new_element->count_int ; j++ ) { + new_element->value_string[j-new_element->count_int] = (type_string*)g_malloc0( sizeof(type_string) ); + new_element->value_string[j-new_element->count_int]->name = get_new_string( buffer_token[4+(j<<1)] ); + new_element->value_string[j-new_element->count_int]->value = get_new_string( buffer_token[5+(j<<1)] ); + /* + _mmcam_dbg_log(" Element STRING[%d] - name[%s],value[%s]", + j-new_element->count_int, new_element->value_string[j-new_element->count_int]->name, new_element->value_string[j-new_element->count_int]->value); + */ + } + } else { + new_element->value_string = NULL; + } + + (*info)->detail_info[i] = (void*)new_element; + break; + } + default: + break; + } + } + + return TRUE; +} + + +int +_mmcamcorder_conf_add_info_with_caps( int type, conf_info** info, char** buffer_details, int category, int count_details ) +{ + const int BUFFER_NUM_TOKEN = 256; + + int i = 0; + int j = 0; + int count_token = 0; + int value_type = 0; + char *token = NULL; + char *buffer_token[BUFFER_NUM_TOKEN]; + char *user_ptr = NULL; + + const char* delimiters = " |=,\t\n"; + const char* delimiters_sub = " |\t\n"; + const char* delimiters_3rd = "|\n"; + + //_mmcam_dbg_log( "" ); + + mmf_return_val_if_fail( buffer_details, FALSE ); + + (*info) = (conf_info*)g_malloc0( sizeof(conf_info) ); + (*info)->detail_info = (void**)g_malloc0( sizeof(void*)*count_details ); + (*info)->count = count_details; + + //g_print( "Count[%d]\n", (*info)->count ); + //g_print( "Pointer[%x]\n", (*info) ); + + for( i = 0 ; i < count_details ; i++ ) + { + //_mmcam_dbg_log( "Read line\"%s\"", buffer_details[i] ); + + count_token = 0; + token = strtok_r( buffer_details[i], delimiters, &user_ptr ); + + if( token ) + { + buffer_token[count_token] = token; + count_token++; + } + else + { + (*info)->detail_info[i] = NULL; + _mmcam_dbg_warn( "No token... check it.[%s]", buffer_details[i] ); + continue; + } + + if( !_mmcamcorder_conf_get_value_type( type, category, buffer_token[0], &value_type ) ) + { + (*info)->detail_info[i] = NULL; + _mmcam_dbg_warn( "Failed to get value type... check it. Category[%d],Name[%s]", category, buffer_token[0] ); + continue; + } + + if( value_type != CONFIGURE_VALUE_STRING && value_type != CONFIGURE_VALUE_STRING_ARRAY ) + { + token = strtok_r( NULL, delimiters, &user_ptr ); + + while( token ) + { + buffer_token[count_token] = token; + //_mmcam_dbg_log( "token : [%s]", buffer_token[count_token] ); + count_token++; + token = strtok_r( NULL, delimiters, &user_ptr ); + } + + if( count_token < 2 ) + { + (*info)->detail_info[i] = NULL; + _mmcam_dbg_warn( "Number of token is too small... check it.[%s]", buffer_details[i] ); + continue; + } + } + else // CONFIGURE_VALUE_STRING or CONFIGURE_VALUE_STRING_ARRAY + { + // skip "=" + strtok_r( NULL, delimiters_sub, &user_ptr ); + + if( value_type == CONFIGURE_VALUE_STRING_ARRAY ) + { + token = strtok_r( NULL, delimiters_sub, &user_ptr ); + + while( token ) + { + buffer_token[count_token] = token; + //_mmcam_dbg_log( "token : [%s]", buffer_token[count_token] ); + count_token++; + token = strtok_r( NULL, delimiters_sub, &user_ptr ); + } + } + else // CONFIGURE_VALUE_STRING + { + token = strtok_r( NULL, delimiters_3rd, &user_ptr ); + + if( token ) + { + g_strchug( token ); + buffer_token[count_token] = token; + //_mmcam_dbg_log( "token : [%s]", buffer_token[count_token] ); + count_token++; + } + } + + if( count_token < 2 ) + { + (*info)->detail_info[i] = NULL; + _mmcam_dbg_warn( "No string value... check it.[%s]", buffer_details[i] ); + continue; + } + } + + switch( value_type ) + { + case CONFIGURE_VALUE_INT: + { + type_int* new_int; + + new_int = (type_int*)g_malloc0( sizeof(type_int) ); + new_int->name = get_new_string( buffer_token[0] ); + new_int->value = atoi( buffer_token[1] ); + (*info)->detail_info[i] = (void*)new_int; + + //_mmcam_dbg_log( "INT - name[%s],value[%d]", new_int->name, new_int->value ); + break; + } + case CONFIGURE_VALUE_INT_RANGE: + { + type_int_range* new_int_range; + + new_int_range = (type_int_range*)g_malloc0( sizeof(type_int_range) ); + new_int_range->name = get_new_string( buffer_token[0] ); + new_int_range->min = atoi( buffer_token[1] ); + new_int_range->max = atoi( buffer_token[2] ); + new_int_range->default_value = atoi( buffer_token[3] ); + (*info)->detail_info[i] = (void*)new_int_range; + + /* + _mmcam_dbg_log( "INT RANGE - name[%s],min[%d],max[%d],default[%d]", + new_int_range->name, + new_int_range->min, + new_int_range->max, + new_int_range->default_value ); + */ + break; + } + case CONFIGURE_VALUE_INT_ARRAY: + { + int count_value = count_token - 2; + type_int_array* new_int_array; + + new_int_array = (type_int_array*)g_malloc0( sizeof(type_int_array) ); + new_int_array->name = get_new_string( buffer_token[0] ); + new_int_array->value = (int*)g_malloc0( sizeof(int)*count_value ); + new_int_array->count = count_value; + + //_mmcam_dbg_log( "INT ARRAY - name[%s]", new_int_array->name ); + for( j = 0 ; j < count_value ; j++ ) + { + new_int_array->value[j] = atoi( buffer_token[j+1] ); + //_mmcam_dbg_log( " index[%d] - value[%d]", j, new_int_array->value[j] ); + } + + new_int_array->default_value = atoi( buffer_token[count_token-1] ); + //_mmcam_dbg_log( " default value[%d]", new_int_array->default_value ); + + (*info)->detail_info[i] = (void*)new_int_array; + break; + } + case CONFIGURE_VALUE_INT_PAIR_ARRAY: + { + int count_value = ( count_token - 3 ) >> 1; + type_int_pair_array* new_int_pair_array; + + new_int_pair_array = (type_int_pair_array*)g_malloc0( sizeof(type_int_pair_array) ); + new_int_pair_array->name = get_new_string( buffer_token[0] ); + new_int_pair_array->value[0] = (int*)g_malloc( sizeof(int)*(count_value) ); + new_int_pair_array->value[1] = (int*)g_malloc( sizeof(int)*(count_value) ); + new_int_pair_array->count = count_value; + + //_mmcam_dbg_log( "INT PAIR ARRAY - name[%s],count[%d]", new_int_pair_array->name, count_value ); + for( j = 0 ; j < count_value ; j++ ) + { + new_int_pair_array->value[0][j] = atoi( buffer_token[(j<<1)+1] ); + new_int_pair_array->value[1][j] = atoi( buffer_token[(j<<1)+2] ); + /* + _mmcam_dbg_log( " index[%d] - value[%d,%d]", j, + new_int_pair_array->value[0][j], + new_int_pair_array->value[1][j] ); + */ + } + + new_int_pair_array->default_value[0] = atoi( buffer_token[count_token-2] ); + new_int_pair_array->default_value[1] = atoi( buffer_token[count_token-1] ); + + /* + _mmcam_dbg_log( " default value[%d,%d]", + new_int_pair_array->default_value[0], + new_int_pair_array->default_value[1] ); + */ + + + (*info)->detail_info[i] = (void*)new_int_pair_array; + break; + } + case CONFIGURE_VALUE_STRING: + { + type_string* new_string; + + new_string = (type_string*)g_malloc0( sizeof(type_string) ); + new_string->name = get_new_string( buffer_token[0] ); + new_string->value = get_new_string( buffer_token[1] ); + (*info)->detail_info[i] = (void*)new_string; + + //_mmcam_dbg_log( "STRING - name[%s],value[%s]", new_string->name, new_string->value ); + break; + } + case CONFIGURE_VALUE_STRING_ARRAY: + { + int count_value = count_token - 2; + type_string_array* new_string_array; + + new_string_array = (type_string_array*)g_malloc0( sizeof(type_string_array) ); + new_string_array->name = get_new_string( buffer_token[0] ); + new_string_array->count = count_value; + new_string_array->value = (char**)g_malloc0( sizeof(char*)*count_value );; + + //_mmcam_dbg_log( "STRING ARRAY - name[%s]", new_string_array->name ); + for( j = 0 ; j < count_value ; j++ ) + { + new_string_array->value[j] = get_new_string( buffer_token[j+1] ); + //_mmcam_dbg_log( " index[%d] - value[%s]", j, new_string_array->value[j] ); + } + + new_string_array->default_value = get_new_string( buffer_token[count_token-1] ); + //_mmcam_dbg_log( " default value[%s]", new_string_array->default_value ); + + (*info)->detail_info[i] = (void*)new_string_array; + break; + } + case CONFIGURE_VALUE_ELEMENT: + { + type_element* new_element; + + new_element = (type_element*)g_malloc0( sizeof(type_element) ); + new_element->name = get_new_string( buffer_token[0] ); + new_element->element_name = get_new_string( buffer_token[1] ); + new_element->count_int = atoi( buffer_token[2] ); + new_element->value_int = NULL; + new_element->count_string = atoi( buffer_token[3] ); + new_element->value_string = NULL; + + //_mmcam_dbg_log( "Element - name[%s],element_name[%s],count_int[%d],count_string[%d]", new_element->name, new_element->element_name, new_element->count_int, new_element->count_string ); + + /* add int values */ + if( new_element->count_int > 0 ) + { + new_element->value_int = (type_int**)g_malloc0( sizeof(type_int*)*(new_element->count_int) ); + + for( j = 0 ; j < new_element->count_int ; j++ ) + { + new_element->value_int[j] = (type_int*)g_malloc( sizeof(type_int) ); + new_element->value_int[j]->name = get_new_string( buffer_token[4+(j<<1)] ); + new_element->value_int[j]->value = atoi( buffer_token[5+(j<<1)] ); + //_mmcam_dbg_log( " Element INT[%d] - name[%s],value[%d]", j, new_element->value_int[j]->name, new_element->value_int[j]->value ); + } + } + else + { + new_element->value_int = NULL; + } + + /* add string values */ + if( new_element->count_string > 0 ) + { + new_element->value_string = (type_string**)g_malloc0( sizeof(type_string*)*(new_element->count_string) ); + + for( ; j < new_element->count_string + new_element->count_int ; j++ ) + { + new_element->value_string[j-new_element->count_int] = (type_string*)g_malloc0( sizeof(type_string) ); + new_element->value_string[j-new_element->count_int]->name = get_new_string( buffer_token[4+(j<<1)] ); + new_element->value_string[j-new_element->count_int]->value = get_new_string( buffer_token[5+(j<<1)] ); + //_mmcam_dbg_log( " Element STRING[%d] - name[%s],value[%s]", j-new_element->count_int, new_element->value_string[j-new_element->count_int]->name, new_element->value_string[j-new_element->count_int]->value ); + } + } + else + { + new_element->value_string = NULL; + } + + (*info)->detail_info[i] = (void*)new_element; + break; + } + default: + break; + } + } + + //_mmcam_dbg_log( "Done." ); + + return TRUE; +} + + +int +_mmcamcorder_conf_get_value_int( camera_conf* configure_info, int category, char* name, int* value ) +{ + int i, count; + conf_info* info; + + //_mmcam_dbg_log( "Entered... category[%d],name[%s]", category, name ); + + mmf_return_val_if_fail( configure_info, FALSE ); + mmf_return_val_if_fail( name, FALSE ); + + if( configure_info->info[category] ) + { + count = configure_info->info[category]->count; + info = configure_info->info[category]; + + for( i = 0 ; i < count ; i++ ) + { + if( info->detail_info[i] == NULL ) + { + continue; + } + + if( !strcmp( ((type_int*)(info->detail_info[i]))->name , name ) ) + { + *value = ((type_int*)(info->detail_info[i]))->value; + //_mmcam_dbg_log( "Get[%s] int[%d]", name, *value ); + return TRUE; + } + } + } + + if( _mmcamcorder_conf_get_default_value_int( configure_info->type, category, name, value ) ) + { + //_mmcam_dbg_log( "Get[%s] int[%d]", name, *value ); + return TRUE; + } + + _mmcam_dbg_warn( "Faild to get int... check it...Category[%d],Name[%s]", category, name ); + + return FALSE; +} + +int +_mmcamcorder_conf_get_value_int_range( camera_conf* configure_info, int category, char* name, type_int_range** value ) +{ + int i, count; + conf_info* info; + + //_mmcam_dbg_log( "Entered... category[%d],name[%s]", category, name ); + + mmf_return_val_if_fail( configure_info, FALSE ); + mmf_return_val_if_fail( name, FALSE ); + + if( configure_info->info[category] ) + { + count = configure_info->info[category]->count; + info = configure_info->info[category]; + + for( i = 0 ; i < count ; i++ ) + { + if( info->detail_info[i] == NULL ) + { + continue; + } + + if( !strcmp( ((type_int_range*)(info->detail_info[i]))->name , name ) ) + { + *value = (type_int_range*)(info->detail_info[i]); + /* + _mmcam_dbg_log( "Get[%s] int range - min[%d],max[%d],default[%d]", + name, (*value)->min, (*value)->max, (*value)->default_value ); + */ + return TRUE; + } + } + } + + *value = NULL; + + _mmcam_dbg_warn( "Faild to get int range... check it...Category[%d],Name[%s]", category, name ); + + return FALSE; +} + +int +_mmcamcorder_conf_get_value_int_array( camera_conf* configure_info, int category, char* name, type_int_array** value ) +{ + int i, count; + conf_info* info; + + //_mmcam_dbg_log( "Entered... category[%d],name[%s]", category, name ); + + mmf_return_val_if_fail( configure_info, FALSE ); + mmf_return_val_if_fail( name, FALSE ); + + if( configure_info->info[category] ) + { + count = configure_info->info[category]->count; + info = configure_info->info[category]; + + for( i = 0 ; i < count ; i++ ) + { + if( info->detail_info[i] == NULL ) + { + continue; + } + + if( !strcmp( ((type_int_array*)(info->detail_info[i]))->name , name ) ) + { + *value = (type_int_array*)(info->detail_info[i]); + /* + _mmcam_dbg_log( "Get[%s] int array - [%x],count[%d],default[%d]", + name, (*value)->value, (*value)->count, (*value)->default_value ); + */ + return TRUE; + } + } + } + + *value = NULL; + + _mmcam_dbg_warn( "Faild to get int array... check it...Category[%d],Name[%s]", category, name ); + + return FALSE; +} + +int +_mmcamcorder_conf_get_value_int_pair_array( camera_conf* configure_info, int category, char* name, type_int_pair_array** value ) +{ + int i, count; + conf_info* info; + + //_mmcam_dbg_log( "Entered... category[%d],name[%s]", category, name ); + + mmf_return_val_if_fail( configure_info, FALSE ); + mmf_return_val_if_fail( name, FALSE ); + + if( configure_info->info[category] ) + { + count = configure_info->info[category]->count; + info = configure_info->info[category]; + + for( i = 0 ; i < count ; i++ ) + { + if( info->detail_info[i] == NULL ) + { + continue; + } + + if( !strcmp( ((type_int_pair_array*)(info->detail_info[i]))->name , name ) ) + { + *value = (type_int_pair_array*)(info->detail_info[i]); + /* + _mmcam_dbg_log( "Get[%s] int pair array - [%x][%x],count[%d],default[%d][%d]", + name, (*value)->value[0], (*value)->value[1], (*value)->count, + (*value)->default_value[0], (*value)->default_value[1] ); + */ + return TRUE; + } + } + } + + *value = NULL; + + _mmcam_dbg_warn( "Faild to get int pair array... check it...Category[%d],Name[%s]", category, name ); + + return FALSE; +} + +int +_mmcamcorder_conf_get_value_string( camera_conf* configure_info, int category, char* name, char** value ) +{ + int i, count; + conf_info* info; + + //_mmcam_dbg_log( "Entered... category[%d],name[%s]", category, name ); + + mmf_return_val_if_fail( configure_info, FALSE ); + mmf_return_val_if_fail( name, FALSE ); + + if( configure_info->info[category] ) + { + count = configure_info->info[category]->count; + info = configure_info->info[category]; + + for( i = 0 ; i < count ; i++ ) + { + if( info->detail_info[i] == NULL ) + { + continue; + } + + if( !strcmp( ((type_string*)(info->detail_info[i]))->name , name ) ) + { + *value = ((type_string*)(info->detail_info[i]))->value; + //_mmcam_dbg_log( "Get[%s] string[%s]", name, *value ); + return TRUE; + } + } + } + + if( _mmcamcorder_conf_get_default_value_string( configure_info->type, category, name, value ) ) + { + //_mmcam_dbg_log( "Get[%s]string[%s]", name, *value ); + return TRUE; + } + + _mmcam_dbg_warn( "Faild to get string... check it...Category[%d],Name[%s]", category, name ); + + return FALSE; +} + +int +_mmcamcorder_conf_get_value_string_array ( camera_conf* configure_info, int category, char* name, type_string_array** value ) +{ + int i, count; + conf_info* info; + + //_mmcam_dbg_log( "Entered... category[%d],name[%s]", category, name ); + + mmf_return_val_if_fail( configure_info, FALSE ); + mmf_return_val_if_fail( name, FALSE ); + + if( configure_info->info[category] ) + { + count = configure_info->info[category]->count; + info = configure_info->info[category]; + + for( i = 0 ; i < count ; i++ ) + { + if( info->detail_info[i] == NULL ) + { + continue; + } + + if( !strcmp( ((type_string_array*)(info->detail_info[i]))->name , name ) ) + { + *value = (type_string_array*)(info->detail_info[i]); + /* + _mmcam_dbg_log( "Get[%s] string array - [%x],count[%d],default[%s]", + name, (*value)->value, (*value)->count, (*value)->default_value ); + */ + return TRUE; + } + } + } + + *value = NULL; + + _mmcam_dbg_warn( "Faild to get string array... check it...Category[%d],Name[%s]", category, name ); + + return FALSE; +} + +int +_mmcamcorder_conf_get_element( camera_conf* configure_info, int category, char* name, type_element** element ) +{ + int i, count; + conf_info* info; + + //_mmcam_dbg_log( "Entered... category[%d],name[%s]", category, name ); + + mmf_return_val_if_fail( configure_info, FALSE ); + mmf_return_val_if_fail( name, FALSE ); + + if( configure_info->info[category] ) + { + count = configure_info->info[category]->count; + info = configure_info->info[category]; + + for( i = 0 ; i < count ; i++ ) + { + if( info->detail_info[i] == NULL ) + { + continue; + } + + if( !strcmp( ((type_element*)(info->detail_info[i]))->name , name ) ) + { + *element = (type_element*)(info->detail_info[i]); + //_mmcam_dbg_log( "Get[%s] element[%x]", name, *element ); + return TRUE; + } + } + } + + if( _mmcamcorder_conf_get_default_element( configure_info->type, category, name, element ) ) + { + //_mmcam_dbg_log( "Get[%s] element[%x]", name, *element ); + return TRUE; + } + + _mmcam_dbg_warn( "Faild to get element name... check it...Category[%d],Name[%s]", category, name ); + + return FALSE; +} + +int +_mmcamcorder_conf_get_value_element_name( type_element* element, char** value ) +{ + //_mmcam_dbg_log( "Entered..." ); + + mmf_return_val_if_fail( element, FALSE ); + + *value = element->element_name; + + //_mmcam_dbg_log( "Get element name : [%s]", *value ); + + return TRUE; +} + +int +_mmcamcorder_conf_get_value_element_int( type_element* element, char* name, int* value ) +{ + int i; + + //_mmcam_dbg_log( "Entered..." ); + + mmf_return_val_if_fail( element, FALSE ); + mmf_return_val_if_fail( name, FALSE ); + + for( i = 0 ; i < element->count_int ; i++ ) + { + if( !strcmp( element->value_int[i]->name , name ) ) + { + *value = element->value_int[i]->value; + //_mmcam_dbg_log( "Get[%s] element int[%d]", name, *value ); + return TRUE; + } + } + + _mmcam_dbg_warn( "Faild to get int in element... ElementName[%p],Name[%s],Count[%d]", + element->name, name, element->count_int ); + + return FALSE; +} + +int +_mmcamcorder_conf_get_value_element_string( type_element* element, char* name, char** value ) +{ + int i; + + //_mmcam_dbg_log( "Entered..." ); + + mmf_return_val_if_fail( element, FALSE ); + mmf_return_val_if_fail( name, FALSE ); + + for( i = 0 ; i < element->count_string ; i++ ) + { + if( !strcmp( element->value_string[i]->name , name ) ) + { + *value = element->value_string[i]->value; + //_mmcam_dbg_log( "Get[%s] element string[%s]", name, *value ); + return TRUE; + } + } + + _mmcam_dbg_warn( "Faild to get int in element... ElementName[%p],Name[%s],Count[%d]", + element->name, name, element->count_string ); + + return FALSE; +} + +int +_mmcamcorder_conf_set_value_element_property( GstElement* gst, type_element* element ) +{ + int i; + + //_mmcam_dbg_log( "Entered..." ); + + mmf_return_val_if_fail( gst, FALSE ); + mmf_return_val_if_fail( element, FALSE ); + + if( element->count_int == 0 ) + { + _mmcam_dbg_log( "There is no integer property to set in INI file[%s].", element->name ); + } + else + { + if( element->value_int == NULL ) + { + _mmcam_dbg_warn( "count_int[%d] is NOT zero, but value_int is NULL", element->count_int ); + return FALSE; + } + + for( i = 0 ; i < element->count_int ; i++ ) + { + MMCAMCORDER_G_OBJECT_SET( gst, element->value_int[i]->name, element->value_int[i]->value ); + + _mmcam_dbg_log( "Element[%s] Set[%s] -> integer[%d]", + element->element_name, + element->value_int[i]->name, + element->value_int[i]->value ); + } + } + + if( element->count_string == 0 ) + { + _mmcam_dbg_log( "There is no string property to set in INI file[%s].", element->name ); + } + else + { + if( element->value_string == NULL ) + { + _mmcam_dbg_warn( "count_string[%d] is NOT zero, but value_string is NULL", element->count_string ); + return FALSE; + } + + for( i = 0 ; i < element->count_string ; i++ ) + { + MMCAMCORDER_G_OBJECT_SET( gst, element->value_string[i]->name, element->value_string[i]->value ); + + _mmcam_dbg_log( "Element[%s] Set[%s] -> string[%s]", + element->element_name, + element->value_string[i]->name, + element->value_string[i]->value ); + } + } + + //_mmcam_dbg_log( "Done." ); + + return TRUE; +} + +int +_mmcamcorder_conf_get_default_value_int( int type, int category, char* name, int* value ) +{ + int i = 0; + int count_value = 0; + + //_mmcam_dbg_log( "Entered..." ); + + mmf_return_val_if_fail( name, FALSE ); + + if( !_mmcamcorder_conf_get_category_size( type, category, &count_value ) ) + { + _mmcam_dbg_warn( "No matched category... check it... categoty[%d]", category ); + return FALSE; + } + + if( type == CONFIGURE_TYPE_MAIN ) + { + for( i = 0 ; i < count_value ; i++ ) + { + if( !strcmp( conf_main_info_table[category][i].name, name ) ) + { + *value = conf_main_info_table[category][i].value_int; + return TRUE; + } + } + } + else + { + for( i = 0 ; i < count_value ; i++ ) + { + if( !strcmp( conf_ctrl_info_table[category][i].name, name ) ) + { + *value = conf_ctrl_info_table[category][i].value_int; + return TRUE; + } + } + } + + _mmcam_dbg_warn( "Failed to get default int... check it... Type[%d],Category[%d],Name[%s]", type, category, name ); + + return FALSE; +} + +int +_mmcamcorder_conf_get_default_value_string( int type, int category, char* name, char** value ) +{ + int i = 0; + int count_value = 0; + + //_mmcam_dbg_log( "Entered..." ); + + mmf_return_val_if_fail( name, FALSE ); + + if( !_mmcamcorder_conf_get_category_size( type, category, &count_value ) ) + { + _mmcam_dbg_warn( "No matched category... check it... categoty[%d]", category ); + return FALSE; + } + + if( type == CONFIGURE_TYPE_MAIN ) + { + for( i = 0 ; i < count_value ; i++ ) + { + if( !strcmp( conf_main_info_table[category][i].name, name ) ) + { + *value = conf_main_info_table[category][i].value_string; + _mmcam_dbg_log( "Get[%s] default string[%s]", name, *value ); + return TRUE; + } + } + } + else + { + for( i = 0 ; i < count_value ; i++ ) + { + if( !strcmp( conf_ctrl_info_table[category][i].name, name ) ) + { + *value = conf_ctrl_info_table[category][i].value_string; + _mmcam_dbg_log( "Get[%s] default string[%s]", name, *value ); + return TRUE; + } + } + } + + _mmcam_dbg_warn( "Failed to get default string... check it... Type[%d],Category[%d],Name[%s]", type, category, name ); + + return FALSE; +} + +int +_mmcamcorder_conf_get_default_element( int type, int category, char* name, type_element** element ) +{ + int i = 0; + int count_value = 0; + + //_mmcam_dbg_log( "Entered..." ); + + mmf_return_val_if_fail( name, FALSE ); + + if( !_mmcamcorder_conf_get_category_size( type, category, &count_value ) ) + { + _mmcam_dbg_warn( "No matched category... check it... categoty[%d]", category ); + return FALSE; + } + + if( type == CONFIGURE_TYPE_MAIN ) + { + for( i = 0 ; i < count_value ; i++ ) + { + if( !strcmp( conf_main_info_table[category][i].name, name ) ) + { + *element = conf_main_info_table[category][i].value_element; + _mmcam_dbg_log( "Get[%s] element[%p]", name, *element ); + return TRUE; + } + } + } + else + { + for( i = 0 ; i < count_value ; i++ ) + { + if( !strcmp( conf_ctrl_info_table[category][i].name, name ) ) + { + *element = conf_ctrl_info_table[category][i].value_element; + _mmcam_dbg_log( "Get[%s] element[%p]", name, *element ); + return TRUE; + } + } + } + + _mmcam_dbg_warn( "Failed to get default element... check it... Type[%d],Category[%d],Name[%s]", type, category, name ); + + return FALSE; +} + +int +_mmcamcorder_conf_get_category_size( int type, int category, int* size ) +{ +// mmf_return_val_if_fail( conf_main_category_size, FALSE ); +// mmf_return_val_if_fail( conf_ctrl_category_size, FALSE ); + + if( type == CONFIGURE_TYPE_MAIN ) + { + mmf_return_val_if_fail( category < CONFIGURE_CATEGORY_MAIN_NUM, FALSE ); + + *size = (int)conf_main_category_size[category]; + } + else + { + mmf_return_val_if_fail( category < CONFIGURE_CATEGORY_CTRL_NUM, FALSE ); + + *size = (int)conf_ctrl_category_size[category]; + } + + return TRUE; +} + +void +_mmcamcorder_conf_print_info( camera_conf** configure_info ) +{ + int i, j, k, type, category_type; + + type_int *temp_int; + type_int_range *temp_int_range; + type_int_array *temp_int_array; + type_int_pair_array *temp_int_pair_array; + type_string *temp_string; + type_element *temp_element; + + g_print( "[ConfigureInfoPrint] : Entered.\n" ); + + mmf_return_if_fail( *configure_info ); + + if( (*configure_info)->type == CONFIGURE_TYPE_MAIN ) + { + category_type = CONFIGURE_CATEGORY_MAIN_NUM; + } + else + { + category_type = CONFIGURE_CATEGORY_CTRL_NUM; + } + + for( i = 0 ; i < category_type ; i++ ) + { + if( (*configure_info)->info[i] ) + { + g_print( "[ConfigureInfo] : Category [%d]\n", i ); + for( j = 0 ; j < (*configure_info)->info[i]->count ; j++ ) + { + if( _mmcamcorder_conf_get_value_type( (*configure_info)->type, i, ((type_int*)((*configure_info)->info[i]->detail_info[j]))->name, &type ) ) + { + switch( type ) + { + case CONFIGURE_VALUE_INT: + temp_int = (type_int*)((*configure_info)->info[i]->detail_info[j]); + g_print( "[ConfigureInfo] : INT - Name[%s],Value [%d]\n", temp_int->name, temp_int->value ); + break; + case CONFIGURE_VALUE_INT_RANGE: + temp_int_range = (type_int_range*)((*configure_info)->info[i]->detail_info[j]); + g_print( "[ConfigureInfo] : INT_RANGE - Name[%s],Value [%d]~[%d], default [%d]\n", + temp_int_range->name, temp_int_range->min, temp_int_range->max, temp_int_range->default_value ); + break; + case CONFIGURE_VALUE_INT_ARRAY: + temp_int_array = (type_int_array*)((*configure_info)->info[i]->detail_info[j]); + g_print( "[ConfigureInfo] : INT_ARRAY - Name[%s], default [%d]\n - ", + temp_int_array->name, temp_int_array->default_value ); + for( k = 0 ; k < temp_int_array->count ; k++ ) + { + g_print( "[%d] ", temp_int_array->value[k] ); + } + g_print( "\n" ); + break; + case CONFIGURE_VALUE_INT_PAIR_ARRAY: + temp_int_pair_array = (type_int_pair_array*)((*configure_info)->info[i]->detail_info[j]); + g_print( "[ConfigureInfo] : INT_PAIR_ARRAY - Name[%s], default [%d][%d]\n - ", + temp_int_pair_array->name, temp_int_pair_array->default_value[0], temp_int_pair_array->default_value[0] ); + for( k = 0 ; k < temp_int_pair_array->count ; k++ ) + { + g_print( "[%d,%d] ", temp_int_pair_array->value[0][k], temp_int_pair_array->value[1][k] ); + } + g_print( "\n" ); + break; + case CONFIGURE_VALUE_STRING: + temp_string = (type_string*)((*configure_info)->info[i]->detail_info[j]); + g_print( "[ConfigureInfo] : STRING - Name[%s],Value[%s]\n", temp_string->name, temp_string->value ); + break; + case CONFIGURE_VALUE_ELEMENT: + temp_element = (type_element*)((*configure_info)->info[i]->detail_info[j]); + g_print( "[ConfigureInfo] : Element - Name[%s],Element_Name[%s]\n", temp_element->name, temp_element->element_name ); + for( k = 0 ; k < temp_element->count_int ; k++ ) + { + g_print( " - INT[%d] Name[%s],Value[%d]\n", k, temp_element->value_int[k]->name, temp_element->value_int[k]->value ); + } + for( k = 0 ; k < temp_element->count_string ; k++ ) + { + g_print( " - STRING[%d] Name[%s],Value[%s]\n", k, temp_element->value_string[k]->name, temp_element->value_string[k]->value ); + } + break; + default: + g_print( "[ConfigureInfo] : Not matched value type... So can not print data... check it... Name[%s],type[%d]\n", ((type_int*)((*configure_info)->info[i]->detail_info[j]))->name, type ); + break; + } + } + else + { + g_print( "[ConfigureInfo] : Failed to get value type." ); + } + } + } + } + + g_print( "[ConfigureInfoPrint] : Done.\n" ); +} + + +static type_element * +__mmcamcorder_get_audio_codec_element(MMHandleType handle) +{ + type_element *telement = NULL; + char * codec_type_str = NULL; + int codec_type = MM_AUDIO_CODEC_INVALID; + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(hcamcorder, NULL); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + + mmf_return_val_if_fail(sc, NULL); + + _mmcam_dbg_log(""); + + /* Check element availability */ + mm_camcorder_get_attributes(handle, NULL, MMCAM_AUDIO_ENCODER, &codec_type, NULL); + + switch( codec_type ) + { + case MM_AUDIO_CODEC_AMR: + codec_type_str = "AMR"; + break; + case MM_AUDIO_CODEC_G723_1: + codec_type_str = "G723_1"; + break; + case MM_AUDIO_CODEC_MP3: + codec_type_str = "MP3"; + break; + case MM_AUDIO_CODEC_AAC: + codec_type_str = "AAC"; + break; + case MM_AUDIO_CODEC_MMF: + codec_type_str = "MMF"; + break; + case MM_AUDIO_CODEC_ADPCM: + codec_type_str = "ADPCM"; + break; + case MM_AUDIO_CODEC_WAVE: + codec_type_str = "WAVE"; + break; + case MM_AUDIO_CODEC_MIDI: + codec_type_str = "MIDI"; + break; + case MM_AUDIO_CODEC_IMELODY: + codec_type_str = "IMELODY"; + break; + case MM_AUDIO_CODEC_VORBIS: + codec_type_str = "VORBIS"; + break; + default: + _mmcam_dbg_err( "Not supported audio codec[%d]", codec_type ); + return NULL; + } + + _mmcamcorder_conf_get_element( hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_AUDIO_ENCODER, + codec_type_str, + &telement ); + + return telement; +} + + +static type_element * +__mmcamcorder_get_video_codec_element(MMHandleType handle) +{ + type_element *telement = NULL; + char * codec_type_str = NULL; + int codec_type = MM_VIDEO_CODEC_INVALID; + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(hcamcorder, NULL); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + + mmf_return_val_if_fail(sc, NULL); + + _mmcam_dbg_log(""); + + /* Check element availability */ + mm_camcorder_get_attributes(handle, NULL, MMCAM_VIDEO_ENCODER, &codec_type, NULL); + + switch( codec_type ) + { + case MM_VIDEO_CODEC_H263: + codec_type_str = "H263"; + break; + case MM_VIDEO_CODEC_H264: + codec_type_str = "H264"; + break; + case MM_VIDEO_CODEC_H26L: + codec_type_str = "H26L"; + break; + case MM_VIDEO_CODEC_MPEG4: + codec_type_str = "MPEG4"; + break; + case MM_VIDEO_CODEC_MPEG1: + codec_type_str = "MPEG1"; + break; + case MM_VIDEO_CODEC_THEORA: // OGG + codec_type_str = "THEORA"; + break; + default: + _mmcam_dbg_err( "Not supported video codec[%d]", codec_type ); + return NULL; + } + + _mmcamcorder_conf_get_element( hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_ENCODER, + codec_type_str, + &telement ); + + return telement; +} + + +static type_element * +__mmcamcorder_get_image_codec_element(MMHandleType handle) +{ + type_element *telement = NULL; + char * codec_type_str = NULL; + int codec_type = MM_IMAGE_CODEC_INVALID; + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(hcamcorder, NULL); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + + mmf_return_val_if_fail(sc, NULL); + + _mmcam_dbg_log(""); + + /* Check element availability */ + mm_camcorder_get_attributes(handle, NULL, MMCAM_IMAGE_ENCODER, &codec_type, NULL); + + switch( codec_type ) + { + case MM_IMAGE_CODEC_JPEG: + codec_type_str = "JPEG"; + break; + case MM_IMAGE_CODEC_SRW: + codec_type_str = "SRW"; + break; + case MM_IMAGE_CODEC_JPEG_SRW: + codec_type_str = "JPEG_SRW"; + break; + case MM_IMAGE_CODEC_PNG: + codec_type_str = "PNG"; + break; + case MM_IMAGE_CODEC_BMP: + codec_type_str = "BMP"; + break; + case MM_IMAGE_CODEC_WBMP: + codec_type_str = "WBMP"; + break; + case MM_IMAGE_CODEC_TIFF: + codec_type_str = "TIFF"; + break; + case MM_IMAGE_CODEC_PCX: + codec_type_str = "PCX"; + break; + case MM_IMAGE_CODEC_GIF: + codec_type_str = "GIF"; + break; + case MM_IMAGE_CODEC_ICO: + codec_type_str = "ICO"; + break; + case MM_IMAGE_CODEC_RAS: + codec_type_str = "RAS"; + break; + case MM_IMAGE_CODEC_TGA: + codec_type_str = "TGA"; + break; + case MM_IMAGE_CODEC_XBM: + codec_type_str = "XBM"; + break; + case MM_IMAGE_CODEC_XPM: + codec_type_str = "XPM"; + break; + default: + _mmcam_dbg_err( "Not supported image codec[%d]", codec_type ); + return NULL; + } + + _mmcamcorder_conf_get_element( hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_IMAGE_ENCODER, + codec_type_str, + &telement ); + + return telement; +} + + +static type_element * +__mmcamcorder_get_file_format_element(MMHandleType handle) +{ + type_element *telement = NULL; + char * mux_type_str = NULL; + int file_type = MM_FILE_FORMAT_INVALID; + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(hcamcorder, NULL); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + + mmf_return_val_if_fail(sc, NULL); + + _mmcam_dbg_log(""); + + /* Check element availability */ + mm_camcorder_get_attributes(handle, NULL, MMCAM_FILE_FORMAT, &file_type, NULL); + + switch( file_type ) + { + case MM_FILE_FORMAT_3GP: + mux_type_str = "3GP"; + break; + case MM_FILE_FORMAT_AMR: + mux_type_str = "AMR"; + break; + case MM_FILE_FORMAT_MP4: + mux_type_str = "MP4"; + break; + case MM_FILE_FORMAT_AAC: + mux_type_str = "AAC"; + break; + case MM_FILE_FORMAT_MP3: + mux_type_str = "MP3"; + break; + case MM_FILE_FORMAT_OGG: + mux_type_str = "OGG"; + break; + case MM_FILE_FORMAT_WAV: + mux_type_str = "WAV"; + break; + case MM_FILE_FORMAT_AVI: + mux_type_str = "AVI"; + break; + case MM_FILE_FORMAT_WMA: + mux_type_str = "WMA"; + break; + case MM_FILE_FORMAT_WMV: + mux_type_str = "WMV"; + break; + case MM_FILE_FORMAT_MID: + mux_type_str = "MID"; + break; + case MM_FILE_FORMAT_MMF: + mux_type_str = "MMF"; + break; + case MM_FILE_FORMAT_MATROSKA: + mux_type_str = "MATROSKA"; + break; + default: + _mmcam_dbg_err( "Not supported file format[%d]", file_type ); + return NULL; + } + + _mmcamcorder_conf_get_element( hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_MUX, + mux_type_str, + &telement ); + + return telement; +} + + +type_element * +_mmcamcorder_get_type_element(MMHandleType handle, int type) +{ + type_element *telement = NULL; + + _mmcam_dbg_log("type:%d", type); + + switch(type) + { + case MM_CAM_AUDIO_ENCODER: + telement = __mmcamcorder_get_audio_codec_element(handle); + break; + case MM_CAM_VIDEO_ENCODER: + telement = __mmcamcorder_get_video_codec_element(handle); + break; + case MM_CAM_IMAGE_ENCODER: + telement = __mmcamcorder_get_image_codec_element(handle); + break; + case MM_CAM_FILE_FORMAT: + telement = __mmcamcorder_get_file_format_element(handle); + break; + default : + _mmcam_dbg_log("Can't get element type form this profile.(%d)", type); + } + + return telement; +} + + +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; + } + } + + _mmcam_dbg_err( "Not supported audio codec[%s]", name); + return -1; + +} + + + +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; + } + } + + _mmcam_dbg_err( "Not supported Video codec[%s]", name); + return -1; + +} + + + +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; + } + } + + _mmcam_dbg_err( "Not supported Image codec[%s]", name); + return -1; + +} + + +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; + } + } + + _mmcam_dbg_err( "Not supported Mux[%s]", name); + return -1; + +} + + +int +_mmcamcorder_get_format(MMHandleType handle, int conf_category, char * name) +{ + int fmt = -1; + + mmf_return_val_if_fail(name, -1); + + switch(conf_category) + { + case CONFIGURE_CATEGORY_MAIN_AUDIO_ENCODER: + fmt = _mmcamcorder_get_audio_codec_format(handle, name); + break; + case CONFIGURE_CATEGORY_MAIN_VIDEO_ENCODER: + fmt = _mmcamcorder_get_video_codec_format(handle, name); + break; + case CONFIGURE_CATEGORY_MAIN_IMAGE_ENCODER: + fmt = _mmcamcorder_get_image_codec_format(handle, name); + break; + case CONFIGURE_CATEGORY_MAIN_MUX: + fmt = _mmcamcorder_get_mux_format(handle, name); + break; + default : + _mmcam_dbg_log("Can't get format from this category.(%d)", conf_category); + } + + return fmt; +} + +int +_mmcamcorder_get_available_format(MMHandleType handle, int conf_category, int ** format) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + camera_conf* configure_info = NULL; + int *arr = NULL; + int total_count = 0; + + mmf_return_val_if_fail(hcamcorder, 0); + + _mmcam_dbg_log("conf_category:%d", conf_category); + + 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]; + int i = 0; + int fmt = 0; + char* name = NULL; + + _mmcam_dbg_log("count[%d], info[%p]", count, 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 ) + { + continue; + } + + name = ((type_element*)(info->detail_info[i]))->name; + + if ((fmt = _mmcamcorder_get_format(handle, conf_category, name)) >= 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 new file mode 100644 index 0000000..a1a2f2e --- /dev/null +++ b/src/mm_camcorder_exifinfo.c @@ -0,0 +1,642 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "mm_camcorder_exifinfo.h" +#include "mm_camcorder_exifdef.h" + +#include <libexif/exif-loader.h> +#include <libexif/exif-utils.h> +#include <libexif/exif-data.h> + +#include <stdlib.h> +#include <stdio.h> +#include <time.h> +#include <mm_debug.h> +#include <mm_error.h> +#include <glib.h> + +#define MM_EXIFINFO_USE_BINARY_EXIFDATA 1 +#define JPEG_MAX_SIZE 20000000 +#define JPEG_THUMBNAIL_MAX_SIZE (128*1024) +#if MM_EXIFINFO_USE_BINARY_EXIFDATA +/** + * Exif Binary Data. + */ +#include <string.h> +#define _EXIF_BIN_SIZE_ ((unsigned int)174) +unsigned char g_exif_bin [_EXIF_BIN_SIZE_] = { + 0x45 , 0x78 , 0x69 , 0x66 , 0x00 , 0x00 , 0x49 , 0x49 , 0x2a , 0x00 , 0x08 , 0x00 , 0x00 , 0x00 , 0x05 , 0x00 + , 0x1a , 0x01 , 0x05 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x4a , 0x00 , 0x00 , 0x00 , 0x1b , 0x01 , 0x05 , 0x00 + , 0x01 , 0x00 , 0x00 , 0x00 , 0x52 , 0x00 , 0x00 , 0x00 , 0x28 , 0x01 , 0x03 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 + , 0x02 , 0x00 , 0x00 , 0x00 , 0x13 , 0x02 , 0x03 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 + , 0x69 , 0x87 , 0x04 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x5a , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 + , 0x48 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x48 , 0x00 , 0x00 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 + , 0x06 , 0x00 , 0x00 , 0x90 , 0x07 , 0x00 , 0x04 , 0x00 , 0x00 , 0x00 , 0x30 , 0x32 , 0x31 , 0x30 , 0x01 , 0x91 + , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0xa0 , 0x07 , 0x00 , 0x04 , 0x00 + , 0x00 , 0x00 , 0x30 , 0x31 , 0x30 , 0x30 , 0x01 , 0xa0 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 + , 0x00 , 0x00 , 0x02 , 0xa0 , 0x04 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x03 , 0xa0 + , 0x04 , 0x00 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 +}; +#endif + +/** + * Structure for exif entry. + */ +typedef struct _mm_exif_entry_t +{ + ExifTag tag; /**< exif tag*/ + ExifFormat format; /**< exif format*/ + unsigned long components; /**< number of components*/ + unsigned char *data; /**< data*/ + unsigned int size; /**< size of data*/ +} mm_exif_entry_type; + + +/** + * local functions. + */ +static void +_exif_set_uint16 (int is_motorola, void * out, unsigned short in) +{ + if (is_motorola) { + ((unsigned char *)out)[0] = in & 0x00ff; + ((unsigned char *)out)[1] = in >> 8; + } else { + ((unsigned char *)out)[0] = in >> 8; + ((unsigned char *)out)[1] = in & 0x00ff; + } +} + + +static unsigned long +_exif_get_jpeg_marker_offset (void *jpeg, int jpeg_size, unsigned short marker) +{ + unsigned char *p = NULL; + unsigned char *src = jpeg; + int src_sz = jpeg_size; + unsigned char m[2]; + unsigned long ret; + int i; + + // mmf_debug (MMF_DEBUG_LOG, "%s()\n", __func__); + + m[0] = marker >> 8; + m[1] = marker & 0x00FF; + + mmf_debug (MMF_DEBUG_LOG,"[%05d][%s] marker: 0x%02X 0x%02X\n\n", __LINE__, __func__,m[0], m[1]); + + if (*src == 0xff && *(src + 1) == 0xd8) + { + p = src + 2; /* SOI(start of image) */ + } + else + { + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] invalid JPEG file.\n", __LINE__, __func__); + return 0UL; + } + + for (i = 0; i < src_sz - (1 + 2); i++, p++) + { + if (*p == 0xff) + { + /*marker is 0xFFxx*/ + if (*(p + 1) == m[1]) + { + ret = p - src; + mmf_debug (MMF_DEBUG_LOG,"[%05d][%s]marker offset: %lu %p %p.\n", __LINE__, __func__,ret, (p+1), src); + return ret; + } + } + } + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s]Marker not found.\n", __LINE__, __func__); + return 0UL; +} + + +ExifData* +mm_exif_get_exif_data_from_data (mm_exif_info_t *info) +{ + ExifData *ed = NULL; + + //mmf_debug (MMF_DEBUG_LOG, "%s()\n", __func__); + + ed = exif_data_new_from_data(info->data, info->size); + if( ed == NULL ) + { + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s]Null exif data. (ed:%p)\n", __LINE__, __func__, ed); + } + + return ed; +} + + +ExifData* +mm_exif_get_exif_from_info (mm_exif_info_t *info) +{ + ExifData *ed = NULL; + ExifLoader *loader = NULL; + + unsigned char size[2]; + unsigned int i; + + //mmf_debug (MMF_DEBUG_LOG, "%s()\n", __func__); + + /*get ExifData from info*/ + loader = exif_loader_new (); + + size[0] = (unsigned char) (info->size); + size[1] = (unsigned char) (info->size >> 8); + exif_loader_write (loader, size, 2); + + for (i = 0; i < info->size && exif_loader_write (loader, info->data + i, 1); i++); + + ed = exif_loader_get_data (loader); + exif_loader_unref (loader); + return ed; +} + + +int +mm_exif_set_exif_to_info (mm_exif_info_t *info, ExifData *exif) +{ + unsigned char *eb = NULL; + unsigned int ebs; + + if (!exif) + { + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s]exif Null\n", __LINE__, __func__); + return MM_ERROR_CAMCORDER_NOT_INITIALIZED; + } + + mmf_debug (MMF_DEBUG_LOG,"[%05d][%s]exif(ifd :%p)\n", __LINE__, __func__, exif->ifd); + + if(info->data) + { + free (info->data); + info->data = NULL; + info->size = 0; + } + + exif_data_save_data (exif, &eb, &ebs); + if(eb==NULL) + { + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s]MM_ERROR_CAMCORDER_LOW_MEMORY\n", __LINE__, __func__); + return MM_ERROR_CAMCORDER_LOW_MEMORY; + } + info->data = eb; + info->size = ebs; + return MM_ERROR_NONE; +} + + +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; + + 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)); + /*create new tag*/ + 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; + + 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); + } + e->size = exif_format_get_size(format)*e->components; + memcpy(e->data,data,e->size); + exif_content_add_entry (ed->ifd[ifd], e); + exif_entry_unref(e); + + return MM_ERROR_NONE; +} + + + + +/** + * global functions. + */ + + +int +mm_exif_create_exif_info (mm_exif_info_t **info) +{ + mm_exif_info_t *x = NULL; +#if (MM_EXIFINFO_USE_BINARY_EXIFDATA == 0) + 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__); + 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__); + free(x); + return MM_ERROR_CAMCORDER_LOW_MEMORY; + } + 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__); + 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__); + free(x->data); + free(x); + exif_data_unref (ed); + return MM_ERROR_CAMCORDER_INTERNAL; + } + 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); + + return MM_ERROR_NONE; +} + +void +mm_exif_destory_exif_info (mm_exif_info_t *info) +{ + //mmf_debug (MMF_DEBUG_LOG, "%s()\n", __func__); + +#if MM_EXIFINFO_USE_BINARY_EXIFDATA + if (info) { + if (info->data) + free (info->data); + free (info); + } +#else + if (info) { + if (info->data) + exif_mem_free (info->data); + free (info); + } +#endif +} + + +int +mm_exif_add_thumbnail_info (mm_exif_info_t *info, void *thumbnail, int width, int height, int len) +{ + ExifData *ed = NULL; + static ExifLong elong[10]; + + unsigned char *p_compressed = NULL; + int ret = MM_ERROR_NONE; + int cntl = 0; + + mmf_debug (MMF_DEBUG_LOG,"[%05d][%s] Thumbnail size:%d, width:%d, height:%d\n", __LINE__, __func__, len, width, height); + + if( len > JPEG_THUMBNAIL_MAX_SIZE ) + { + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] Thumbnail size[%d] over!!! Skip inserting thumbnail...\n", __LINE__, __func__, len); + return MM_ERROR_NONE; + } + + /* get ExifData from info*/ + ed = mm_exif_get_exif_from_info(info); + ed->data=thumbnail; + ed->size = len; + + /* set thumbnail data */ + p_compressed = malloc(sizeof(ExifShort)); + if (p_compressed != NULL) { + exif_set_short(p_compressed, exif_data_get_byte_order(ed), 6); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_1, EXIF_TAG_COMPRESSION, EXIF_FORMAT_SHORT, 1, p_compressed); + if (ret != MM_ERROR_NONE) { + goto exit; + } + } else { + ret = MM_ERROR_CAMCORDER_LOW_MEMORY; + goto exit; + } + + /* set thumbnail size */ + exif_set_long ((unsigned char *)&elong[cntl], exif_data_get_byte_order(ed), width); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_1, EXIF_TAG_IMAGE_WIDTH, EXIF_FORMAT_LONG, 1, (unsigned char*)&elong[cntl++]); + if (ret != MM_ERROR_NONE) { + goto exit; + } + exif_set_long ((unsigned char *)&elong[cntl], exif_data_get_byte_order(ed), height); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_1, EXIF_TAG_IMAGE_LENGTH, EXIF_FORMAT_LONG, 1, (unsigned char*)&elong[cntl++]); + if (ret != MM_ERROR_NONE) { + goto exit; + } + + ret = mm_exif_set_exif_to_info (info, ed); + if (ret != MM_ERROR_NONE) { + goto exit; + } + + ed->data = NULL; + ed->size = 0; + exif_data_unref (ed); + +exit : + if(p_compressed != NULL) + free(p_compressed); + return ret; +} + + +int mm_exif_mnote_create (ExifData *exif) +{ + ExifData* ed = exif; + ExifDataOption o = 0; + if(!ed){ + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] invalid argument exif=%p \n", __LINE__, __func__,ed); + return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + } + + if(!exif_data_mnote_data_new(ed, MAKER_SAMSUNG, o )){ + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] exif_mnote_data_samsung_new() failed. \n", __LINE__, __func__); + return MM_ERROR_CAMCORDER_MNOTE_CREATION; + } + + return MM_ERROR_NONE; +} + + +int mm_exif_mnote_set_add_entry (ExifData *exif, MnoteSamsungTag tag, int index, int subindex1, int subindex2) +{ + ExifData *ed = exif; + ExifMnoteData *md; + + ExifShort product_id = 32768; //should be modified + char serialNum[] = "SerialNum123"; //should be modified + + if(!ed){ + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] invalid argument exif=%p \n", __LINE__, __func__,ed); + return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + } + + md = exif_data_get_mnote_data (ed); + if(!md){ + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] exif_data_get_mnote_data() failed. \n", __LINE__, __func__); + return MM_ERROR_CAMCORDER_MNOTE_CREATION; + } + + if(!exif_data_mnote_set_mem_for_adding_entry(md, MAKER_SAMSUNG)){ + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] exif_data_mnote_set_mem_for_adding_entry() failed. \n", __LINE__, __func__); + return MM_ERROR_CAMCORDER_MNOTE_MALLOC; + } + + exif_mnote_data_set_byte_order(md, (ExifByteOrder) exif_data_get_data_order(ed)); + + switch(tag){ + case MNOTE_SAMSUNG_TAG_MNOTE_VERSION: + if(!exif_data_mnote_set_add_entry(md, MAKER_SAMSUNG, tag, EXIF_FORMAT_UNDEFINED, 4, index)){ + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] exif_data_mnote_set_add_entry() failed. \n", __LINE__, __func__); + return MM_ERROR_CAMCORDER_MNOTE_ADD_ENTRY; + } + break; + case MNOTE_SAMSUNG_TAG_DEVICE_ID: + if(!exif_data_mnote_set_add_entry(md, MAKER_SAMSUNG, tag, EXIF_FORMAT_LONG, 1, index)){ + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] exif_data_mnote_set_add_entry() failed. \n", __LINE__, __func__); + return MM_ERROR_CAMCORDER_MNOTE_ADD_ENTRY; + } + break; + case MNOTE_SAMSUNG_TAG_MODEL_ID: + if(!exif_data_mnote_set_add_entry_subtag(md, MAKER_SAMSUNG, tag, EXIF_FORMAT_LONG, 1, MNOTE_SAMSUNG_SUBTAG_MODEL_ID_CLASS, subindex1, MNOTE_SAMSUNG_SUBTAG_MODEL_ID_DEVEL, subindex2, product_id )){ + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] exif_data_mnote_set_add_entry_subtag() failed. \n", __LINE__, __func__); + return MM_ERROR_CAMCORDER_MNOTE_ADD_ENTRY; + } + break; + case MNOTE_SAMSUNG_TAG_COLOR_INFO: + case MNOTE_SAMSUNG_TAG_SERIAL_NUM: + if(!exif_data_mnote_set_add_entry_string(md, MAKER_SAMSUNG, tag, EXIF_FORMAT_ASCII, strlen(serialNum), serialNum)){ + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] exif_data_mnote_set_add_entry_string() failed. \n", __LINE__, __func__); + return MM_ERROR_CAMCORDER_MNOTE_ADD_ENTRY; + } + break; + case MNOTE_SAMSUNG_TAG_IMAGE_COUNT: + case MNOTE_SAMSUNG_TAG_GPS_INFO01: + case MNOTE_SAMSUNG_TAG_GPS_INFO02: + case MNOTE_SAMSUNG_TAG_PREVIEW_IMAGE: + case MNOTE_SAMSUNG_TAG_FAVOR_TAGGING: + case MNOTE_SAMSUNG_TAG_SRW_COMPRESS: + case MNOTE_SAMSUNG_TAG_COLOR_SPACE: + if(!exif_data_mnote_set_add_entry(md, MAKER_SAMSUNG, tag, EXIF_FORMAT_LONG, 1, index)){ + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] exif_data_mnote_set_add_entry() failed. \n", __LINE__, __func__); + return MM_ERROR_CAMCORDER_MNOTE_ADD_ENTRY; + } + break; + case MNOTE_SAMSUNG_TAG_AE: + case MNOTE_SAMSUNG_TAG_AF: + case MNOTE_SAMSUNG_TAG_AWB01: + case MNOTE_SAMSUNG_TAG_AWB02: + case MNOTE_SAMSUNG_TAG_IPC: + case MNOTE_SAMSUNG_TAG_SCENE_RESULT: + case MNOTE_SAMSUNG_TAG_SADEBUG_INFO01: + case MNOTE_SAMSUNG_TAG_SADEBUG_INFO02: + case MNOTE_SAMSUNG_TAG_FACE_DETECTION: + if(!exif_data_mnote_set_add_entry(md, MAKER_SAMSUNG, tag, EXIF_FORMAT_LONG, 1, index)){ + mmf_debug (MMF_DEBUG_ERROR,"[%05d][%s] exif_data_mnote_set_add_entry() failed. \n", __LINE__, __func__); + return MM_ERROR_CAMCORDER_MNOTE_ADD_ENTRY; + } + break; + case MNOTE_SAMSUNG_TAG_FACE_FEAT01: + case MNOTE_SAMSUNG_TAG_FACE_FEAT02: + case MNOTE_SAMSUNG_TAG_FACE_RECOG: + case MNOTE_SAMSUNG_TAG_LENS_INFO: + case MNOTE_SAMSUNG_TAG_THIRDPARTY: + break; + default: + break; + } + return MM_ERROR_NONE; +} + + +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; + + 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) { + mmf_debug (MMF_DEBUG_ERROR, "%s(), fopen() failed [%s].\n", __func__, filename); + return MM_ERROR_IMAGE_FILEOPEN; + } + + /*set SOI, APP1*/ + _exif_set_uint16 (0, &head[0], 0xffd8); + _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*/ + + fclose (fp); + + return MM_ERROR_NONE; +} + +int +mm_exif_write_exif_jpeg_to_memory (void **mem, unsigned int *length, mm_exif_info_t *info, void *jpeg, unsigned int jpeg_len) +{ + /*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; + mmf_debug (MMF_DEBUG_LOG,"[%05d][%s]\n", __LINE__, __func__); + + if(info==NULL || jpeg==NULL) + { + mmf_debug (MMF_DEBUG_ERROR, "%s(), MM_ERROR_CAMCORDER_INVALID_ARGUMENT info=%p, jpeg=%p\n", __func__,info,jpeg); + return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + } + + if(jpeg_len>JPEG_MAX_SIZE) + { + mmf_debug (MMF_DEBUG_ERROR, "%s(),jpeg_len is worng jpeg_len=%d\n", __func__,jpeg_len); + return MM_ERROR_CAMCORDER_DEVICE_WRONG_JPEG; + } + + 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); + /*alloc output image*/ + m = malloc (m_len); + if (!m) { + mmf_debug (MMF_DEBUG_ERROR, "%s(), malloc() failed.\n", __func__); + return MM_ERROR_CAMCORDER_LOW_MEMORY; + } + + /*set SOI, APP1*/ + _exif_set_uint16 (0, &head[0], 0xffd8); + _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__); + 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*/ + + /*set ouput param*/ + *mem = m; + *length = m_len; + + return MM_ERROR_NONE; +} diff --git a/src/mm_camcorder_gstcommon.c b/src/mm_camcorder_gstcommon.c new file mode 100644 index 0000000..b631caf --- /dev/null +++ b/src/mm_camcorder_gstcommon.c @@ -0,0 +1,2243 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include <gst/interfaces/xoverlay.h> +#include <gst/interfaces/cameracontrol.h> +#include <sys/time.h> +#include <unistd.h> + +#include "mm_camcorder_internal.h" +#include "mm_camcorder_gstcommon.h" + +/*----------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS for internal | +-----------------------------------------------------------------------*/ +/* Table for compatibility between audio codec and file format */ +gboolean audiocodec_fileformat_compatibility_table[MM_AUDIO_CODEC_NUM][MM_FILE_FORMAT_NUM] = +{ /* 3GP ASF AVI MATROSKA MP4 OGG NUT QT REAL AMR AAC MP3 AIFF AU WAV MID MMF DIVX FLV VOB IMELODY WMA WMV JPG */ +/*AMR*/ { 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*G723.1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MP3*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*OGG*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*AAC*/ { 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*WMA*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MMF*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*ADPCM*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*WAVE*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*WAVE_NEW*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MIDI*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*IMELODY*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MXMF*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MPA*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MP2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*G711*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*G722*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*G722.1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*G722.2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*G723*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*G726*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*G728*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*G729*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*G729A*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*G729.1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*REAL*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*AAC_LC*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*AAC_MAIN*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*AAC_SRS*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*AAC_LTP*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*AAC_HE_V1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*AAC_HE_V2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*AC3*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*ALAC*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*ATRAC*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*SPEEX*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*VORBIS*/ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*AIFF*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*AU*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*NONE*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*PCM*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*ALAW*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MULAW*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MS_ADPCM*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +}; + +/* Table for compatibility between video codec and file format */ +gboolean videocodec_fileformat_compatibility_table[MM_VIDEO_CODEC_NUM][MM_FILE_FORMAT_NUM] = +{ /* 3GP ASF AVI MATROSKA MP4 OGG NUT QT REAL AMR AAC MP3 AIFF AU WAV MID MMF DIVX FLV VOB IMELODY WMA WMV JPG */ +/*NONE*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*H263*/ { 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*H264*/ { 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*H26L*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MPEG4*/ { 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MPEG1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*WMV*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*DIVX*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*XVID*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*H261*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*H262*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*H263V2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*H263V3*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MJPEG*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MPEG2*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MPEG4_SIMPLE*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MPEG4_ADV*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MPEG4_MAIN*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MPEG4_CORE*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MPEG4_ACE*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MPEG4_ARTS*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*MPEG4_AVC*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*REAL*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*VC1*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*AVS*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*CINEPAK*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*INDEO*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +/*THEORA*/ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, +}; + + +/*----------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS for internal | +-----------------------------------------------------------------------*/ +#define USE_AUDIO_CLOCK_TUNE +#define _MMCAMCORDER_WAIT_EOS_TIME 5.0 //sec +#define _DPRAM_RAW_PCM_LOCATION "/dev/rawPCM0" + +/*----------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +-----------------------------------------------------------------------*/ +/* STATIC INTERNAL FUNCTION */ +/** + * These functions are preview video data probing function. + * If this function is linked with certain pad by gst_pad_add_buffer_probe(), + * this function will be called when data stream pass through the pad. + * + * @param[in] pad probing pad which calls this function. + * @param[in] buffer buffer which contains stream data. + * @param[in] u_data user data. + * @return This function returns true on success, or false value with error + * @remarks + * @see __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); + +/*======================================================================================= +| FUNCTION DEFINITIONS | +=======================================================================================*/ +/*----------------------------------------------------------------------- +| GLOBAL FUNCTION DEFINITIONS: | +-----------------------------------------------------------------------*/ +int _mmcamcorder_create_videosrc_bin(MMHandleType handle) +{ + int err = MM_ERROR_NONE; + int rotate = 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; + char *videosrc_name = NULL; + char *err_name = NULL; + + GList *element_list = NULL; + GstCaps *caps = NULL; + GstPad *video_tee0 = NULL; + GstPad *video_tee1 = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + type_element *VideosrcElement = NULL; + type_int_array *input_index = 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); + + _mmcam_dbg_log(""); + + /* Check existence */ + if (sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst) { + if (((GObject *)sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst)->ref_count > 0) { + gst_object_unref(sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst); + } + _mmcam_dbg_log("_MMCAMCORDER_VIDEOSRC_BIN is Already existed."); + } + + /* Get video device index info */ + _mmcamcorder_conf_get_value_int_array(hcamcorder->conf_ctrl, + CONFIGURE_CATEGORY_CTRL_CAMERA, + "InputIndex", + &input_index ); + if (input_index == NULL) { + _mmcam_dbg_err("Failed to get input_index"); + return MM_ERROR_CAMCORDER_CREATE_CONFIGURE; + } + + err = mm_camcorder_get_attributes(handle, &err_name, + MMCAM_CAMERA_FORMAT, &PictureFormat, + MMCAM_CAMERA_FPS, &fps, + "camera-slow-motion-fps", &slow_fps, + MMCAM_CAMERA_ROTATION, &rotate, + MMCAM_CAPTURE_WIDTH, &capture_width, + MMCAM_CAPTURE_HEIGHT, &capture_height, + MMCAM_IMAGE_ENCODER, &codectype, + "camera-hold-af-after-capturing", &hold_af, + NULL); + if (err != MM_ERROR_NONE) { + _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err); + SAFE_FREE(err_name); + return err; + } + + /* Get fourcc from picture format */ + sc->fourcc = _mmcamcorder_get_fourcc(PictureFormat, codectype, hcamcorder->use_zero_copy_format); + + /* Get videosrc element and its name from configure */ + _mmcamcorder_conf_get_element(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, + "VideosrcElement", + &VideosrcElement); + _mmcamcorder_conf_get_value_element_name(VideosrcElement, &videosrc_name); + + /* Create bin element */ + __ta__(" videosrc_bin", + _MMCAMCORDER_BIN_MAKE(sc, _MMCAMCORDER_VIDEOSRC_BIN, "videosrc_bin", err); + ); + + /* Create child element */ + __ta__(" videosrc_src", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSRC_SRC, videosrc_name, "videosrc_src", element_list, err); + ); + __ta__(" videosrc_capsfilter", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSRC_FILT, "capsfilter", "videosrc_filter", element_list, err); + ); + + sc->is_slow = FALSE; + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "high-speed-fps", 0); + 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); + + 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); + ); + + _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 (slow_fps > 0) { + sc->is_slow = TRUE; + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "high-speed-fps", fps); + } + } + + __ta__(" tee", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSRC_TEE, "tee", "videosrc_tee", element_list, err); + ); + + /* Set basic infomation of videosrc element */ + _mmcamcorder_conf_set_value_element_property(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, VideosrcElement); + + /* Set video device index */ + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "camera-id", input_index->default_value); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", hold_af); + + _mmcam_dbg_log("Current mode[%d]", hcamcorder->type); + + /* Set sensor mode as CAMERA */ + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "sensor-mode", 0); + + /* Set caps by rotation */ + _mmcamcorder_set_videosrc_rotation(handle, rotate); + + if (!_mmcamcorder_add_elements_to_bin(GST_BIN(sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst), element_list)) { + _mmcam_dbg_err( "element add error." ); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + if (!_mmcamcorder_link_elements(element_list)) { + _mmcam_dbg_err( "element link error." ); + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + + video_tee0 = gst_element_get_request_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, "src%d"); + video_tee1 = gst_element_get_request_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, "src%d"); + + MMCAMCORDER_G_OBJECT_SET((sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst), "alloc-pad", video_tee0); + + /* Ghost pad */ + if ((gst_element_add_pad( sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst, gst_ghost_pad_new("src0", video_tee0) )) < 0) { + _mmcam_dbg_err("failed to create ghost pad1 on _MMCAMCORDER_VIDEOSRC_BIN."); + gst_object_unref(video_tee0); + video_tee0 = NULL; + gst_object_unref(video_tee1); + video_tee1 = NULL; + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + + if ((gst_element_add_pad( sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst, gst_ghost_pad_new("src1", video_tee1) )) < 0) { + _mmcam_dbg_err("failed to create ghost pad2 on _MMCAMCORDER_VIDEOSRC_BIN."); + gst_object_unref(video_tee0); + video_tee0 = NULL; + gst_object_unref(video_tee1); + video_tee1 = NULL; + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + + gst_object_unref(video_tee0); + video_tee0 = NULL; + gst_object_unref(video_tee1); + video_tee1 = NULL; + + if (element_list) { + g_list_free(element_list); + element_list = NULL; + } + + return MM_ERROR_NONE; + +pipeline_creation_error: + _MMCAMCORDER_ELEMENT_REMOVE( sc, _MMCAMCORDER_VIDEOSRC_SRC ); + _MMCAMCORDER_ELEMENT_REMOVE( sc, _MMCAMCORDER_VIDEOSRC_FILT ); + _MMCAMCORDER_ELEMENT_REMOVE( sc, _MMCAMCORDER_VIDEOSRC_SCALE ); + _MMCAMCORDER_ELEMENT_REMOVE( sc, _MMCAMCORDER_VIDEOSRC_VSFLT ); + _MMCAMCORDER_ELEMENT_REMOVE( sc, _MMCAMCORDER_VIDEOSRC_TEE ); + _MMCAMCORDER_ELEMENT_REMOVE( sc, _MMCAMCORDER_VIDEOSRC_BIN ); + if (element_list) { + g_list_free(element_list); + element_list = NULL; + } + + return err; +} + + +int _mmcamcorder_create_audiosrc_bin(MMHandleType handle) +{ + int err = MM_ERROR_NONE; + int val = 0; + int rate = 0; + int format = 0; + int channel = 0; + int a_enc = MM_AUDIO_CODEC_AMR; + int a_dev = MM_AUDIO_DEVICE_MIC; + int UseNoiseSuppressor = 0; + double volume = 0.0; + char *err_name = NULL; + char *audiosrc_name = NULL; + char *cat_name = NULL; + + GstCaps *caps = NULL; + GstPad *pad = NULL; + GList *element_list = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + _MMCamcorderGstElement *last_element = NULL; + type_element *AudiosrcElement = 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); + + _mmcam_dbg_log(""); + + err = _mmcamcorder_check_audiocodec_fileformat_compatibility(handle); + if (err != MM_ERROR_NONE) { + return err; + } + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_RECORD, + "UseNoiseSuppressor", + &UseNoiseSuppressor); + + err = mm_camcorder_get_attributes(handle, &err_name, + MMCAM_AUDIO_DEVICE, &a_dev, + MMCAM_AUDIO_ENCODER, &a_enc, + MMCAM_AUDIO_ENCODER_BITRATE, &val, + MMCAM_AUDIO_SAMPLERATE, &rate, + MMCAM_AUDIO_FORMAT, &format, + MMCAM_AUDIO_CHANNEL, &channel, + MMCAM_AUDIO_VOLUME, &volume, + NULL); + if (err != MM_ERROR_NONE) { + _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err); + SAFE_FREE(err_name); + return err; + } + + /* Check existence */ + if (sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst) { + if (((GObject *)sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst)->ref_count > 0) { + gst_object_unref(sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst); + } + _mmcam_dbg_log("_MMCAMCORDER_AUDIOSRC_BIN is Already existed. Unref once..."); + } + + /* Create bin element */ + __ta__(" audiosource_bin", + _MMCAMCORDER_BIN_MAKE(sc, _MMCAMCORDER_AUDIOSRC_BIN, "audiosource_bin", err); + ); + + if (a_dev == MM_AUDIO_DEVICE_MODEM) { + cat_name = strdup("AudiomodemsrcElement"); + } else { + /* MM_AUDIO_DEVICE_MIC or others */ + cat_name = strdup("AudiosrcElement"); + } + + if (cat_name == NULL) { + _mmcam_dbg_err("strdup failed."); + err = MM_ERROR_CAMCORDER_LOW_MEMORY; + goto pipeline_creation_error; + } + + _mmcamcorder_conf_get_element(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_AUDIO_INPUT, + cat_name, + &AudiosrcElement); + _mmcamcorder_conf_get_value_element_name(AudiosrcElement, &audiosrc_name); + + free(cat_name); + cat_name = NULL; + + _mmcam_dbg_log("Audio src name : %s", audiosrc_name); + + __ta__(" audiosrc", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_AUDIOSRC_SRC, audiosrc_name, NULL, element_list, err); + ); + + _mmcamcorder_conf_set_value_element_property(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, AudiosrcElement); + + __ta__(" audiosource_capsfilter", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_AUDIOSRC_FILT, "capsfilter", NULL, element_list, err); + ); + + if (a_enc != MM_AUDIO_CODEC_VORBIS) { + __ta__(" audiosource_volume", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_AUDIOSRC_VOL, "volume", NULL, element_list, err); + ); + } + + if (UseNoiseSuppressor && a_enc != MM_AUDIO_CODEC_AAC) { + __ta__(" noise_suppressor", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_AUDIOSRC_NS, "noisesuppressor", "audiofilter", element_list, err); + ); + } + + /* Set basic infomation */ + if (a_enc != MM_AUDIO_CODEC_VORBIS) { + int depth = 0; + + if (volume == 0.0) { + /* Because data probe of audio src do the same job, it doesn't need to set "mute" here. Already null raw data. */ + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_AUDIOSRC_VOL].gst, "volume", 1.0); + } else { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_AUDIOSRC_VOL].gst, "mute", FALSE); + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_AUDIOSRC_VOL].gst, "volume", volume); + } + + if (format == MM_CAMCORDER_AUDIO_FORMAT_PCM_S16_LE) { + depth = 16; + } else { /* MM_CAMCORDER_AUDIO_FORMAT_PCM_U8 */ + depth = 8; + } + + caps = gst_caps_new_simple("audio/x-raw-int", + "rate", G_TYPE_INT, rate, + "channels", G_TYPE_INT, channel, + "depth", G_TYPE_INT, depth, + NULL); + _mmcam_dbg_log("caps [x-raw-int,rate:%d,channel:%d,depth:%d]", + rate, channel, depth); + } else { + /* what are the audio encoder which should get audio/x-raw-float? */ + caps = gst_caps_new_simple("audio/x-raw-float", + "rate", G_TYPE_INT, rate, + "channels", G_TYPE_INT, channel, + "endianness", G_TYPE_INT, BYTE_ORDER, + "width", G_TYPE_INT, 32, + NULL); + _mmcam_dbg_log("caps [x-raw-float,rate:%d,channel:%d,endianness:%d,width:32]", + rate, channel, BYTE_ORDER); + } + + MMCAMCORDER_G_OBJECT_SET((sc->element[_MMCAMCORDER_AUDIOSRC_FILT].gst), "caps", caps); + gst_caps_unref(caps); + + if (!_mmcamcorder_add_elements_to_bin(GST_BIN(sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst), element_list)) { + _mmcam_dbg_err("element add error."); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + if (!_mmcamcorder_link_elements(element_list)) { + _mmcam_dbg_err( "element link error." ); + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + + last_element = (_MMCamcorderGstElement*)(g_list_last(element_list)->data); + pad = gst_element_get_static_pad(last_element->gst, "src"); + if ((gst_element_add_pad( sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, gst_ghost_pad_new("src", pad) )) < 0) { + gst_object_unref(pad); + pad = NULL; + _mmcam_dbg_err("failed to create ghost pad on _MMCAMCORDER_AUDIOSRC_BIN."); + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + + gst_object_unref(pad); + pad = NULL; + + if (element_list) { + g_list_free(element_list); + element_list = NULL; + } + + return MM_ERROR_NONE; + +pipeline_creation_error: + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_AUDIOSRC_SRC); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_AUDIOSRC_FILT); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_AUDIOSRC_VOL); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_AUDIOSRC_QUE); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_AUDIOSRC_CONV); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_AUDIOSRC_ENC); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_AUDIOSRC_BIN); + if (element_list) { + g_list_free(element_list); + element_list = NULL; + } + + return err; +} + + +int _mmcamcorder_create_videosink_bin(MMHandleType handle) +{ + int err = MM_ERROR_NONE; + int rect_width = 0; + int rect_height = 0; + int camera_width = 0; + int camera_height = 0; + int rotate = 0; + int camera_format = MM_PIXEL_FORMAT_NV12; + int UseVideoscale = 0, EnableConvertedSC = 0; + int scale_method = 0; + char* videosink_name = NULL; + char* videoscale_name = NULL; + char* err_name = NULL; + + GstCaps *caps = NULL; + GstPad *pad = NULL; + GList *element_list = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + _MMCamcorderGstElement *first_element = NULL; + type_element *VideoscaleElement = 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); + + _mmcam_dbg_log("START"); + + /* Get attributes */ + 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, + "enable-converted-stream-callback", &EnableConvertedSC, + NULL); + if (err != MM_ERROR_NONE) { + _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err); + SAFE_FREE(err_name); + return err; + } + + /* Get videosink name */ + _mmcamcorder_conf_get_value_element_name(sc->VideosinkElement, &videosink_name); + + /* Check existence */ + if (sc->element[_MMCAMCORDER_VIDEOSINK_BIN].gst) { + if (((GObject *)sc->element[_MMCAMCORDER_VIDEOSINK_BIN].gst)->ref_count > 0) { + gst_object_unref(sc->element[_MMCAMCORDER_VIDEOSINK_BIN].gst); + } + _mmcam_dbg_log("_MMCAMCORDER_VIDEOSINK_BIN is Already existed. Unref once..."); + } + + /* Create bin element */ + __ta__(" videosink_bin", + _MMCAMCORDER_BIN_MAKE(sc, _MMCAMCORDER_VIDEOSINK_BIN, "videosink_bin", err); + ); + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT, + "UseVideoscale", + &UseVideoscale); + + /* Create child element */ + if (EnableConvertedSC || + !strcmp(videosink_name, "evasimagesink") || + !strcmp(videosink_name, "ximagesink")) { + if (camera_format == MM_PIXEL_FORMAT_NV12 || + camera_format == MM_PIXEL_FORMAT_NV12T) { + int set_rotate = 0; + + __ta__(" videosink_fimcconvert", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSINK_CLS, "fimcconvert", NULL, element_list, err); + ); + + if (rotate < MM_DISPLAY_ROTATION_FLIP_HORZ) { + set_rotate = rotate * 90; + } else { + set_rotate = 0; + } + + if (rect_width == 0 || rect_height == 0) { + _mmcam_dbg_warn("rect_width or height is 0. set camera width and height."); + + if (rotate == MM_DISPLAY_ROTATION_90 || + rotate == MM_DISPLAY_ROTATION_270) { + rect_width = camera_height; + rect_height = camera_width; + } else { + rect_width = camera_width; + rect_height = camera_height; + } + } + + _mmcam_dbg_log("Fimcconvert set values - %dx%d, rotate: %d", rect_width, rect_height, set_rotate); + 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); + } else { + __ta__(" videosink_ffmpegcolorspace", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSINK_CLS, "ffmpegcolorspace", NULL, element_list, err); + ); + } + } else if(UseVideoscale) { + __ta__(" videosink_queue", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSINK_QUE, "queue", NULL, element_list, err); + ); + + _mmcamcorder_conf_get_element(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT, + "VideoscaleElement", + &VideoscaleElement); + _mmcamcorder_conf_get_value_element_name(VideoscaleElement, &videoscale_name); + + __ta__(" videosink_videoscale", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSINK_SCALE, videoscale_name, NULL, element_list, err); + ); + __ta__(" videosink_capsfilter", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSINK_FILT, "capsfilter", NULL, element_list, err); + ); + + _mmcamcorder_conf_get_value_element_int(VideoscaleElement, "method", &scale_method); + _mmcam_dbg_log("VideoSINK Scale[%dx%d], Method[%d]", rect_width, rect_height, scale_method); + + if (rect_width == 0 || rect_height == 0) { + _mmcam_dbg_warn("rect_width or height is 0. set camera width and height."); + + rect_width = camera_width; + rect_height = camera_height; + } + + caps = gst_caps_new_simple("video/x-raw-yuv", + "width", G_TYPE_INT, rect_width, + "height", G_TYPE_INT, rect_height, + NULL); + MMCAMCORDER_G_OBJECT_SET((sc->element[_MMCAMCORDER_VIDEOSINK_FILT].gst), "caps", caps); + MMCAMCORDER_G_OBJECT_SET((sc->element[_MMCAMCORDER_VIDEOSINK_SCALE].gst), "method", scale_method); + gst_caps_unref(caps); + caps = NULL; + } + + if (sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst == NULL) { + __ta__(" videosink_queue", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_VIDEOSINK_QUE, "queue", "videosink_queue", element_list, err); + ); + } + + __ta__(" videosink", + _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 (_mmcamcorder_videosink_window_set(handle, sc->VideosinkElement) != MM_ERROR_NONE) { + _mmcam_dbg_err("_mmcamcorder_videosink_window_set error"); + err = MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + goto pipeline_creation_error; + } + } + + _mmcamcorder_conf_set_value_element_property(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, sc->VideosinkElement); + + if (!_mmcamcorder_add_elements_to_bin(GST_BIN(sc->element[_MMCAMCORDER_VIDEOSINK_BIN].gst), element_list)) { + _mmcam_dbg_err("element add error."); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + if (!_mmcamcorder_link_elements(element_list)) { + _mmcam_dbg_err("element link error."); + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + + first_element = (_MMCamcorderGstElement*)(element_list->data); + __ta__(" gst_element_get_static_pad", + pad = gst_element_get_static_pad( first_element->gst, "sink"); + ); + if ((gst_element_add_pad( sc->element[_MMCAMCORDER_VIDEOSINK_BIN].gst, gst_ghost_pad_new("sink", pad) )) < 0) { + gst_object_unref(pad); + pad = NULL; + _mmcam_dbg_err("failed to create ghost pad on _MMCAMCORDER_VIDEOSINK_BIN."); + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + + gst_object_unref(pad); + pad = NULL; + + if (element_list) { + g_list_free(element_list); + element_list = NULL; + } + + _mmcam_dbg_log("END"); + + return MM_ERROR_NONE; + +pipeline_creation_error: + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_VIDEOSINK_QUE); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_VIDEOSINK_SCALE); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_VIDEOSINK_FILT); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_VIDEOSINK_CLS); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_VIDEOSINK_SINK); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_VIDEOSINK_BIN); + if (element_list) { + g_list_free(element_list); + element_list = NULL; + } + + return err; +} + + +int _mmcamcorder_create_encodesink_bin(MMHandleType handle) +{ + 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; + int encodebin_profile = 0; + int auto_audio_convert = 0; + int auto_audio_resample = 0; + int auto_color_space = 0; + char *gst_element_venc_name = NULL; + char *gst_element_aenc_name = NULL; + char *gst_element_ienc_name = NULL; + char *gst_element_mux_name = NULL; + char *gst_element_rsink_name = NULL; + char *str_profile = NULL; + char *str_aac = NULL; + char *str_aar = NULL; + char *str_acs = NULL; + char *err_name = NULL; + + GstCaps *caps = NULL; + GstPad *pad = NULL; + GList *element_list = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + type_element *VideoencElement = NULL; + type_element *AudioencElement = NULL; + type_element *ImageencElement = NULL; + type_element *MuxElement = NULL; + type_element *RecordsinkElement = 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); + + _mmcam_dbg_log(""); + + /* Check existence */ + if (sc->element[_MMCAMCORDER_ENCSINK_BIN].gst) { + if (((GObject *)sc->element[_MMCAMCORDER_ENCSINK_BIN].gst)->ref_count > 0) { + gst_object_unref(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst); + } + _mmcam_dbg_log("_MMCAMCORDER_ENCSINK_BIN is Already existed."); + } + + /* Create bin element */ + __ta__(" encodesink_bin", + _MMCAMCORDER_BIN_MAKE(sc, _MMCAMCORDER_ENCSINK_BIN, "encodesink_bin", err); + ); + + /* Create child element */ + __ta__(" encodebin", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_ENCBIN, "encodebin", NULL, element_list, err); + ); + + /* 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; + } + + _mmcam_dbg_log("Profile[%d]", profile); + + /* Set information */ + if (profile == MM_CAMCORDER_MODE_VIDEO) { + str_profile = "VideoProfile"; + str_aac = "VideoAutoAudioConvert"; + str_aar = "VideoAutoAudioResample"; + str_acs = "VideoAutoColorSpace"; + } else if (profile == MM_CAMCORDER_MODE_AUDIO) { + str_profile = "AudioProfile"; + str_aac = "AudioAutoAudioConvert"; + str_aar = "AudioAutoAudioResample"; + str_acs = "AudioAutoColorSpace"; + } else if (profile == MM_CAMCORDER_MODE_IMAGE) { + str_profile = "ImageProfile"; + str_aac = "ImageAutoAudioConvert"; + str_aar = "ImageAutoAudioResample"; + str_acs = "ImageAutoColorSpace"; + } + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, CONFIGURE_CATEGORY_MAIN_RECORD, str_profile, &encodebin_profile); + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, CONFIGURE_CATEGORY_MAIN_RECORD, str_aac, &auto_audio_convert); + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, CONFIGURE_CATEGORY_MAIN_RECORD, str_aar, &auto_audio_resample); + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, CONFIGURE_CATEGORY_MAIN_RECORD, str_acs, &auto_color_space); + + _mmcam_dbg_log("Profile:%d, AutoAudioConvert:%d, AutoAudioResample:%d, AutoColorSpace:%d", + encodebin_profile, auto_audio_convert, auto_audio_resample, auto_color_space); + + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "profile", encodebin_profile); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "auto-audio-convert", auto_audio_convert); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "auto-audio-resample", auto_audio_resample); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "auto-colorspace", auto_color_space); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "use-video-toggle", FALSE); + + /* Codec */ + if (profile == MM_CAMCORDER_MODE_VIDEO) { + int use_venc_queue = 0; + + VideoencElement = _mmcamcorder_get_type_element(handle, MM_CAM_VIDEO_ENCODER); + + if (!VideoencElement) { + _mmcam_dbg_err("Fail to get type element"); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + _mmcamcorder_conf_get_value_element_name(VideoencElement, &gst_element_venc_name); + + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "venc-name", gst_element_venc_name); + _MMCAMCORDER_ENCODEBIN_ELMGET(sc, _MMCAMCORDER_ENCSINK_VENC, "video-encode", err); + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_RECORD, + "UseVideoEncoderQueue", + &use_venc_queue); + 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; + + 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_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_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); + } + } + } + + if (profile == MM_CAMCORDER_MODE_IMAGE) { + ImageencElement = _mmcamcorder_get_type_element(handle, MM_CAM_IMAGE_ENCODER); + if (!ImageencElement) { + _mmcam_dbg_err("Fail to get type element"); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + _mmcamcorder_conf_get_value_element_name(ImageencElement, &gst_element_ienc_name); + + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "ienc-name", gst_element_ienc_name); + _MMCAMCORDER_ENCODEBIN_ELMGET(sc, _MMCAMCORDER_ENCSINK_IENC, "image-encode", err); + } + + /* Mux */ + if (profile == MM_CAMCORDER_MODE_AUDIO || profile == MM_CAMCORDER_MODE_VIDEO) { + MuxElement = _mmcamcorder_get_type_element(handle, MM_CAM_FILE_FORMAT); + if (!MuxElement) { + _mmcam_dbg_err("Fail to get type element"); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + _mmcamcorder_conf_get_value_element_name(MuxElement, &gst_element_mux_name); + + __ta__(" mux", + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "mux-name", gst_element_mux_name); + ); + _MMCAMCORDER_ENCODEBIN_ELMGET(sc, _MMCAMCORDER_ENCSINK_MUX, "mux", err); + + _mmcamcorder_conf_set_value_element_property(sc->element[_MMCAMCORDER_ENCSINK_MUX].gst, MuxElement); + } + + /* Sink */ + if (profile == MM_CAMCORDER_MODE_AUDIO || profile == MM_CAMCORDER_MODE_VIDEO) { + _mmcamcorder_conf_get_element(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_RECORD, + "RecordsinkElement", + &RecordsinkElement ); + _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name); + + __ta__(" Recordsink_sink", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_SINK, gst_element_rsink_name, NULL, element_list, err); + ); + + _mmcamcorder_conf_set_value_element_property(sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, RecordsinkElement); + } else { + /* for stillshot */ + __ta__(" fakesink", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_ENCSINK_SINK, "fakesink", NULL, element_list, err); + ); + } + + if (profile == MM_CAMCORDER_MODE_VIDEO) { + /* video encoder attribute setting */ + if (v_bitrate > 0) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "bitrate", v_bitrate); + } else { + _mmcam_dbg_warn("video bitrate is too small[%d], so skip setting. Use DEFAULT value.", v_bitrate); + } + /*MMCAMCORDER_G_OBJECT_SET ((sc->element[_MMCAMCORDER_ENCSINK_VENC].gst),"hw-accel", v_hw);*/ + _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."); + } + _mmcamcorder_conf_set_value_element_property( sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, AudioencElement ); + } + } + + _mmcam_dbg_log("Element creation complete"); + + /* Add element to bin */ + if (!_mmcamcorder_add_elements_to_bin(GST_BIN(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst), element_list)) { + _mmcam_dbg_err("element add error."); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + _mmcam_dbg_log("Element add complete"); + + if (profile == MM_CAMCORDER_MODE_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); + pad = NULL; + _mmcam_dbg_err("failed to create ghost video_sink0 on _MMCAMCORDER_ENCSINK_BIN."); + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + gst_object_unref(pad); + pad = NULL; + + if (sc->is_slow == 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); + pad = NULL; + _mmcam_dbg_err("failed to create ghost audio_sink0 on _MMCAMCORDER_ENCSINK_BIN."); + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + gst_object_unref(pad); + pad = NULL; + } + } else if (profile == MM_CAMCORDER_MODE_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); + pad = NULL; + _mmcam_dbg_err("failed to create ghost audio_sink0 on _MMCAMCORDER_ENCSINK_BIN."); + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + gst_object_unref(pad); + pad = NULL; + } else { + /* for stillshot */ + pad = gst_element_get_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "image"); + if (gst_element_add_pad(sc->element[_MMCAMCORDER_ENCSINK_BIN].gst, gst_ghost_pad_new("image_sink0", pad)) < 0) { + gst_object_unref(pad); + pad = NULL; + _mmcam_dbg_err("failed to create ghost image_sink0 on _MMCAMCORDER_ENCSINK_BIN."); + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + gst_object_unref(pad); + pad = NULL; + } + + _mmcam_dbg_log("Get pad complete"); + + /* Link internal element */ + if (!_mmcamcorder_link_elements(element_list)) { + _mmcam_dbg_err("element link error."); + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + + if (element_list) { + g_list_free(element_list); + element_list = NULL; + } + + return MM_ERROR_NONE; + +pipeline_creation_error : + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_ENCSINK_ENCBIN); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_ENCSINK_VENC); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_ENCSINK_AENC); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_ENCSINK_IENC); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_ENCSINK_MUX); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_ENCSINK_SINK); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_ENCSINK_BIN); + if (element_list) { + g_list_free(element_list); + element_list = NULL; + } + + return err; +} + + +int _mmcamcorder_create_stillshotsink_bin(MMHandleType handle) +{ + int err = MM_ERROR_NONE; + int capture_width = 0; + int capture_height = 0; + int UseCaptureMode = 0; + char *gst_element_ienc_name = NULL; + char *gst_element_videoscale_name = NULL; + + GList *element_list = NULL; + GstPad *pad = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + _MMCamcorderGstElement *first_element = NULL; + type_element* ImageencElement = NULL; + type_element* VideoscaleElement = 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); + + _mmcam_dbg_log(""); + + /* Check existence */ + if (sc->element[_MMCAMCORDER_STILLSHOTSINK_BIN].gst) { + if (((GObject *)sc->element[_MMCAMCORDER_STILLSHOTSINK_BIN].gst)->ref_count > 0) { + gst_object_unref(sc->element[_MMCAMCORDER_STILLSHOTSINK_BIN].gst); + } + _mmcam_dbg_log("_MMCAMCORDER_STILLSHOTSINK_BIN is Already existed. Unref once..."); + } + + /* Check element availability */ + ImageencElement = _mmcamcorder_get_type_element(handle, MM_CAM_IMAGE_ENCODER); + if (!ImageencElement) { + _mmcam_dbg_err("Fail to get type element"); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + _mmcamcorder_conf_get_value_element_name(ImageencElement, &gst_element_ienc_name); + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_CAPTURE, + "UseCaptureMode", + &UseCaptureMode); + + /* Create bin element */ + __ta__(" stillshotsink_bin", + _MMCAMCORDER_BIN_MAKE(sc, _MMCAMCORDER_STILLSHOTSINK_BIN, "stillshotsink_bin", err); + ); + + /* Create child element */ + __ta__(" stillshotsink_queue", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_STILLSHOTSINK_QUE, "queue", NULL, element_list, err); + ); + __ta__(" stillshotsink_toggle", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_STILLSHOTSINK_TOGGLE, "toggle", NULL, element_list, err); + ); + + if (UseCaptureMode) { + _mmcamcorder_conf_get_element(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_CAPTURE, + "VideoscaleElement", + &VideoscaleElement); + _mmcamcorder_conf_get_value_element_name(VideoscaleElement, &gst_element_videoscale_name); + + __ta__(" stillshotsink_videoscale", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_STILLSHOTSINK_SCALE, "gst_element_videoscale_name", NULL, element_list, err); + ); + __ta__(" stillshotsink_videocrop", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_STILLSHOTSINK_CROP, "videocrop", NULL, element_list, err); + ); + __ta__(" stillshotsink_capsfiltern", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_STILLSHOTSINK_FILT, "capsfilter", NULL, element_list, err); + ); + } + + __ta__(" image encoder", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_STILLSHOTSINK_ENC, gst_element_ienc_name, NULL, element_list, err); + ); + + __ta__(" fakesink", + _MMCAMCORDER_ELEMENT_MAKE(sc, _MMCAMCORDER_STILLSHOTSINK_SINK, "fakesink", NULL, element_list, err); + ); + + if (UseCaptureMode) { + _mmcamcorder_conf_set_value_element_property(sc->element[_MMCAMCORDER_STILLSHOTSINK_SCALE].gst, VideoscaleElement); + + /* Set property */ + mm_camcorder_get_attributes(handle, NULL, + MMCAM_CAPTURE_WIDTH, &capture_width, + MMCAM_CAPTURE_HEIGHT, &capture_height, + NULL); + + __ta__(" _mmcamcorder_set_resize_property", + err = _mmcamcorder_set_resize_property(handle, capture_width, capture_height); + ); + if (err != MM_ERROR_NONE) { + //unref?? + _mmcam_dbg_log("Set resize property failed."); + goto pipeline_creation_error; + } + } + + if (!_mmcamcorder_add_elements_to_bin(GST_BIN(sc->element[_MMCAMCORDER_STILLSHOTSINK_BIN].gst), element_list)) { + _mmcam_dbg_err( "element add error." ); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + if (!_mmcamcorder_link_elements(element_list)) { + _mmcam_dbg_err( "element link error." ); + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + + first_element = (_MMCamcorderGstElement*)(element_list->data); + + pad = gst_element_get_static_pad(first_element->gst, "sink"); + if (gst_element_add_pad( sc->element[_MMCAMCORDER_STILLSHOTSINK_BIN].gst, gst_ghost_pad_new("sink", pad)) < 0) { + gst_object_unref(pad); + pad = NULL; + _mmcam_dbg_err("failed to create ghost pad on _MMCAMCORDER_STILLSHOTSINK_BIN."); + err = MM_ERROR_CAMCORDER_GST_LINK; + goto pipeline_creation_error; + } + gst_object_unref(pad); + pad = NULL; + + if (element_list) { + g_list_free(element_list); + element_list = NULL; + } + + return MM_ERROR_NONE; + +pipeline_creation_error : + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_STILLSHOTSINK_QUE); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_STILLSHOTSINK_TOGGLE); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_STILLSHOTSINK_CROP); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_STILLSHOTSINK_FILT); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_STILLSHOTSINK_SCALE); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_STILLSHOTSINK_ENC); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_STILLSHOTSINK_SINK); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_STILLSHOTSINK_BIN); + if (element_list) { + g_list_free(element_list); + element_list = NULL; + } + + return err; +} + + +int _mmcamcorder_create_preview_pipeline(MMHandleType handle) +{ + int err = MM_ERROR_NONE; + + GstPad *srcpad = NULL; + GstPad *sinkpad = NULL; + GstBus *bus = NULL; + + 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, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log(""); + + /** Create gstreamer element **/ + /* Main pipeline */ + _MMCAMCORDER_PIPELINE_MAKE(sc, _MMCAMCORDER_MAIN_PIPE, "camcorder_pipeline", err); + + /* Sub pipeline */ + __ta__(" __mmcamcorder_create_videosrc_bin", + err = _mmcamcorder_create_videosrc_bin((MMHandleType)hcamcorder); + ); + if (err != MM_ERROR_NONE ) { + goto pipeline_creation_error; + } + + __ta__(" _mmcamcorder_create_videosink_bin", + err = _mmcamcorder_create_videosink_bin((MMHandleType)hcamcorder); + ); + if (err != MM_ERROR_NONE ) { + goto pipeline_creation_error; + } + + gst_bin_add_many(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), + sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst, + sc->element[_MMCAMCORDER_VIDEOSINK_BIN].gst, + NULL); + + /* Link each element */ + srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_BIN].gst, "src0"); + sinkpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSINK_BIN].gst, "sink"); + _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"); + 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; + + /* 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); + gst_object_unref(bus); + bus = NULL; + + /* Below signals are meaningfull only when video source is using. */ + MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, + _MMCAMCORDER_HANDLER_PREVIEW, + "nego-complete", + _mmcamcorder_negosig_handler, + hcamcorder); + + return MM_ERROR_NONE; + +pipeline_creation_error: + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_VIDEOSRC_BIN); + _MMCAMCORDER_ELEMENT_REMOVE(sc, _MMCAMCORDER_MAIN_PIPE); + return err; +} + + +void _mmcamcorder_negosig_handler(GstElement *videosrc, MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + _mmcam_dbg_log(""); + + mmf_return_if_fail(hcamcorder); + mmf_return_if_fail(hcamcorder->sub_context); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + + /* kernel was modified. No need to set. + _mmcamcorder_set_attribute_to_camsensor(handle); + */ + + if (sc->cam_stability_count != _MMCAMCORDER_CAMSTABLE_COUNT) { + sc->cam_stability_count = _MMCAMCORDER_CAMSTABLE_COUNT; + } + + if (hcamcorder->type == MM_CAMCORDER_MODE_IMAGE) { + _MMCamcorderImageInfo *info = NULL; + info = sc->info; + 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); + info->resolution_change = FALSE; + } + } +} + + +int _mmcamcorder_videosink_window_set(MMHandleType handle, type_element* VideosinkElement) +{ + int err = MM_ERROR_NONE; + int size = 0; + int retx = 0; + int rety = 0; + int retwidth = 0; + int retheight = 0; + 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 display_geometry_method = MM_DISPLAY_METHOD_LETTER_BOX; + int origin_size = 0; + int zoom_attr = 0; + int zoom_level = 0; + int *overlay = NULL; + gulong xid; + char *err_name = NULL; + char *videosink_name = NULL; + + GstElement *vsink = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + _mmcam_dbg_log(""); + + 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->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + vsink = sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst; + + /* Get video display information */ + __ta__(" videosink get attributes", + err = mm_camcorder_get_attributes(handle, &err_name, + MMCAM_DISPLAY_RECT_X, &retx, + MMCAM_DISPLAY_RECT_Y, &rety, + MMCAM_DISPLAY_RECT_WIDTH, &retwidth, + MMCAM_DISPLAY_RECT_HEIGHT, &retheight, + MMCAM_DISPLAY_ROTATION, &rotation, + MMCAM_DISPLAY_VISIBLE, &visible, + MMCAM_DISPLAY_HANDLE, (void**)&overlay, &size, + MMCAM_DISPLAY_DEVICE, &display_device, + MMCAM_DISPLAY_GEOMETRY_METHOD, &display_geometry_method, + MMCAM_DISPLAY_SCALE, &zoom_attr, + 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")) { + 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." ); + 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")) { + if (overlay) { + MMCAMCORDER_G_OBJECT_SET( vsink, "evas-object", overlay ); + } else { + _mmcam_dbg_err("Evas Object pointer is NULL"); + return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + } + } else { + _mmcam_dbg_warn("Who are you?? (Videosink: %s)", videosink_name); + } + + /* 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; + } + + switch (zoom_attr) { + case MM_DISPLAY_SCALE_DEFAULT: + zoom_level = 1; + break; + case MM_DISPLAY_SCALE_DOUBLE_LENGTH: + zoom_level = 2; + break; + case MM_DISPLAY_SCALE_TRIPLE_LENGTH: + zoom_level = 3; + break; + default: + _mmcam_dbg_warn("Unsupported zoom value. set as default."); + zoom_level = 1; + 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) { + g_object_set(vsink, + "dst-roi-x", retx, + "dst-roi-y", rety, + "dst-roi-w", retwidth, + "dst-roi-h", retheight, + NULL); + } + } + + return MM_ERROR_NONE; +} + + +int _mmcamcorder_vframe_stablize(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder= MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + _mmcam_dbg_log("%d", _MMCAMCORDER_CAMSTABLE_COUNT); + + 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); + + if (sc->cam_stability_count != _MMCAMCORDER_CAMSTABLE_COUNT) { + sc->cam_stability_count = _MMCAMCORDER_CAMSTABLE_COUNT; + } + + return MM_ERROR_NONE; +} + +/* Retreive device information and set them to attributes */ +gboolean _mmcamcorder_get_device_info(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + GstCameraControl *control = NULL; + GstCameraControlExifInfo exif_info = {0,}; + + mmf_return_val_if_fail(hcamcorder, FALSE); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + + if (sc && sc->element) { + int err = MM_ERROR_NONE; + char *err_name = NULL; + double focal_len = 0.0; + + /* Video input device */ + if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) { + /* Exif related information */ + control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); + if (control != NULL) { + gst_camera_control_get_exif_info(control, &exif_info); //get video input device information + focal_len = ((double)exif_info.focal_len_numerator) / ((double) exif_info.focal_len_denominator); + } else { + _mmcam_dbg_err("Fail to get camera control interface!"); + focal_len = 0.0; + } + } + + /* Set values to attributes */ + err = mm_camcorder_set_attributes(handle, &err_name, + MMCAM_CAMERA_FOCAL_LENGTH, focal_len, + NULL); + if (err != MM_ERROR_NONE) { + _mmcam_dbg_err("Set attributes error(%s:%x)!", err_name, err); + if (err_name) { + free(err_name); + err_name = NULL; + } + return FALSE; + } + } else { + _mmcam_dbg_warn( "Sub context isn't exist."); + return FALSE; + } + + return TRUE; +} + + +static gboolean __mmcamcorder_video_dataprobe_preview(GstPad *pad, GstBuffer *buffer, gpointer u_data) +{ + int current_state = MM_CAMCORDER_STATE_NONE; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); + _MMCamcorderSubContext *sc = NULL; + _MMCamcorderKPIMeasure *kpi = NULL; + + mmf_return_val_if_fail(hcamcorder, TRUE); + + sc = MMF_CAMCORDER_SUBCONTEXT(u_data); + mmf_return_val_if_fail(sc, TRUE); + + current_state = hcamcorder->state; + + if (sc->drop_vframe > 0) { + if (sc->pass_first_vframe > 0) { + sc->pass_first_vframe--; + _mmcam_dbg_log("Pass video frame by pass_first_vframe"); + } else { + sc->drop_vframe--; + _mmcam_dbg_log("Drop video frame by drop_vframe"); + return FALSE; + } + } else if (sc->cam_stability_count > 0) { + sc->cam_stability_count--; + _mmcam_dbg_log("Drop video frame by cam_stability_count"); + return FALSE; + } + + if (current_state >= MM_CAMCORDER_STATE_PREPARE) { + int diff_sec; + int frame_count = 0; + struct timeval current_video_time; + + kpi = &(sc->kpi); + if (kpi->init_video_time.tv_sec == kpi->last_video_time.tv_sec && + kpi->init_video_time.tv_usec == kpi->last_video_time.tv_usec && + kpi->init_video_time.tv_usec == 0) { + _mmcam_dbg_log("START to measure FPS"); + gettimeofday(&(kpi->init_video_time), NULL); + } + + frame_count = ++(kpi->video_framecount); + + gettimeofday(¤t_video_time, NULL); + diff_sec = current_video_time.tv_sec - kpi->last_video_time.tv_sec; + if (diff_sec != 0) { + kpi->current_fps = (frame_count - kpi->last_framecount) / diff_sec; + if ((current_video_time.tv_sec - kpi->init_video_time.tv_sec) != 0) { + int framecount = kpi->video_framecount; + int elased_sec = current_video_time.tv_sec - kpi->init_video_time.tv_sec; + kpi->average_fps = framecount / elased_sec; + } + + kpi->last_framecount = frame_count; + kpi->last_video_time.tv_sec = current_video_time.tv_sec; + kpi->last_video_time.tv_usec = current_video_time.tv_usec; + /* + _mmcam_dbg_log("current fps(%d), average(%d)", kpi->current_fps, kpi->average_fps); + */ + } + } + + 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; + } + + if (hcamcorder->vstream_cb && buffer) { + GstCaps *caps = NULL; + GstStructure *structure = NULL; + int state = MM_CAMCORDER_STATE_NULL; + unsigned int fourcc = 0; + MMCamcorderVideoStreamDataType stream; + + state = _mmcamcorder_get_state((MMHandleType)hcamcorder); + if (state < MM_CAMCORDER_STATE_PREPARE) { + _mmcam_dbg_warn("Not ready for stream callback"); + return TRUE; + } + + caps = gst_buffer_get_caps(buffer); + if (caps == NULL) { + _mmcam_dbg_warn( "Caps is NULL." ); + return TRUE; + } + + structure = gst_caps_get_structure( caps, 0 ); + gst_structure_get_int(structure, "width", &(stream.width)); + gst_structure_get_int(structure, "height", &(stream.height)); + gst_structure_get_fourcc(structure, "format", &fourcc); + stream.format = _mmcamcorder_get_pixtype(fourcc); + gst_caps_unref( caps ); + caps = NULL; + + /* + _mmcam_dbg_log( "Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]", + GST_BUFFER_DATA(buffer), stream.width, stream.height, stream.format ); + */ + + if (stream.width == 0 || stream.height == 0) { + _mmcam_dbg_warn("Wrong condition!!"); + return TRUE; + } + + stream.data = (void *)GST_BUFFER_DATA(buffer); + stream.length = GST_BUFFER_SIZE(buffer); + stream.timestamp = (unsigned int)(GST_BUFFER_TIMESTAMP(buffer)/1000000); /* nano sec -> mili sec */ + + _MMCAMCORDER_LOCK_VSTREAM_CALLBACK(hcamcorder); + if (hcamcorder->vstream_cb) { + hcamcorder->vstream_cb(&stream, hcamcorder->vstream_cb_param); + } + _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; + } + + 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; + } +} + + +int __mmcamcorder_get_amrnb_bitrate_mode(int bitrate) +{ + int result = MM_CAMCORDER_MR475; + + if (bitrate< 5150) { + result = MM_CAMCORDER_MR475; /*AMR475*/ + } else if (bitrate< 5900) { + result = MM_CAMCORDER_MR515; /*AMR515*/ + } else if (bitrate < 6700) { + result = MM_CAMCORDER_MR59; /*AMR59*/ + } else if (bitrate< 7400) { + result = MM_CAMCORDER_MR67; /*AMR67*/ + } else if (bitrate< 7950) { + result = MM_CAMCORDER_MR74; /*AMR74*/ + } else if (bitrate < 10200) { + result = MM_CAMCORDER_MR795; /*AMR795*/ + } else if (bitrate < 12200) { + result = MM_CAMCORDER_MR102; /*AMR102*/ + } else { + result = MM_CAMCORDER_MR122; /*AMR122*/ + } + + return result; +} + +int _mmcamcorder_get_eos_message(MMHandleType handle) +{ + double elapsed = 0.0; + + GstMessage *gMessage = NULL; + GstBus *bus = NULL; + GstClockTime timeout = 1 * GST_SECOND; /* maximum waiting time */ + GTimer *timer = NULL; + + mmf_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); + + _mmcam_dbg_log(""); + + bus = gst_pipeline_get_bus(GST_PIPELINE(sc->element[_MMCAMCORDER_MAIN_PIPE].gst)); + timer = g_timer_new(); + + if (sc && !(sc->bget_eos)) { + while (1) { + elapsed = g_timer_elapsed(timer, NULL); + + /*_mmcam_dbg_log("elapsed:%f sec", elapsed);*/ + + if (elapsed > _MMCAMCORDER_WAIT_EOS_TIME) { + _mmcam_dbg_warn("Timeout. EOS isn't received."); + g_timer_destroy(timer); + gst_object_unref(bus); + return MM_ERROR_CAMCORDER_RESPONSE_TIMEOUT; + } + + gMessage = gst_bus_timed_pop (bus, timeout); + if (gMessage != NULL) { + _mmcam_dbg_log("Get message(%x).", GST_MESSAGE_TYPE(gMessage)); + _mmcamcorder_pipeline_cb_message(bus, gMessage, (void*)hcamcorder); + + if (GST_MESSAGE_TYPE(gMessage) == GST_MESSAGE_EOS || sc->bget_eos) { + gst_message_unref(gMessage); + break; + } + gst_message_unref(gMessage); + } else { + _mmcam_dbg_log("timeout of gst_bus_timed_pop()"); + if (sc->bget_eos) { + _mmcam_dbg_log("Get EOS in another thread."); + break; + } + } + } + } + + g_timer_destroy(timer); + gst_object_unref(bus); + + _mmcam_dbg_log("END"); + + return MM_ERROR_NONE; +} + + +void _mmcamcorder_remove_element_handle(MMHandleType handle, int first_elem, int last_elem) +{ + int i = 0; + _MMCamcorderSubContext *sc = NULL; + + mmf_return_if_fail(handle); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_if_fail(sc); + mmf_return_if_fail(sc->element); + mmf_return_if_fail((first_elem > 0) && (last_elem > 0) && (last_elem > first_elem)); + + _mmcam_dbg_log(""); + + for (i = first_elem ; i <= last_elem ; i++) { + sc->element[i].gst = NULL; + sc->element[i].id = _MMCAMCORDER_NONE; + } + + return; +} + + +int _mmcamcorder_check_audiocodec_fileformat_compatibility(MMHandleType handle) +{ + int err = MM_ERROR_NONE; + int audio_codec = MM_AUDIO_CODEC_INVALID; + int file_format = MM_FILE_FORMAT_INVALID; + + char *err_name = NULL; + + err = mm_camcorder_get_attributes(handle, &err_name, + MMCAM_AUDIO_ENCODER, &audio_codec, + MMCAM_FILE_FORMAT, &file_format, + NULL); + if (err != MM_ERROR_NONE) { + _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err); + SAFE_FREE(err_name); + return err; + } + + /* Check compatibility between audio codec and file format */ + if (audio_codec >= MM_AUDIO_CODEC_INVALID && audio_codec < MM_AUDIO_CODEC_NUM && + file_format >= MM_FILE_FORMAT_INVALID && file_format < MM_FILE_FORMAT_NUM) { + if (audiocodec_fileformat_compatibility_table[audio_codec][file_format] == 0) { + _mmcam_dbg_err("Audio codec[%d] and file format[%d] compatibility FAILED.", + audio_codec, file_format); + return MM_ERROR_CAMCORDER_ENCODER_WRONG_TYPE; + } + + _mmcam_dbg_log("Audio codec[%d] and file format[%d] compatibility SUCCESS.", + audio_codec, file_format); + } else { + _mmcam_dbg_err("Audio codec[%d] or file format[%d] is INVALID.", + audio_codec, file_format); + return MM_ERROR_CAMCORDER_ENCODER_WRONG_TYPE; + } + + return MM_ERROR_NONE; +} + + +int _mmcamcorder_check_videocodec_fileformat_compatibility(MMHandleType handle) +{ + int err = MM_ERROR_NONE; + int video_codec = MM_VIDEO_CODEC_INVALID; + int file_format = MM_FILE_FORMAT_INVALID; + + char *err_name = NULL; + + err = mm_camcorder_get_attributes(handle, &err_name, + MMCAM_VIDEO_ENCODER, &video_codec, + MMCAM_FILE_FORMAT, &file_format, + NULL); + if (err != MM_ERROR_NONE) { + _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err); + SAFE_FREE(err_name); + return err; + } + + /* Check compatibility between audio codec and file format */ + if (video_codec >= MM_VIDEO_CODEC_INVALID && video_codec < MM_VIDEO_CODEC_NUM && + file_format >= MM_FILE_FORMAT_INVALID && file_format < MM_FILE_FORMAT_NUM) { + if (videocodec_fileformat_compatibility_table[video_codec][file_format] == 0) { + _mmcam_dbg_err("Video codec[%d] and file format[%d] compatibility FAILED.", + video_codec, file_format); + return MM_ERROR_CAMCORDER_ENCODER_WRONG_TYPE; + } + + _mmcam_dbg_log("Video codec[%d] and file format[%d] compatibility SUCCESS.", + video_codec, file_format); + } else { + _mmcam_dbg_err("Video codec[%d] or file format[%d] is INVALID.", + video_codec, file_format); + return MM_ERROR_CAMCORDER_ENCODER_WRONG_TYPE; + } + + return MM_ERROR_NONE; +} + + +bool _mmcamcorder_set_display_rotation(MMHandleType handle, int display_rotate) +{ + 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")) { + 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); + return TRUE; + } else { + _mmcam_dbg_warn("videosink[%s] does not support DISPLAY_ROTATION.", 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; + int height = 0; + int set_width = 0; + 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; + + type_int_array *input_index = 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_VIDEOSRC_SRC].gst) { + _mmcam_dbg_err("Video src is NULL!"); + return FALSE; + } + + if (!sc->element[_MMCAMCORDER_VIDEOSRC_FILT].gst) { + _mmcam_dbg_err("Video filter is NULL!"); + return FALSE; + } + + mm_camcorder_get_attributes(handle, NULL, + 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, + CONFIGURE_CATEGORY_CTRL_CAMERA, + "InputIndex", + &input_index ); + if (input_index == NULL) { + _mmcam_dbg_err("Failed to get input_index"); + 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); + + /* 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 (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; + + 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); + } + } + } + + set_fps = sc->is_slow ? slow_fps : fps; + + MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_VIDEOSRC_FILT].gst, "caps", &caps); + if (caps) { + GstStructure *structure = NULL; + + structure = gst_caps_get_structure(caps, 0); + if (structure) { + int caps_width = 0; + int caps_height = 0; + int caps_fps = 0; + int caps_rotate = 0; + + gst_structure_get_int(structure, "width", &caps_width); + gst_structure_get_int(structure, "height", &caps_height); + 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) { + _mmcam_dbg_log("No need to replace caps."); + } else { + _mmcam_dbg_log("something is different. set new one..."); + do_set_caps = TRUE; + } + } else { + _mmcam_dbg_log("can not get structure of caps. set new one..."); + do_set_caps = TRUE; + } + + gst_caps_unref(caps); + caps = NULL; + } else { + _mmcam_dbg_log("No caps. set new one..."); + do_set_caps = TRUE; + } + + if (do_set_caps) { + 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, set_fps, 1, + "rotate", G_TYPE_INT, set_rotate, + NULL); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_FILT].gst, "caps", caps); + gst_caps_unref(caps); + 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); + } + + return TRUE; +} diff --git a/src/mm_camcorder_internal.c b/src/mm_camcorder_internal.c new file mode 100644 index 0000000..50528e9 --- /dev/null +++ b/src/mm_camcorder_internal.c @@ -0,0 +1,3449 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +========================================================================================*/ +#include <stdio.h> +#include <string.h> +#include <gst/gst.h> +#include <gst/gstutils.h> +#include <gst/gstpad.h> + +#include <mm_error.h> +#include "mm_camcorder_internal.h" +#include <mm_types.h> + +#include <gst/interfaces/colorbalance.h> +#include <gst/interfaces/cameracontrol.h> +#include <asm/types.h> + +#include <mm_session.h> +#include <mm_session_private.h> +#include <audio-session-manager.h> + +/*--------------------------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------------------*/ + +//#define _MMCAM_USING_CAPTUREMODE +#define __MMCAMCORDER_CMD_ITERATE_MAX 3 + +/*--------------------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------------------*/ +/* STATIC INTERNAL FUNCTION */ +static gboolean __mmcamcorder_gstreamer_init(camera_conf * conf); + +static gboolean __mmcamcorder_handle_gst_error(MMHandleType handle, GstMessage *message, GError *error); +static gint __mmcamcorder_gst_handle_stream_error(MMHandleType handle, int code, GstMessage *message); +static gint __mmcamcorder_gst_handle_resource_error(MMHandleType handle, int code, GstMessage *message); +static gint __mmcamcorder_gst_handle_library_error(MMHandleType handle, int code, GstMessage *message); +static gint __mmcamcorder_gst_handle_core_error(MMHandleType handle, int code, GstMessage *message); +static gint __mmcamcorder_gst_handle_resource_warning(MMHandleType handle, GstMessage *message , GError *error); +static gboolean __mmcamcorder_handle_gst_warning(MMHandleType handle, GstMessage *message, GError *error); + +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); + +static gboolean __mmcamcorder_set_attr_to_camsensor_cb(gpointer data); + + +/*======================================================================================= +| FUNCTION DEFINITIONS | +=======================================================================================*/ +/*--------------------------------------------------------------------------------------- +| GLOBAL FUNCTION DEFINITIONS: | +---------------------------------------------------------------------------------------*/ + +/* Internal command functions {*/ +int _mmcamcorder_create(MMHandleType *handle, MMCamPreset *info) +{ + int ret = MM_ERROR_NONE; + int UseConfCtrl = 0; + int sessionType = MM_SESSION_TYPE_EXCLUSIVE; + 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; + char *err_attr_name = NULL; + char *ConfCtrlFile = NULL; + mmf_camcorder_t *hcamcorder = NULL; + ASM_resource_t mm_resource = ASM_RESOURCE_NONE; + + _mmcam_dbg_log("Entered"); + + mmf_return_val_if_fail( handle, MM_ERROR_CAMCORDER_INVALID_ARGUMENT ); + + /* Create mmf_camcorder_t handle and initialize every variable */ + hcamcorder = (mmf_camcorder_t *)malloc(sizeof(mmf_camcorder_t)); + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_LOW_MEMORY); + 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; + + /* thread - for g_mutex_new() */ + if (!g_thread_supported()) { + g_thread_init(NULL); + } + + (hcamcorder->mtsafe).lock = g_mutex_new(); + (hcamcorder->mtsafe).cond = g_cond_new(); + + (hcamcorder->mtsafe).cmd_lock = g_mutex_new(); + (hcamcorder->mtsafe).state_lock = g_mutex_new(); + (hcamcorder->mtsafe).gst_state_lock = g_mutex_new(); + (hcamcorder->mtsafe).message_cb_lock = g_mutex_new(); + (hcamcorder->mtsafe).vcapture_cb_lock = g_mutex_new(); + (hcamcorder->mtsafe).vstream_cb_lock = g_mutex_new(); + (hcamcorder->mtsafe).astream_cb_lock = g_mutex_new(); + + pthread_mutex_init(&(hcamcorder->sound_lock), NULL); + pthread_cond_init(&(hcamcorder->sound_cond), NULL); + + /* Sound mutex/cond init */ + pthread_mutex_init(&(hcamcorder->snd_info.open_mutex), NULL); + pthread_cond_init(&(hcamcorder->snd_info.open_cond), NULL); + + if (info->videodev_type < MM_VIDEO_DEVICE_NONE || + info->videodev_type >= MM_VIDEO_DEVICE_NUM) { + _mmcam_dbg_err("_mmcamcorder_create::video device type is out of range."); + ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + goto _ERR_DEFAULT_VALUE_INIT; + } + + /* 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; + } + } + 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, + (void*)hcamcorder, mm_resource, &errorcode)) { + _mmcam_dbg_err("ASM_register_sound() failed[%x]", errorcode); + ret = MM_ERROR_POLICY_INTERNAL; + goto _ERR_DEFAULT_VALUE_INIT; + } + hcamcorder->asm_handle = asm_handle; + } + + /* Get Camera Configure information from Camcorder INI file */ + __ta__( " _mmcamcorder_conf_get_info main", + _mmcamcorder_conf_get_info(CONFIGURE_TYPE_MAIN, CONFIGURE_MAIN_FILE, &hcamcorder->conf_main); + ); + + if (!(hcamcorder->conf_main)) { + _mmcam_dbg_err( "Failed to get configure(main) info." ); + + ret = MM_ERROR_CAMCORDER_CREATE_CONFIGURE; + goto _ERR_AUDIO_BLOCKED; + } + + __ta__(" _mmcamcorder_alloc_attribute", + hcamcorder->attributes= _mmcamcorder_alloc_attribute((MMHandleType)hcamcorder, info); + ); + if (!(hcamcorder->attributes)) { + _mmcam_dbg_err("_mmcamcorder_create::alloc attribute error."); + + ret = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto _ERR_AUDIO_BLOCKED; + } + + if (info->videodev_type != MM_VIDEO_DEVICE_NONE) { + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, + "UseConfCtrl", &UseConfCtrl); + + if (UseConfCtrl) { + _mmcam_dbg_log( "Enable Configure Control system." ); +#if 1 + switch (info->videodev_type) { + case MM_VIDEO_DEVICE_CAMERA0: + _mmcamcorder_conf_get_value_string(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, + "ConfCtrlFile0", &ConfCtrlFile); + break; + case MM_VIDEO_DEVICE_CAMERA1: + _mmcamcorder_conf_get_value_string(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, + "ConfCtrlFile1", &ConfCtrlFile); + break; + default: + _mmcam_dbg_err( "Not supported camera type." ); + ret = MM_ERROR_CAMCORDER_NOT_SUPPORTED; + goto _ERR_ALLOC_ATTRIBUTE; + } + + _mmcam_dbg_log("videodev_type : [%d], ConfCtrlPath : [%s]", info->videodev_type, ConfCtrlFile); + + __ta__( " _mmcamcorder_conf_get_info ctrl", + _mmcamcorder_conf_get_info(CONFIGURE_TYPE_CTRL, ConfCtrlFile, &hcamcorder->conf_ctrl); + ); +/* + _mmcamcorder_conf_print_info(&hcamcorder->conf_main); + _mmcamcorder_conf_print_info(&hcamcorder->conf_ctrl); +*/ +#else + _mmcamcorder_conf_query_info(CONFIGURE_TYPE_CTRL, info->videodev_type, &hcamcorder->conf_ctrl); +#endif + if (!(hcamcorder->conf_ctrl)) { + _mmcam_dbg_err( "Failed to get configure(control) info." ); + ret = MM_ERROR_CAMCORDER_CREATE_CONFIGURE; + goto _ERR_ALLOC_ATTRIBUTE; + } + + __ta__( " _mmcamcorder_init_convert_table", + ret = _mmcamcorder_init_convert_table((MMHandleType)hcamcorder); + ); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_warn("converting table initialize error!!"); + } + + __ta__( " _mmcamcorder_init_attr_from_configure", + ret = _mmcamcorder_init_attr_from_configure((MMHandleType)hcamcorder); + ); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_warn("converting table initialize error!!"); + } + } + else + { + _mmcam_dbg_log( "Disable Configure Control system." ); + hcamcorder->conf_ctrl = NULL; + } + } + + __ta__( " __mmcamcorder_gstreamer_init", + ret = __mmcamcorder_gstreamer_init(hcamcorder->conf_main); + ); + if (!ret) { + _mmcam_dbg_err( "Failed to initialize gstreamer!!" ); + ret = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + 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); + ); + + /* Disable attributes in each model */ + __ta__( " _mmcamcorder_set_disabled_attributes", + _mmcamcorder_set_disabled_attributes((MMHandleType)hcamcorder); + ); + + /* Determine state change as sync or async */ + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_GENERAL, + "SyncStateChange", + &hcamcorder->sync_state_change ); + if (!(hcamcorder->sync_state_change)) { + _mmcamcorder_create_command_loop((MMHandleType)hcamcorder); + } + + /* Set initial state */ + _mmcamcorder_set_state((MMHandleType)hcamcorder, MM_CAMCORDER_STATE_NULL); + _mmcam_dbg_log("_mmcamcorder_set_state"); + + *handle = (MMHandleType)hcamcorder; + + return MM_ERROR_NONE; + +_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; + } + + 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); + } + } + } + +_ERR_DEFAULT_VALUE_INIT: + g_mutex_free ((hcamcorder->mtsafe).lock); + g_cond_free ((hcamcorder->mtsafe).cond); + g_mutex_free ((hcamcorder->mtsafe).cmd_lock); + g_mutex_free ((hcamcorder->mtsafe).state_lock); + g_mutex_free ((hcamcorder->mtsafe).gst_state_lock); + + if (hcamcorder->conf_ctrl) { + _mmcamcorder_conf_release_info( &hcamcorder->conf_ctrl ); + } + + if (hcamcorder->conf_main) { + _mmcamcorder_conf_release_info( &hcamcorder->conf_main ); + } + + return ret; +} + + +int _mmcamcorder_destroy(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + 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(""); + + if (!hcamcorder) { + _mmcam_dbg_err("Not initialized"); + ret = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + ret = MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + state = _mmcamcorder_get_state(handle); + if (state != state_FROM) { + _mmcam_dbg_err("Wrong state(%d)", state); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + /* Set async state */ + ret = _mmcamcorder_set_async_state(handle, state_TO); + if (ret < 0) { + _mmcam_dbg_err("Can't set async state"); + 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) { + __ta__(" _mmcamcorder_destroy_pipeline", + _mmcamcorder_destroy_pipeline(handle, hcamcorder->type); + ); + } + + _mmcamcorder_dealloc_subcontext(hcamcorder->sub_context); + hcamcorder->sub_context = NULL; + } + + /* Remove idle function which is not called yet */ + if (hcamcorder->setting_event_id) { + _mmcam_dbg_log("Remove remaining idle function"); + g_source_remove(hcamcorder->setting_event_id); + hcamcorder->setting_event_id = 0; + } + + /* Remove attributes */ + if (hcamcorder->attributes) { + _mmcamcorder_dealloc_attribute(hcamcorder->attributes); + hcamcorder->attributes = 0; + } + + /* Remove exif info */ + if (hcamcorder->exif_info) { + mm_exif_destory_exif_info(hcamcorder->exif_info); + hcamcorder->exif_info=NULL; + + } + + /* Remove command loop when async state change mode */ + if (!hcamcorder->sync_state_change) { + _mmcamcorder_destroy_command_loop(handle); + } + + /* Release configure info */ + if (hcamcorder->conf_ctrl) { + _mmcamcorder_conf_release_info( &hcamcorder->conf_ctrl ); + } + if (hcamcorder->conf_main) { + _mmcamcorder_conf_release_info( &hcamcorder->conf_main ); + } + + /* Remove messages which are not called yet */ + _mmcamcroder_remove_message_all(handle); + + /* Unregister ASM */ + if (MM_ERROR_NONE != _mm_session_util_read_type(-1, &sessionType)) { + _mmcam_dbg_err("_mm_session_util_read_type Fail"); + } + 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); + } + } + + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + + /* Release lock, cond */ + if ((hcamcorder->mtsafe).lock) { + g_mutex_free ((hcamcorder->mtsafe).lock); + (hcamcorder->mtsafe).lock = NULL; + } + if ((hcamcorder->mtsafe).cond) { + g_cond_free ((hcamcorder->mtsafe).cond); + (hcamcorder->mtsafe).cond = NULL; + } + if ((hcamcorder->mtsafe).cmd_lock) { + g_mutex_free ((hcamcorder->mtsafe).cmd_lock); + (hcamcorder->mtsafe).cmd_lock = NULL; + } + if ((hcamcorder->mtsafe).state_lock) { + g_mutex_free ((hcamcorder->mtsafe).state_lock); + (hcamcorder->mtsafe).state_lock = NULL; + } + if ((hcamcorder->mtsafe).gst_state_lock) { + g_mutex_free ((hcamcorder->mtsafe).gst_state_lock); + (hcamcorder->mtsafe).gst_state_lock = NULL; + } + if ((hcamcorder->mtsafe).message_cb_lock) { + g_mutex_free ((hcamcorder->mtsafe).message_cb_lock); + (hcamcorder->mtsafe).message_cb_lock = NULL; + } + if ((hcamcorder->mtsafe).vcapture_cb_lock) { + g_mutex_free ((hcamcorder->mtsafe).vcapture_cb_lock); + (hcamcorder->mtsafe).vcapture_cb_lock = NULL; + } + if ((hcamcorder->mtsafe).vstream_cb_lock) { + g_mutex_free ((hcamcorder->mtsafe).vstream_cb_lock); + (hcamcorder->mtsafe).vstream_cb_lock = NULL; + } + if ((hcamcorder->mtsafe).astream_cb_lock) { + g_mutex_free ((hcamcorder->mtsafe).astream_cb_lock); + (hcamcorder->mtsafe).astream_cb_lock = NULL; + } + + pthread_mutex_destroy(&(hcamcorder->sound_lock)); + pthread_cond_destroy(&(hcamcorder->sound_cond)); + pthread_mutex_destroy(&(hcamcorder->snd_info.open_mutex)); + pthread_cond_destroy(&(hcamcorder->snd_info.open_cond)); + + /* Release handle */ + memset(hcamcorder, 0x00, sizeof(mmf_camcorder_t)); + free(hcamcorder); + + return MM_ERROR_NONE; + +_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); + } + + return ret; +} + + +int _mmcamcorder_realize(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + 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 errorcode = MM_ERROR_NONE; + int display_surface_type = MM_DISPLAY_SURFACE_X; + char *videosink_element_type = NULL; + char *videosink_name = NULL; + _MMCamcorderMsgItem msg; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + _mmcam_dbg_log(""); + + if (!hcamcorder) { + _mmcam_dbg_err("Not initialized"); + ret = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + return ret; + } + + /* Check quick-device-close for emergency */ + if (hcamcorder->quick_device_close) { + _mmcam_dbg_err("_mmcamcorder_realize can't be called!!!!"); + ret = MM_ERROR_CAMCORDER_DEVICE; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + ret = MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + state = _mmcamcorder_get_state(handle); + if (state != state_FROM) { + _mmcam_dbg_err("Wrong state(%d)", state); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + /* Set async state */ + ret = _mmcamcorder_set_async_state(handle, state_TO); + if (ret < 0) { + _mmcam_dbg_err("Can't set async state"); + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + /* 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 */ + 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 ((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: + default: + mm_resource = ASM_RESOURCE_CAMERA | ASM_RESOURCE_VIDEO_OVERLAY; + break; + } + + if (!ASM_set_sound_state(hcamcorder->asm_handle, asm_session_type, + ASM_STATE_PLAYING, mm_resource, &errorcode)) { + debug_error("Set state to playing failed 0x%X\n", errorcode); + ret = MM_ERROR_POLICY_BLOCKED; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + } + + /* alloc sub context */ + hcamcorder->sub_context = _mmcamcorder_alloc_subcontext(hcamcorder->type); + if(!hcamcorder->sub_context) { + ret = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto _ERR_CAMCORDER_CMD; + } + + /* Set basic configure information */ + mm_camcorder_get_attributes(handle, NULL, MMCAM_DISPLAY_SURFACE, &display_surface_type, NULL); + switch (display_surface_type) { + case MM_DISPLAY_SURFACE_X: + videosink_element_type = strdup("VideosinkElementX"); + break; + case MM_DISPLAY_SURFACE_EVAS: + videosink_element_type = strdup("VideosinkElementEvas"); + break; + case MM_DISPLAY_SURFACE_GL: + videosink_element_type = strdup("VideosinkElementGL"); + break; + case MM_DISPLAY_SURFACE_NULL: + videosink_element_type = strdup("VideosinkElementNull"); + break; + default: + 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 ); + + if (videosink_element_type) { + free(videosink_element_type); + videosink_element_type = NULL; + } + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_ctrl, + CONFIGURE_CATEGORY_CTRL_CAPTURE, + "SensorEncodedCapture", + &(hcamcorder->sub_context->SensorEncodedCapture)); + _mmcam_dbg_log("Support sensor encoded capture : %d", hcamcorder->sub_context->SensorEncodedCapture); + + /* create pipeline */ + __ta__(" _mmcamcorder_create_pipeline", + ret = _mmcamcorder_create_pipeline(handle, hcamcorder->type); + ); + if(ret<0) { + _mmcamcorder_dealloc_subcontext(hcamcorder->sub_context); + hcamcorder->sub_context = NULL; + goto _ERR_CAMCORDER_CMD; + } + + /* set command function */ + ret = _mmcamcorder_set_functions(handle, hcamcorder->type); + + if(ret<0) { + _mmcamcorder_destroy_pipeline(handle, hcamcorder->type); + _mmcamcorder_dealloc_subcontext(hcamcorder->sub_context); + hcamcorder->sub_context = NULL; + goto _ERR_CAMCORDER_CMD; + } + + _mmcamcorder_set_state(handle, state_TO); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + + return MM_ERROR_NONE; + +_ERR_CAMCORDER_CMD: + /* set async state and (set async cancel or set state) are pair. */ + _mmcamcorder_set_async_cancel(handle); + +_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); + + 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); + + return ret; +} + + +int _mmcamcorder_unrealize(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + int state = MM_CAMCORDER_STATE_NONE; + 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(""); + + if (!hcamcorder) { + _mmcam_dbg_err("Not initialized"); + ret = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + return ret; + } + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + ret = MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + state = _mmcamcorder_get_state(handle); + if (state != state_FROM) { + _mmcam_dbg_err("Wrong state(%d)", state); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + /* set async state */ + ret = _mmcamcorder_set_async_state(handle, state_TO); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Can't set async state"); + 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 */ + _mmcamcorder_destroy_pipeline(handle, hcamcorder->type); + /* Deallocate SubContext */ + _mmcamcorder_dealloc_subcontext(hcamcorder->sub_context); + hcamcorder->sub_context = NULL; + } + + /* Deinitialize main context member */ + + 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; + } + + /* 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); + } + } + + _mmcamcorder_set_state(handle, state_TO); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + + return MM_ERROR_NONE; + +_ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + +_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); + + return ret; +} + +int _mmcamcorder_start(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + 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); + + _mmcam_dbg_log(""); + + if (!hcamcorder) { + _mmcam_dbg_err("Not initialized"); + ret = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + return ret; + } + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + /* check quick-device-close for emergency */ + if (hcamcorder->quick_device_close) { + _mmcam_dbg_err("_mmcamcorder_start can't be called!!!!"); + ret = MM_ERROR_CAMCORDER_DEVICE; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + ret = MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + state = _mmcamcorder_get_state(handle); + if (state != state_FROM) { + _mmcam_dbg_err("Wrong state(%d)", state); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + /* set async state */ + ret = _mmcamcorder_set_async_state(handle, state_TO); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Can't set async state"); + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + ret = hcamcorder->command((MMHandleType)hcamcorder, _MMCamcorder_CMD_PREVIEW_START); + if (ret != MM_ERROR_NONE) { + goto _ERR_CAMCORDER_CMD; + } + + _mmcamcorder_set_state(handle, state_TO); + + if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { + _mmcamcorder_set_attribute_to_camsensor(handle); + } + + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + + return MM_ERROR_NONE; + +_ERR_CAMCORDER_CMD: + /* set async state and (set async cancel or set state) are pair. */ + _mmcamcorder_set_async_cancel(handle); + +_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); + + 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); + + return ret; +} + +int _mmcamcorder_stop(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + int state = MM_CAMCORDER_STATE_NONE; + 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(""); + + if (!hcamcorder) { + _mmcam_dbg_err("Not initialized"); + ret = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + return ret; + } + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + ret = MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + state = _mmcamcorder_get_state(handle); + if (state != state_FROM) { + _mmcam_dbg_err("Wrong state(%d)", state); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + /* set async state */ + ret = _mmcamcorder_set_async_state(handle, state_TO); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Can't set async state"); + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + ret = hcamcorder->command((MMHandleType)hcamcorder, _MMCamcorder_CMD_PREVIEW_STOP); + if (ret != MM_ERROR_NONE) { + goto _ERR_CAMCORDER_CMD; + } + + /* KPI : frame rate */ + frame_rate=_mmcamcorder_video_average_framerate(handle); + __ta__(__tafmt__("MM_CAM_006:: Frame per sec : %d", frame_rate), ;); + + _mmcamcorder_set_state(handle, state_TO); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + + return MM_ERROR_NONE; + +_ERR_CAMCORDER_CMD: + /* set async state and (set async cancel or set state) are pair. */ + _mmcamcorder_set_async_cancel(handle); + +_ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + +_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); + + return ret; +} + + +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_TO = MM_CAMCORDER_STATE_CAPTURING; + char *err_name = NULL; + + _MMCamcorderMsgItem msg; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + _mmcam_dbg_log(""); + + if (!hcamcorder) { + _mmcam_dbg_err("Not initialized"); + ret = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + return ret; + } + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + ret = MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + state = _mmcamcorder_get_state(handle); + if (state != state_FROM) { + _mmcam_dbg_err("Wrong state(%d)", state); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + /* set async state */ + ret = _mmcamcorder_set_async_state(handle, state_TO); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Can't set async state"); + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + ret = hcamcorder->command((MMHandleType)hcamcorder, _MMCamcorder_CMD_CAPTURE); + if (ret != MM_ERROR_NONE) { + goto _ERR_CAMCORDER_CMD; + } + + _mmcamcorder_set_state(handle, state_TO); + + /* Init break continuous shot attr */ + mm_camcorder_set_attributes(handle, &err_name, "capture-break-cont-shot", 0, NULL); + + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + + return MM_ERROR_NONE; + +_ERR_CAMCORDER_CMD: + /* set async state and (set async cancel or set state) are pair. */ + _mmcamcorder_set_async_cancel(handle); + +_ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + +_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); + + return ret; +} + +int _mmcamcorder_capture_stop(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + 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(""); + + if (!hcamcorder) { + _mmcam_dbg_err("Not initialized"); + ret = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + return ret; + } + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + ret = MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + state = _mmcamcorder_get_state(handle); + if (state != state_FROM) { + _mmcam_dbg_err("Wrong state(%d)", state); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + /* set async state */ + ret = _mmcamcorder_set_async_state(handle, state_TO); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Can't set async state"); + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + ret = hcamcorder->command((MMHandleType)hcamcorder, _MMCamcorder_CMD_PREVIEW_START); + if (ret != MM_ERROR_NONE) { + goto _ERR_CAMCORDER_CMD; + } + + _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); + + return MM_ERROR_NONE; + +_ERR_CAMCORDER_CMD: + /* set async state and (set async cancel or set state) are pair. */ + _mmcamcorder_set_async_cancel(handle); + +_ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + +_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); + + return ret; +} + +int _mmcamcorder_record(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + int state = MM_CAMCORDER_STATE_NONE; + int state_FROM1 = MM_CAMCORDER_STATE_PREPARE; + int state_FROM2 = MM_CAMCORDER_STATE_PAUSED; + int state_TO = MM_CAMCORDER_STATE_RECORDING; + _MMCamcorderMsgItem msg; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + _mmcam_dbg_log(""); + + if (!hcamcorder) { + _mmcam_dbg_err("Not initialized"); + ret = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + return ret; + } + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + ret = MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + state = _mmcamcorder_get_state(handle); + if (state != state_FROM1 && state != state_FROM2) { + _mmcam_dbg_err("Wrong state(%d)", state); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + /* set async state */ + ret = _mmcamcorder_set_async_state(handle, state_TO); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Can't set async state"); + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + ret = hcamcorder->command((MMHandleType)hcamcorder, _MMCamcorder_CMD_RECORD); + if (ret != MM_ERROR_NONE) { + goto _ERR_CAMCORDER_CMD; + } + + _mmcamcorder_set_state(handle, state_TO); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + + return MM_ERROR_NONE; + +_ERR_CAMCORDER_CMD: + /* set async state and (set async cancel or set state) are pair. */ + _mmcamcorder_set_async_cancel(handle); + +_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); + + 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); + + return ret; +} + + +int _mmcamcorder_pause(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + 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(""); + + if (!hcamcorder) { + _mmcam_dbg_err("Not initialized"); + ret = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + return ret; + } + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + ret = MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + state = _mmcamcorder_get_state(handle); + if (state != state_FROM) { + _mmcam_dbg_err("Wrong state(%d)", state); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + /* set async state */ + ret = _mmcamcorder_set_async_state(handle, state_TO); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Can't set async state"); + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + ret = hcamcorder->command((MMHandleType)hcamcorder, _MMCamcorder_CMD_PAUSE); + if (ret != MM_ERROR_NONE) { + goto _ERR_CAMCORDER_CMD; + } + + _mmcamcorder_set_state(handle, state_TO); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + + return MM_ERROR_NONE; + +_ERR_CAMCORDER_CMD: + /* set async state and (set async cancel or set state) are pair. */ + _mmcamcorder_set_async_cancel(handle); + +_ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + +_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); + + return ret; +} + + +int _mmcamcorder_commit(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + int state = MM_CAMCORDER_STATE_NONE; + 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(""); + + if (!hcamcorder) { + _mmcam_dbg_err("Not initialized"); + ret = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + return ret; + } + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + ret = MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + state = _mmcamcorder_get_state(handle); + if (state != state_FROM1 && state != state_FROM2) { + _mmcam_dbg_err("Wrong state(%d)", state); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + /* set async state */ + ret = _mmcamcorder_set_async_state(handle, state_TO); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Can't set async state"); + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + ret = hcamcorder->command((MMHandleType)hcamcorder, _MMCamcorder_CMD_COMMIT); + if (ret != MM_ERROR_NONE) { + goto _ERR_CAMCORDER_CMD; + } + + _mmcamcorder_set_state(handle,state_TO); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + + return MM_ERROR_NONE; + +_ERR_CAMCORDER_CMD: + /* set async state and (set async cancel or set state) are pair. */ + _mmcamcorder_set_async_cancel(handle); + +_ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + +_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); + + return ret; +} + + +int _mmcamcorder_cancel(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + int state = MM_CAMCORDER_STATE_NONE; + 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(""); + + if (!hcamcorder) { + _mmcam_dbg_err("Not initialized"); + ret = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + return ret; + } + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + ret = MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + goto _ERR_CAMCORDER_CMD_PRECON; + } + + state = _mmcamcorder_get_state(handle); + if (state != state_FROM1 && state != state_FROM2) { + _mmcam_dbg_err("Wrong state(%d)", state); + ret = MM_ERROR_CAMCORDER_INVALID_STATE; + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + /* set async state */ + ret = _mmcamcorder_set_async_state(handle, state_TO); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Can't set async state"); + goto _ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK; + } + + ret = hcamcorder->command((MMHandleType)hcamcorder, _MMCamcorder_CMD_CANCEL); + if (ret != MM_ERROR_NONE) { + goto _ERR_CAMCORDER_CMD; + } + + _mmcamcorder_set_state(handle, state_TO); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + + return MM_ERROR_NONE; + +_ERR_CAMCORDER_CMD: + /* set async state and (set async cancel or set state) are pair. */ + _mmcamcorder_set_async_cancel(handle); + +_ERR_CAMCORDER_CMD_PRECON_AFTER_LOCK: + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + +_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); + + return ret; +} +/* } Internal command functions */ + + +int _mmcamcorder_commit_async_end(MMHandleType handle) +{ + _mmcam_dbg_log(""); + + _mmcam_dbg_warn("_mmcamcorder_commit_async_end : MM_CAMCORDER_STATE_PREPARE"); + _mmcamcorder_set_state(handle, MM_CAMCORDER_STATE_PREPARE); + + return MM_ERROR_NONE; +} + + +int _mmcamcorder_set_message_callback(MMHandleType handle, MMMessageCallback callback, void *user_data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + _mmcam_dbg_log("%p", hcamcorder); + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + if (callback == NULL) { + _mmcam_dbg_warn("Message Callback is disabled, because application sets it to NULL"); + } + + if (!_MMCAMCORDER_TRYLOCK_MESSAGE_CALLBACK(hcamcorder)) { + _mmcam_dbg_warn("Application's message callback is running now"); + return MM_ERROR_CAMCORDER_INVALID_CONDITION; + } + + /* set message callback to message handle */ + hcamcorder->msg_cb = callback; + hcamcorder->msg_cb_param = user_data; + + _MMCAMCORDER_UNLOCK_MESSAGE_CALLBACK(hcamcorder); + + return MM_ERROR_NONE; +} + + +int _mmcamcorder_set_video_stream_callback(MMHandleType handle, mm_camcorder_video_stream_callback callback, void *user_data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + _mmcam_dbg_log(""); + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + if (callback == NULL) { + _mmcam_dbg_warn("Video Stream Callback is disabled, because application sets it to NULL"); + } + + if (!_MMCAMCORDER_TRYLOCK_VSTREAM_CALLBACK(hcamcorder)) { + _mmcam_dbg_warn("Application's video stream callback is running now"); + return MM_ERROR_CAMCORDER_INVALID_CONDITION; + } + + hcamcorder->vstream_cb = callback; + hcamcorder->vstream_cb_param = user_data; + + _MMCAMCORDER_UNLOCK_VSTREAM_CALLBACK(hcamcorder); + + return MM_ERROR_NONE; +} + + +int _mmcamcorder_set_audio_stream_callback(MMHandleType handle, mm_camcorder_audio_stream_callback callback, void *user_data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + _mmcam_dbg_log(""); + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + if (callback == NULL) { + _mmcam_dbg_warn("Audio Stream Callback is disabled, because application sets it to NULL"); + } + + if (!_MMCAMCORDER_TRYLOCK_ASTREAM_CALLBACK(hcamcorder)) { + _mmcam_dbg_warn("Application's audio stream callback is running now"); + return MM_ERROR_CAMCORDER_INVALID_CONDITION; + } + + hcamcorder->astream_cb = callback; + hcamcorder->astream_cb_param = user_data; + + _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder); + + return MM_ERROR_NONE; +} + + +int _mmcamcorder_set_video_capture_callback(MMHandleType handle, mm_camcorder_video_capture_callback callback, void *user_data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + _mmcam_dbg_log(""); + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + if (callback == NULL) { + _mmcam_dbg_warn("Video Capture Callback is disabled, because application sets it to NULLL"); + } + + if (!_MMCAMCORDER_TRYLOCK_VCAPTURE_CALLBACK(hcamcorder)) { + _mmcam_dbg_warn("Application's video capture callback is running now"); + return MM_ERROR_CAMCORDER_INVALID_CONDITION; + } + + hcamcorder->vcapture_cb = callback; + hcamcorder->vcapture_cb_param = user_data; + + _MMCAMCORDER_UNLOCK_VCAPTURE_CALLBACK(hcamcorder); + + return MM_ERROR_NONE; +} + +int _mmcamcorder_get_current_state(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + _mmcam_dbg_log(""); + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + return _mmcamcorder_get_state(handle); +} + +int _mmcamcorder_init_focusing(MMHandleType handle) +{ + int ret = 0; + 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; + mmf_camcorder_t *hcamcorder = NULL; + _MMCamcorderSubContext *sc = NULL; + mmf_attrs_t *attr = NULL; + GstCameraControl *control = NULL; + + _mmcam_dbg_log(""); + + hcamcorder = MMF_CAMCORDER(handle); + mmf_return_val_if_fail(handle, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + return MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + } + + state = _mmcamcorder_get_state(handle); + + if (state == MM_CAMCORDER_STATE_CAPTURING || + state < MM_CAMCORDER_STATE_PREPARE) { + _mmcam_dbg_err( "Not proper state. state[%d]", state ); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + return MM_ERROR_CAMCORDER_INVALID_STATE; + } + + if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { + _mmcam_dbg_log("Can't cast Video source into camera control."); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + return MM_ERROR_NONE; + } + control = GST_CAMERA_CONTROL (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); + + ret = gst_camera_control_stop_auto_focus(control); + if (!ret) { + _mmcam_dbg_err("Auto focusing stop fail."); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + return MM_ERROR_CAMCORDER_DEVICE_IO; + } + + /* Initialize lens position */ + attr = (mmf_attrs_t *)MMF_CAMCORDER_ATTRS(handle); + mm_camcorder_get_attributes(handle, NULL, + 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); + + ret = gst_camera_control_set_focus(control, sensor_focus_mode, sensor_af_range); + + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + + if (ret) { + _mmcam_dbg_log("Lens init success."); + return MM_ERROR_NONE; + } else { + _mmcam_dbg_err("Lens init fail."); + return MM_ERROR_CAMCORDER_DEVICE_IO; + } +} + +int _mmcamcorder_adjust_focus(MMHandleType handle, int direction) +{ + int state; + int focus_mode = MM_CAMCORDER_FOCUS_MODE_NONE; + int ret = MM_ERROR_UNKNOWN; + char *err_attr_name = NULL; + + mmf_return_val_if_fail(handle, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(direction, MM_ERROR_CAMCORDER_INVALID_ARGUMENT); + + _mmcam_dbg_log(""); + + state = _mmcamcorder_get_state(handle); + if (state == MM_CAMCORDER_STATE_CAPTURING || + state < MM_CAMCORDER_STATE_PREPARE) { + _mmcam_dbg_err("Not proper state. state[%d]", state); + return MM_ERROR_CAMCORDER_INVALID_STATE; + } + + /* TODO : call a auto or manual focus function */ + ret = mm_camcorder_get_attributes(handle, &err_attr_name, + MMCAM_CAMERA_FOCUS_MODE, &focus_mode, + NULL); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_warn("Get focus-mode fail. (%s:%x)", err_attr_name, ret); + SAFE_FREE (err_attr_name); + return ret; + } + + if (focus_mode == MM_CAMCORDER_FOCUS_MODE_MANUAL) { + return _mmcamcorder_adjust_manual_focus(handle, direction); + } else if (focus_mode == MM_CAMCORDER_FOCUS_MODE_AUTO || + focus_mode == MM_CAMCORDER_FOCUS_MODE_TOUCH_AUTO || + focus_mode == MM_CAMCORDER_FOCUS_MODE_CONTINUOUS) { + return _mmcamcorder_adjust_auto_focus(handle); + } else { + _mmcam_dbg_err("It doesn't adjust focus. Focusing mode(%d)", focus_mode); + return MM_ERROR_CAMCORDER_NOT_SUPPORTED; + } +} + +int _mmcamcorder_adjust_manual_focus(MMHandleType handle, int direction) +{ + int max_level = 0; + int min_level = 0; + int cur_level = 0; + int focus_level = 0; + float unit_level = 0; + GstCameraControl *control = NULL; + _MMCamcorderSubContext *sc = NULL; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + _mmcam_dbg_log(""); + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(_MMFCAMCORDER_FOCUS_TOTAL_LEVEL != 1, MM_ERROR_CAMCORDER_NOT_SUPPORTED); + mmf_return_val_if_fail((direction >= MM_CAMCORDER_MF_LENS_DIR_FORWARD) && + (direction <= MM_CAMCORDER_MF_LENS_DIR_BACKWARD), + MM_ERROR_CAMCORDER_INVALID_ARGUMENT ); + + sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { + _mmcam_dbg_log("Can't cast Video source into camera control."); + return MM_ERROR_NONE; + } + control = GST_CAMERA_CONTROL (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); + + /* TODO : get max, min level */ + if (max_level - min_level + 1 < _MMFCAMCORDER_FOCUS_TOTAL_LEVEL) { + _mmcam_dbg_warn("Total level of manual focus of MMF is greater than that of the camera driver."); + } + + unit_level = ((float)max_level - (float)min_level)/(float)(_MMFCAMCORDER_FOCUS_TOTAL_LEVEL - 1); + + if (!gst_camera_control_get_focus_level(control, &cur_level)) { + _mmcam_dbg_err("Can't get current level of manual focus."); + return MM_ERROR_CAMCORDER_DEVICE_IO; + } + + //TODO : adjust unit level value + if (direction == MM_CAMCORDER_MF_LENS_DIR_FORWARD) { + focus_level = cur_level + unit_level; + } else if (direction == MM_CAMCORDER_MF_LENS_DIR_BACKWARD) { + focus_level = cur_level - unit_level; + } + + if (focus_level > max_level) { + focus_level = max_level; + } else if (focus_level < min_level) { + focus_level = min_level; + } + + if (!gst_camera_control_set_focus_level(control, focus_level)) { + _mmcam_dbg_err("Manual focusing fail."); + return MM_ERROR_CAMCORDER_DEVICE_IO; + } + + return MM_ERROR_NONE; +} + + +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; + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(handle, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log(""); + + sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + + if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { + _mmcam_dbg_log("Can't cast Video source into camera control."); + return MM_ERROR_NONE; + } + control = GST_CAMERA_CONTROL (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); + + /* 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 { + _mmcam_dbg_err("Auto focusing start fail."); + return MM_ERROR_CAMCORDER_DEVICE_IO; + } +} + +int _mmcamcorder_stop_focusing(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + int ret, state; + GstCameraControl *control = NULL; + + mmf_return_val_if_fail(handle, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log(""); + + sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + + if (!_MMCAMCORDER_TRYLOCK_CMD(hcamcorder)) { + _mmcam_dbg_err("Another command is running."); + return MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + } + + state = _mmcamcorder_get_state(handle); + if (state == MM_CAMCORDER_STATE_CAPTURING || + state < MM_CAMCORDER_STATE_PREPARE) { + _mmcam_dbg_err( "Not proper state. state[%d]", state ); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + return MM_ERROR_CAMCORDER_INVALID_STATE; + } + + if (!GST_IS_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst)) { + _mmcam_dbg_log("Can't cast Video source into camera control."); + _MMCAMCORDER_UNLOCK_CMD(hcamcorder); + return MM_ERROR_NONE; + } + 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); + + if (ret) { + _mmcam_dbg_log("Auto focusing stop success."); + return MM_ERROR_NONE; + } else { + _mmcam_dbg_err("Auto focusing stop fail."); + return MM_ERROR_CAMCORDER_DEVICE_IO; + } +} + + +/*----------------------------------------------- +| CAMCORDER INTERNAL LOCAL | +-----------------------------------------------*/ +static gboolean +__mmcamcorder_gstreamer_init(camera_conf * conf) +{ + static const int max_argc = 10; + int i = 0; + int cnt_str = 0; + gint *argc = NULL; + gchar **argv = NULL; + GError *err = NULL; + gboolean ret = FALSE; + type_string_array *GSTInitOption = NULL; + + mmf_return_val_if_fail(conf, FALSE); + + _mmcam_dbg_log(""); + + /* alloc */ + argc = malloc(sizeof(int)); + argv = malloc(sizeof(gchar *) * max_argc); + + if (!argc || !argv) { + goto ERROR; + } + + memset(argv, 0, sizeof(gchar *) * max_argc); + + /* add initial */ + *argc = 1; + argv[0] = g_strdup("mmcamcorder"); + + /* add gst_param */ + _mmcamcorder_conf_get_value_string_array(conf, + CONFIGURE_CATEGORY_MAIN_GENERAL, + "GSTInitOption", + &GSTInitOption); + if (GSTInitOption != NULL && GSTInitOption->value) { + cnt_str = GSTInitOption->count; + for( ; *argc < max_argc && *argc <= cnt_str ; (*argc)++ ) + { + argv[*argc] = g_strdup(GSTInitOption->value[(*argc)-1]); + } + } + + _mmcam_dbg_log("initializing gstreamer with following parameter[argc:%d]", *argc); + + for (i = 0; i < *argc; i++) { + _mmcam_dbg_log("argv[%d] : %s", i, argv[i]); + } + + /* initializing gstreamer */ + __ta__(" gst_init_check", + ret = gst_init_check (argc, &argv, &err); + ); + + if (!ret) { + _mmcam_dbg_err("Could not initialize GStreamer: %s\n", + err ? err->message : "unknown error occurred"); + if (err) { + g_error_free (err); + } + } + + /* release */ + for (i = 0; i < *argc; i++) { + if (argv[i]) { + free(argv[i]); + argv[i] = NULL; + } + } + + if (argv) { + free(argv); + argv = NULL; + } + + if (argc) { + free(argc); + argc = NULL; + } + + return ret; + +ERROR: + _mmcam_dbg_err("failed to initialize gstreamer"); + + if (argv) { + free(argv); + argv = NULL; + } + + if (argc) { + free(argc); + argc = NULL; + } + + return FALSE; +} + + +int _mmcamcorder_get_state(MMHandleType handle) +{ + int state; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + mmf_return_val_if_fail(hcamcorder, -1); + + _MMCAMCORDER_LOCK_STATE(handle); + + state = hcamcorder->state; + _mmcam_dbg_log("state=%d",state); + + _MMCAMCORDER_UNLOCK_STATE(handle); + + return state; +} + + +void _mmcamcorder_set_state(MMHandleType handle, int state) +{ + int old_state; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderMsgItem msg; + + mmf_return_if_fail(hcamcorder); + + _mmcam_dbg_log(""); + + _MMCAMCORDER_LOCK_STATE(handle); + + old_state = hcamcorder->state; + if(old_state != state) { + hcamcorder->state = state; + hcamcorder->target_state = state; + + _mmcam_dbg_log("set state[%d] and send state-changed message", state); + + /* To discern who changes the state */ + switch (hcamcorder->state_change_by_system) { + case _MMCAMCORDER_STATE_CHANGE_BY_ASM: + msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED_BY_ASM; + msg.param.state.code = hcamcorder->asm_event_code; + break; + default: + msg.id = MM_MESSAGE_CAMCORDER_STATE_CHANGED; + msg.param.state.code = MM_ERROR_NONE; + break; + } + + msg.param.state.previous = old_state; + msg.param.state.current = state; + + _mmcam_dbg_log("_mmcamcroder_send_message : msg : %p, id:%x", &msg, msg.id); + _mmcamcroder_send_message(handle, &msg); + } + + _MMCAMCORDER_UNLOCK_STATE(handle); + + return; +} + + +int _mmcamcorder_get_async_state(MMHandleType handle) +{ + int state; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + _MMCAMCORDER_LOCK_STATE(handle); + state = hcamcorder->target_state; + + _MMCAMCORDER_UNLOCK_STATE(handle); + + return state; +} + +int _mmcamcorder_set_async_state(MMHandleType handle, int target_state) +{ + int error = MM_ERROR_NONE; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_INVALID_CONDITION); + + _mmcam_dbg_log(""); + + if (hcamcorder->sync_state_change) { + return error; + } + + _MMCAMCORDER_LOCK_STATE(handle); + + /* check changing state */ + if (hcamcorder->state != hcamcorder->target_state) { + _mmcam_dbg_warn("State is changing now."); + error = MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + goto _SET_ASYNC_END; + } + + /* check already set */ + if (hcamcorder->state == target_state) { + _mmcam_dbg_log("Target state already set."); + error = MM_ERROR_CAMCORDER_INVALID_STATE; + goto _SET_ASYNC_END; + } + + hcamcorder->target_state = target_state; + + _mmcam_dbg_log("Done"); + +_SET_ASYNC_END: + _MMCAMCORDER_UNLOCK_STATE(handle); + return error; +} + + +gboolean _mmcamcorder_set_async_cancel(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + mmf_return_val_if_fail(hcamcorder, FALSE); + + _mmcam_dbg_log(""); + + if (hcamcorder->sync_state_change) { + return TRUE; + } + + _MMCAMCORDER_LOCK_STATE(handle); + + if (hcamcorder->target_state != hcamcorder->state) { + hcamcorder->target_state = hcamcorder->state; + _mmcam_dbg_log("Async state change is canceled."); + _MMCAMCORDER_UNLOCK_STATE(handle); + return TRUE; + } else { + _mmcam_dbg_log("Nothing to be cancel or Already processed."); + } + + _MMCAMCORDER_UNLOCK_STATE(handle); + + return FALSE; +} + + +gboolean _mmcamcorder_is_state_changing(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + mmf_return_val_if_fail(hcamcorder, FALSE); + + _mmcam_dbg_log("(%d)", (hcamcorder->target_state != hcamcorder->state)); + + if (hcamcorder->sync_state_change) { + return FALSE; + } + + _MMCAMCORDER_LOCK_STATE(handle); + + if (hcamcorder->target_state != hcamcorder->state) { + _MMCAMCORDER_UNLOCK_STATE(handle); + return TRUE; + } + + _MMCAMCORDER_UNLOCK_STATE(handle); + + return FALSE; +} + + +_MMCamcorderSubContext *_mmcamcorder_alloc_subcontext(int type) +{ + int i; + _MMCamcorderSubContext *sc = NULL; + + _mmcam_dbg_log(""); + + /* alloc container */ + sc = (_MMCamcorderSubContext *)malloc(sizeof(_MMCamcorderSubContext)); + mmf_return_val_if_fail(sc != NULL, NULL); + + /* init members */ + memset(sc, 0x00, sizeof(_MMCamcorderSubContext)); + + sc->element_num = _MMCamcorder_PIPELINE_ELEMENT_NUM; + + /* alloc info for each mode */ + switch (type) { + case MM_CAMCORDER_MODE_IMAGE: + sc->info = malloc( sizeof(_MMCamcorderImageInfo)); + if(sc->info == NULL) { + _mmcam_dbg_err("Failed to alloc info structure"); + free(sc); + return NULL; + } + memset(sc->info, 0x00, sizeof(_MMCamcorderImageInfo)); + break; + case MM_CAMCORDER_MODE_AUDIO: + sc->info = malloc( sizeof(_MMCamcorderAudioInfo)); + if(sc->info == 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) { + _mmcam_dbg_err("Failed to alloc info structure"); + free(sc); + return NULL; + } + memset(sc->info, 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); + free(sc); + return NULL; + } + + for (i = 0; i< sc->element_num; i++) { + sc->element[i].id = _MMCAMCORDER_NONE; + sc->element[i].gst = NULL; + } + + sc->fourcc = 0x80000000; + + sc->cam_stability_count = 0; + sc->drop_vframe = 0; + sc->pass_first_vframe = 0; + + return sc; +} + + +void _mmcamcorder_dealloc_subcontext(_MMCamcorderSubContext *sc) +{ + _mmcam_dbg_log(""); + + if (sc) { + if (sc->element) { + free(sc->element); + sc->element = NULL; + } + + if (sc->info) { + free(sc->info); + sc->info = NULL; + } + + free(sc); + sc = NULL; + } + + return; +} + + +int _mmcamcorder_set_functions(MMHandleType handle, int type) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + _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; + default: + return MM_ERROR_CAMCORDER_INTERNAL; + break; + } + + return MM_ERROR_NONE; +} + + +gboolean _mmcamcorder_pipeline_cb_message(GstBus *bus, GstMessage *message, gpointer data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data); + _MMCamcorderMsgItem msg; + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(hcamcorder, FALSE); + mmf_return_val_if_fail(message, FALSE); + //_mmcam_dbg_log("message type=(%d)", GST_MESSAGE_TYPE(message)); + + switch (GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_UNKNOWN: + _mmcam_dbg_log("GST_MESSAGE_UNKNOWN"); + break; + case GST_MESSAGE_EOS: + { + _mmcam_dbg_log ("Got EOS from element \"%s\".", + GST_STR_NULL(GST_ELEMENT_NAME(GST_MESSAGE_SRC(message)))); + + 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) { + _mmcamcorder_video_handle_eos((MMHandleType)hcamcorder); + } + } else if (hcamcorder->type == MM_CAMCORDER_MODE_AUDIO) { + _MMCamcorderAudioInfo *info = sc->info; + if (info->b_commiting) { + _mmcamcorder_audio_handle_eos((MMHandleType)hcamcorder); + } + } + + sc->bget_eos = TRUE; + + break; + } + case GST_MESSAGE_ERROR: + { + GError *err; + gchar *debug; + gst_message_parse_error(message, &err, &debug); + + _mmcam_dbg_err ("GSTERR: %s", err->message); + _mmcam_dbg_err ("Error Debug: %s", debug); + + __mmcamcorder_handle_gst_error((MMHandleType)hcamcorder, message, err); + + g_error_free (err); + g_free (debug); + break; + } + case GST_MESSAGE_WARNING: + { + GError *err; + gchar *debug; + gst_message_parse_warning (message, &err, &debug); + + _mmcam_dbg_warn("GSTWARN: %s", err->message); + + __mmcamcorder_handle_gst_warning((MMHandleType)hcamcorder, message, err); + + g_error_free (err); + g_free (debug); + break; + } + case GST_MESSAGE_INFO: + _mmcam_dbg_log("GST_MESSAGE_INFO"); + break; + case GST_MESSAGE_TAG: + _mmcam_dbg_log("GST_MESSAGE_TAG"); + break; + case GST_MESSAGE_BUFFERING: + _mmcam_dbg_log("GST_MESSAGE_BUFFERING"); + break; + case GST_MESSAGE_STATE_CHANGED: + { + GValue *vnewstate; + GstState newstate; + GstElement *pipeline = NULL; + + sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + if ((sc) && (sc->element)) { + if (sc->element[_MMCAMCORDER_MAIN_PIPE].gst) { + pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; + if (message->src == (GstObject*)pipeline) { + vnewstate = (GValue*)gst_structure_get_value(message->structure, "new-state"); + newstate = (GstState)vnewstate->data[0].v_int; + _mmcam_dbg_log("GST_MESSAGE_STATE_CHANGED[%s]",gst_element_state_get_name(newstate)); + } + } + } + break; + } + case GST_MESSAGE_STATE_DIRTY: + _mmcam_dbg_log("GST_MESSAGE_STATE_DIRTY"); + break; + case GST_MESSAGE_STEP_DONE: + _mmcam_dbg_log("GST_MESSAGE_STEP_DONE"); + break; + case GST_MESSAGE_CLOCK_PROVIDE: + _mmcam_dbg_log("GST_MESSAGE_CLOCK_PROVIDE"); + break; + case GST_MESSAGE_CLOCK_LOST: + _mmcam_dbg_log("GST_MESSAGE_CLOCK_LOST"); + break; + case GST_MESSAGE_NEW_CLOCK: + { + GstClock *clock; + gst_message_parse_new_clock(message, &clock); + _mmcam_dbg_log("GST_MESSAGE_NEW_CLOCK : %s", (clock ? GST_OBJECT_NAME (clock) : "NULL")); + break; + } + case GST_MESSAGE_STRUCTURE_CHANGE: + _mmcam_dbg_log("GST_MESSAGE_STRUCTURE_CHANGE"); + break; + case GST_MESSAGE_STREAM_STATUS: + _mmcam_dbg_log("GST_MESSAGE_STREAM_STATUS"); + break; + case GST_MESSAGE_APPLICATION: + _mmcam_dbg_log("GST_MESSAGE_APPLICATION"); + break; + case GST_MESSAGE_ELEMENT: + _mmcam_dbg_log("GST_MESSAGE_ELEMENT"); + + if (gst_structure_has_name(message->structure, "avsysvideosrc-AF") || + gst_structure_has_name(message->structure, "camerasrc-AF")) { + int focus_state = 0; + + gst_structure_get_int(message->structure, "focus-state", &focus_state); + _mmcam_dbg_log("Focus State:%d", focus_state); + + msg.id = MM_MESSAGE_CAMCORDER_FOCUS_CHANGED; + msg.param.code = focus_state; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + } + break; + case GST_MESSAGE_SEGMENT_START: + _mmcam_dbg_log("GST_MESSAGE_SEGMENT_START"); + break; + case GST_MESSAGE_SEGMENT_DONE: + _mmcam_dbg_log("GST_MESSAGE_SEGMENT_DONE"); + break; + case GST_MESSAGE_DURATION: + _mmcam_dbg_log("GST_MESSAGE_DURATION"); + break; + case GST_MESSAGE_LATENCY: + _mmcam_dbg_log("GST_MESSAGE_LATENCY"); + break; + case GST_MESSAGE_ASYNC_START: + _mmcam_dbg_log("GST_MESSAGE_ASYNC_START"); + break; + case GST_MESSAGE_ASYNC_DONE: + _mmcam_dbg_log("GST_MESSAGE_ASYNC_DONE"); + break; + case GST_MESSAGE_ANY: + _mmcam_dbg_log("GST_MESSAGE_ANY"); + break; + default: + _mmcam_dbg_log("not handled message type=(%d)", GST_MESSAGE_TYPE(message)); + break; + } + + return TRUE; +} + + +static int __mmcamcorder_asm_get_event_type(int sessionType) +{ + switch (sessionType) { + case MM_SESSION_TYPE_SHARE: + return ASM_EVENT_SHARE_MMCAMCORDER; + case MM_SESSION_TYPE_EXCLUSIVE: + return ASM_EVENT_EXCLUSIVE_MMCAMCORDER; + case MM_SESSION_TYPE_NOTIFY: + return ASM_EVENT_NOTIFY; + case MM_SESSION_TYPE_CALL: + return ASM_EVENT_CALL; + case MM_SESSION_TYPE_VIDEOCALL: + return ASM_EVENT_VIDEOCALL; + case MM_SESSION_TYPE_ALARM: + return ASM_EVENT_ALARM; + default: + return ASM_EVENT_SHARE_MMCAMCORDER; + } +} + +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) +{ + 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); + if (current_state <= MM_CAMCORDER_STATE_NONE || + current_state >= MM_CAMCORDER_STATE_NUM) { + _mmcam_dbg_err("Abnormal state. Or null handle. (%p, %d, %d)", hcamcorder, 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"); + return ASM_CB_RES_PLAYING; + } + + __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; +} + + +int _mmcamcorder_create_pipeline(MMHandleType handle, int type) +{ + int ret = MM_ERROR_NONE; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + GstElement *pipeline = NULL; + + _mmcam_dbg_log("handle : %x, type : %d", handle, type); + + 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); + + 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); + ); + if (ret != MM_ERROR_NONE) { + return ret; + } + break; + case MM_CAMCORDER_MODE_VIDEO: + __ta__(" _mmcamcorder_create_preview_pipeline", + ret = _mmcamcorder_create_preview_pipeline(handle); + ); + if (ret != MM_ERROR_NONE) { + return ret; + } + break; + default: + return MM_ERROR_CAMCORDER_INTERNAL; + } + + pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; + if (type != MM_CAMCORDER_MODE_AUDIO) { + if (hcamcorder->sync_state_change) { + ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY); + } else { + ret = _mmcamcorder_gst_set_state_async(handle, pipeline, GST_STATE_READY); + if (ret == GST_STATE_CHANGE_FAILURE) { + return MM_ERROR_CAMCORDER_GST_STATECHANGE; + } + } + } + + if (!_mmcamcorder_get_device_info(handle)) { + _mmcam_dbg_err("Getting device information error!!"); + } + + _mmcam_dbg_log("ret[%x]", ret); + return ret; +} + + +void _mmcamcorder_destroy_pipeline(MMHandleType handle, int type) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + gint i = 0; + GstBus *bus = NULL; + + mmf_return_if_fail(hcamcorder); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_if_fail(sc); + + _mmcam_dbg_log(""); + + bus = gst_pipeline_get_bus(GST_PIPELINE(sc->element[_MMCAMCORDER_MAIN_PIPE].gst)); + + /* Inside each pipeline destroy function, Set GST_STATE_NULL to Main pipeline */ + switch (type) { + case MM_CAMCORDER_MODE_IMAGE: + _mmcamcorder_destroy_image_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: + break; + } + + _mmcam_dbg_log("Pipeline clear!!"); + + /* Remove pipeline message callback */ + g_source_remove(hcamcorder->pipeline_cb_event_id); + + /* Remove remained message in bus */ + if (bus != NULL) { + GstMessage *gst_msg = NULL; + while ((gst_msg = gst_bus_pop(bus)) != NULL) { + _mmcamcorder_pipeline_cb_message(bus, gst_msg, (gpointer)hcamcorder); + gst_message_unref( gst_msg ); + gst_msg = NULL; + } + gst_object_unref( bus ); + bus = NULL; + } + + /* checking unreleased element */ + for (i = 0 ; i < _MMCamcorder_PIPELINE_ELEMENT_NUM ; i++ ) { + if (sc->element[i].gst) { + if (GST_IS_ELEMENT(sc->element[i].gst)) { + _mmcam_dbg_warn("Still alive element - ID[%d], name [%s], ref count[%d], status[%s]", + sc->element[i].id, + GST_OBJECT_NAME(sc->element[i].gst), + GST_OBJECT_REFCOUNT_VALUE(sc->element[i].gst), + gst_element_state_get_name (GST_STATE (sc->element[i].gst))); + g_object_weak_unref(G_OBJECT(sc->element[i].gst), (GWeakNotify)_mmcamcorder_element_release_noti, sc); + } else { + _mmcam_dbg_warn("The element[%d] is still aliving, check it", sc->element[i].id); + } + + sc->element[i].id = _MMCAMCORDER_NONE; + sc->element[i].gst = NULL; + } + } +} + + +int _mmcamcorder_gst_set_state_async(MMHandleType handle, GstElement *pipeline, GstState target_state) +{ + GstStateChangeReturn setChangeReturn = GST_STATE_CHANGE_FAILURE; + + _MMCAMCORDER_LOCK_GST_STATE(handle); + setChangeReturn = gst_element_set_state(pipeline, target_state); + _MMCAMCORDER_UNLOCK_GST_STATE(handle); + + return setChangeReturn; +} + + +static gboolean __mmcamcorder_set_attr_to_camsensor_cb(gpointer data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data); + + mmf_return_val_if_fail(hcamcorder, FALSE); + + _mmcam_dbg_log(""); + + _mmcamcorder_set_attribute_to_camsensor((MMHandleType)hcamcorder); + + /* initialize */ + hcamcorder->setting_event_id = 0; + + _mmcam_dbg_log("Done"); + + /* once */ + return FALSE; +} + + +int _mmcamcorder_gst_set_state (MMHandleType handle, GstElement *pipeline, GstState target_state) +{ + unsigned int k = 0; + GstState pipeline_state = GST_STATE_VOID_PENDING; + GstStateChangeReturn setChangeReturn = GST_STATE_CHANGE_FAILURE; + GstStateChangeReturn getChangeReturn = GST_STATE_CHANGE_FAILURE; + GstClockTime get_timeout = 3 * GST_SECOND; + + mmf_return_val_if_fail(handle, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log("Set state to %d", target_state); + + _MMCAMCORDER_LOCK_GST_STATE(handle); + + for (k = 0; k < _MMCAMCORDER_STATE_SET_COUNT; k++) { + setChangeReturn = gst_element_set_state(pipeline, target_state); + if (setChangeReturn != GST_STATE_CHANGE_FAILURE) { + getChangeReturn = gst_element_get_state(pipeline, &pipeline_state, NULL, get_timeout); + switch (getChangeReturn) { + case GST_STATE_CHANGE_NO_PREROLL: + _mmcam_dbg_log("status=GST_STATE_CHANGE_NO_PREROLL."); + case GST_STATE_CHANGE_SUCCESS: + /* if we reached the final target state, exit */ + if (pipeline_state == target_state) { + _MMCAMCORDER_UNLOCK_GST_STATE(handle); + return MM_ERROR_NONE; + } + break; + case GST_STATE_CHANGE_ASYNC: + _mmcam_dbg_log("status=GST_STATE_CHANGE_ASYNC."); + break; + default : + _MMCAMCORDER_UNLOCK_GST_STATE(handle); + _mmcam_dbg_log("status=GST_STATE_CHANGE_FAILURE."); + return MM_ERROR_CAMCORDER_GST_STATECHANGE; + } + + _MMCAMCORDER_UNLOCK_GST_STATE(handle); + _mmcam_dbg_err("timeout of gst_element_get_state()!!"); + return MM_ERROR_CAMCORDER_RESPONSE_TIMEOUT; + } + usleep(_MMCAMCORDER_STATE_CHECK_INTERVAL); + } + + _MMCAMCORDER_UNLOCK_GST_STATE(handle); + + _mmcam_dbg_err("Failure. gst_element_set_state timeout!!"); + + return MM_ERROR_CAMCORDER_RESPONSE_TIMEOUT; +} + + +/* For performance check */ +int _mmcamcorder_video_current_framerate(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(hcamcorder, -1); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, -1); + + return sc->kpi.current_fps; +} + + +int _mmcamcorder_video_average_framerate(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(hcamcorder, -1); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, -1); + + return sc->kpi.average_fps; +} + + +void _mmcamcorder_video_current_framerate_init(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_if_fail(hcamcorder); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_if_fail(sc); + + memset(&(sc->kpi), 0x00, sizeof(_MMCamcorderKPIMeasure)); + + return; +} + +/* Async state change */ +void _mmcamcorder_delete_command_info(__MMCamcorderCmdInfo *cmdinfo) +{ + if (cmdinfo) { + g_free(cmdinfo); + } +} + +static void __mmcamcorder_force_stop(mmf_camcorder_t *hcamcorder) +{ + int i = 0; + int loop = 0; + int itr_cnt = 0; + int result = MM_ERROR_NONE; + int current_state = MM_CAMCORDER_STATE_NONE; + + mmf_return_if_fail(hcamcorder); + + current_state = _mmcamcorder_get_state((MMHandleType)hcamcorder); + + _mmcam_dbg_log( "Force STOP MMFW Camcorder" ); + + for (loop = 0 ; current_state > MM_CAMCORDER_STATE_NULL && loop < __MMCAMCORDER_CMD_ITERATE_MAX * 3 ; loop++) { + itr_cnt = __MMCAMCORDER_CMD_ITERATE_MAX; + switch (current_state) { + case MM_CAMCORDER_STATE_CAPTURING: + { + _MMCamcorderSubContext *sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + _MMCamcorderImageInfo *info = NULL; + + mmf_return_if_fail(sc); + mmf_return_if_fail((info = sc->info)); + + _mmcam_dbg_log("Stop capturing."); + + /* if caturing isn't finished, waiting for 2 sec to finish real capture operation. check 'info->capturing'. */ + mm_camcorder_set_attributes((MMHandleType)hcamcorder, NULL, + MMCAM_CAPTURE_BREAK_CONTINUOUS_SHOT, TRUE, + NULL); + + for (i = 0; i < 20 && info->capturing; i++) { + usleep(100000); + } + + if (i == 20) { + _mmcam_dbg_err("Timeout. Can't check stop capturing."); + } + + while ((itr_cnt--) && ((result = _mmcamcorder_capture_stop((MMHandleType)hcamcorder)) != MM_ERROR_NONE)) { + _mmcam_dbg_warn("Can't stop capturing.(%x)", result); + } + + break; + } + case MM_CAMCORDER_STATE_RECORDING: + case MM_CAMCORDER_STATE_PAUSED: + { + _mmcam_dbg_log("Stop recording."); + + while ((itr_cnt--) && ((result = _mmcamcorder_commit((MMHandleType)hcamcorder)) != MM_ERROR_NONE)) { + _mmcam_dbg_warn("Can't commit.(%x)", result); + } + break; + } + case MM_CAMCORDER_STATE_PREPARE: + { + _mmcam_dbg_log("Stop preview."); + + while ((itr_cnt--) && ((result = _mmcamcorder_stop((MMHandleType)hcamcorder)) != MM_ERROR_NONE)) { + _mmcam_dbg_warn("Can't stop preview.(%x)", result); + } + break; + } + case MM_CAMCORDER_STATE_READY: + { + _mmcam_dbg_log("unrealize"); + + if ((result = _mmcamcorder_unrealize((MMHandleType)hcamcorder)) != MM_ERROR_NONE) { + _mmcam_dbg_warn("Can't unrealize.(%x)", result); + } + break; + } + case MM_CAMCORDER_STATE_NULL: + default: + _mmcam_dbg_log("Already stopped."); + break; + } + + current_state = _mmcamcorder_get_state((MMHandleType)hcamcorder); + } + + _mmcam_dbg_log( "Done." ); + + return; +} + + +static void __mmcamcorder_force_resume(mmf_camcorder_t *hcamcorder) +{ + int loop = 0; + int result = MM_ERROR_NONE; + int itr_cnt = 0; + int current_state = MM_CAMCORDER_STATE_NONE; + + mmf_return_if_fail(hcamcorder); + + _mmcam_dbg_log("Force RESUME MMFW Camcorder"); + + current_state = _mmcamcorder_get_state((MMHandleType)hcamcorder); + + for (loop = 0 ; current_state < MM_CAMCORDER_STATE_PREPARE && loop < __MMCAMCORDER_CMD_ITERATE_MAX * 3 ; loop++) { + itr_cnt = __MMCAMCORDER_CMD_ITERATE_MAX; + + switch (current_state) { + case MM_CAMCORDER_STATE_NULL: + _mmcam_dbg_log("Realize"); + while ((itr_cnt--) && ((result = _mmcamcorder_realize((MMHandleType)hcamcorder)) != MM_ERROR_NONE)) { + _mmcam_dbg_warn("Can't realize.(%x)", result); + } + break; + case MM_CAMCORDER_STATE_READY: + _mmcam_dbg_log("Start previewing"); + + while ((itr_cnt--) && ((result = _mmcamcorder_start((MMHandleType)hcamcorder)) != MM_ERROR_NONE)) { + _mmcam_dbg_warn("Can't start previewing.(%x)", result); + } + break; + default: + _mmcam_dbg_log("Abnormal state."); + break; + } + + current_state = _mmcamcorder_get_state((MMHandleType)hcamcorder); + } + + _mmcam_dbg_log( "Done." ); + + return; +} + +int _mmcamcorder_create_command_loop(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderCommand *cmd; + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log(""); + + cmd = (_MMCamcorderCommand *)&(hcamcorder->cmd); + cmd->cmd_queue = g_queue_new(); + mmf_return_val_if_fail(cmd->cmd_queue, MM_ERROR_CAMCORDER_INVALID_CONDITION); + + sem_init(&cmd->sema, 0, 0); + + if (pthread_create(&cmd->pCommandThread, NULL, _mmcamcorder_command_loop_thread, hcamcorder)) { + perror("Make Command Thread Fail"); + return MM_ERROR_COMMON_UNKNOWN; + } + + return MM_ERROR_NONE; +} + + +int _mmcamcorder_destroy_command_loop(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderCommand *cmd; + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + _mmcam_dbg_log(""); + + cmd = (_MMCamcorderCommand *)&(hcamcorder->cmd); + mmf_return_val_if_fail(cmd->cmd_queue, MM_ERROR_CAMCORDER_INVALID_CONDITION); + + _mmcamcorder_append_simple_command(handle, _MMCAMCORDER_CMD_QUIT); + + sem_post(&cmd->sema); /* why is this needed? */ + + _mmcam_dbg_log("wait for pthread join"); + + pthread_join(cmd->pCommandThread, NULL); + + _mmcam_dbg_log("pthread join!!"); + + sem_destroy(&cmd->sema); + + while (!g_queue_is_empty(cmd->cmd_queue)) { + __MMCamcorderCmdInfo *info = NULL; + info = g_queue_pop_head(cmd->cmd_queue); + _mmcamcorder_delete_command_info(info); + } + g_queue_free(cmd->cmd_queue); + + _mmcam_dbg_log("Command loop clear."); + + return MM_ERROR_NONE; +} + + +int _mmcamcorder_append_command(MMHandleType handle, __MMCamcorderCmdInfo *info) +{ + int value = 0; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderCommand *cmd; + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log(""); + + cmd = (_MMCamcorderCommand *)&(hcamcorder->cmd); + mmf_return_val_if_fail(cmd->cmd_queue, MM_ERROR_CAMCORDER_INVALID_CONDITION); + + g_queue_push_tail (cmd->cmd_queue, (gpointer)info); + + sem_getvalue(&cmd->sema, &value); + + if (value == 0) { + sem_post(&cmd->sema); + } else { + /* Don't need to post. */ + } + + return MM_ERROR_NONE; +} + + +int _mmcamcorder_append_simple_command(MMHandleType handle, _MMCamcorderCommandType type) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + __MMCamcorderCmdInfo *info = NULL; + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log("Command Type=%d", type); + + info = (__MMCamcorderCmdInfo*)malloc(sizeof(__MMCamcorderCmdInfo)); + + info->handle = handle; + info->type = type; + + _mmcamcorder_append_command(handle, info); + + return MM_ERROR_NONE; +} + + +void *_mmcamcorder_command_loop_thread(void *arg) +{ + gboolean bExit_loop = FALSE; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(arg); + _MMCamcorderCommand *cmd = NULL; + __MMCamcorderCmdInfo *cmdinfo = NULL; + + mmf_return_val_if_fail(hcamcorder, NULL); + + cmd = (_MMCamcorderCommand *)&(hcamcorder->cmd); + mmf_return_val_if_fail(cmd->cmd_queue, NULL); + + _mmcam_dbg_log(""); + + while (!bExit_loop) { + sem_wait(&cmd->sema); + + /* send command */ + while (!g_queue_is_empty (cmd->cmd_queue)) { + int bRet = MM_ERROR_NONE; + + cmdinfo = g_queue_pop_head(cmd->cmd_queue); + if (cmdinfo->handle == (MMHandleType)NULL) { + _mmcam_dbg_log("Handle in cmdinfo is Null."); + bRet = MM_ERROR_CAMCORDER_NOT_INITIALIZED; + } else { + switch (cmdinfo->type) { + case _MMCAMCORDER_CMD_CREATE: + case _MMCAMCORDER_CMD_DESTROY: + case _MMCAMCORDER_CMD_CAPTURESTART: + case _MMCAMCORDER_CMD_CAPTURESTOP: + case _MMCAMCORDER_CMD_RECORD: + case _MMCAMCORDER_CMD_PAUSE: + case _MMCAMCORDER_CMD_COMMIT: + __ta__("_mmcamcorder_commit", + bRet = _mmcamcorder_commit(cmdinfo->handle); + ); + break; + case _MMCAMCORDER_CMD_CANCEL: + //Not used yet. + break; + case _MMCAMCORDER_CMD_REALIZE: + __ta__("_mmcamcorder_realize", + bRet = _mmcamcorder_realize(cmdinfo->handle); + ); + break; + case _MMCAMCORDER_CMD_UNREALIZE: + __ta__("_mmcamcorder_unrealize", + bRet = _mmcamcorder_unrealize(cmdinfo->handle); + ); + break; + case _MMCAMCORDER_CMD_START: + __ta__("_mmcamcorder_start", + bRet = _mmcamcorder_start(cmdinfo->handle); + ); + break; + case _MMCAMCORDER_CMD_STOP: + __ta__("_mmcamcorder_stop", + bRet = _mmcamcorder_stop(cmdinfo->handle); + ); + break; + case _MMCAMCORDER_CMD_QUIT: + _mmcam_dbg_log("Exit command loop!!"); + bExit_loop = TRUE; + break; + default: + _mmcam_dbg_log("Wrong command type!!!"); + break; + } + } + + if (bRet != MM_ERROR_NONE) { + _mmcam_dbg_log("Error on command process!(%x)", bRet); + /* Do something? */ + } + + _mmcamcorder_delete_command_info(cmdinfo); + + if (bExit_loop) { + break; + } + usleep(1); + } + } + + return NULL; +} + + +static gboolean __mmcamcorder_handle_gst_error(MMHandleType handle, GstMessage *message, GError *error) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderMsgItem msg; + gchar *msg_src_element; + _MMCamcorderSubContext *sc = NULL; + + return_val_if_fail(hcamcorder, FALSE); + return_val_if_fail(error, FALSE); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, FALSE); + + _mmcam_dbg_log(""); + + /* filtering filesink related errors */ + if (hcamcorder->state == MM_CAMCORDER_STATE_RECORDING && + (error->code == GST_RESOURCE_ERROR_WRITE || error->code == GST_RESOURCE_ERROR_SEEK)) { + if (sc->ferror_count == 2 && sc->ferror_send == FALSE) { + sc->ferror_send = TRUE; + msg.param.code = __mmcamcorder_gst_handle_resource_error(handle, error->code, message); + } else { + sc->ferror_count++; + _mmcam_dbg_warn("Skip error"); + return TRUE; + } + } + + if (error->domain == GST_CORE_ERROR) { + msg.param.code = __mmcamcorder_gst_handle_core_error(handle, error->code, message); + } else if (error->domain == GST_LIBRARY_ERROR) { + msg.param.code = __mmcamcorder_gst_handle_library_error(handle, error->code, message); + } else if (error->domain == GST_RESOURCE_ERROR) { + msg.param.code = __mmcamcorder_gst_handle_resource_error(handle, error->code, message); + } 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"); + + /* we treat system error as an internal error */ + msg.param.code = MM_ERROR_CAMCORDER_INTERNAL; + } + + 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); + } 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); + } + + /* 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; + } + + /* post error to application */ + sc->error_occurs = TRUE; + msg.id = MM_MESSAGE_CAMCORDER_ERROR; + _mmcamcroder_send_message(handle, &msg); + + return TRUE; +} + + +static gint __mmcamcorder_gst_handle_core_error(MMHandleType handle, int code, GstMessage *message) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + GstElement *element = NULL; + + _mmcam_dbg_log(""); + + 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); + + /* Specific plugin - video encoder plugin */ + element = GST_ELEMENT_CAST(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst); + + if (GST_ELEMENT_CAST(message->src) == element) { + if (code == GST_CORE_ERROR_NEGOTIATION) { + return MM_ERROR_CAMCORDER_GST_NEGOTIATION; + } else { + return MM_ERROR_CAMCORDER_ENCODER; + } + } + + /* General */ + switch (code) + { + case GST_CORE_ERROR_STATE_CHANGE: + return MM_ERROR_CAMCORDER_GST_STATECHANGE; + case GST_CORE_ERROR_NEGOTIATION: + return MM_ERROR_CAMCORDER_GST_NEGOTIATION; + case GST_CORE_ERROR_MISSING_PLUGIN: + case GST_CORE_ERROR_SEEK: + case GST_CORE_ERROR_NOT_IMPLEMENTED: + case GST_CORE_ERROR_FAILED: + case GST_CORE_ERROR_TOO_LAZY: + case GST_CORE_ERROR_PAD: + case GST_CORE_ERROR_THREAD: + case GST_CORE_ERROR_EVENT: + case GST_CORE_ERROR_CAPS: + case GST_CORE_ERROR_TAG: + case GST_CORE_ERROR_CLOCK: + case GST_CORE_ERROR_DISABLED: + default: + return MM_ERROR_CAMCORDER_GST_CORE; + break; + } +} + +static gint __mmcamcorder_gst_handle_library_error(MMHandleType handle, int code, GstMessage *message) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log(""); + + /* Specific plugin - NONE */ + + /* General */ + switch (code) { + case GST_LIBRARY_ERROR_FAILED: + case GST_LIBRARY_ERROR_TOO_LAZY: + case GST_LIBRARY_ERROR_INIT: + case GST_LIBRARY_ERROR_SHUTDOWN: + case GST_LIBRARY_ERROR_SETTINGS: + case GST_LIBRARY_ERROR_ENCODE: + default: + _mmcam_dbg_err("Library error(%d)", code); + return MM_ERROR_CAMCORDER_GST_LIBRARY; + } +} + + +static gint __mmcamcorder_gst_handle_resource_error(MMHandleType handle, int code, GstMessage *message) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + GstElement *element =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); + + _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) { + if (code == GST_RESOURCE_ERROR_WRITE) { + _mmcam_dbg_err("Display device [Off]"); + return MM_ERROR_CAMCORDER_DISPLAY_DEVICE_OFF; + } else { + _mmcam_dbg_err("Display device [General(%d)]", code); + } + } + + /* encodebin */ + element = GST_ELEMENT_CAST(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst); + if (GST_ELEMENT_CAST(message->src) == element) { + if (code == GST_RESOURCE_ERROR_FAILED) { + _mmcam_dbg_err("Encoder [Resource error]"); + return MM_ERROR_CAMCORDER_ENCODER_BUFFER; + } else { + _mmcam_dbg_err("Encoder [General(%d)]", code); + return MM_ERROR_CAMCORDER_ENCODER; + } + } + + /* General */ + switch (code) { + case GST_RESOURCE_ERROR_WRITE: + _mmcam_dbg_err("File write error"); + return MM_ERROR_FILE_WRITE; + case GST_RESOURCE_ERROR_NO_SPACE_LEFT: + _mmcam_dbg_err("No left space"); + return MM_MESSAGE_CAMCORDER_NO_FREE_SPACE; + case GST_RESOURCE_ERROR_OPEN_WRITE: + _mmcam_dbg_err("Out of storage"); + return MM_ERROR_OUT_OF_STORAGE; + case GST_RESOURCE_ERROR_SEEK: + _mmcam_dbg_err("File read(seek)"); + return MM_ERROR_FILE_READ; + case GST_RESOURCE_ERROR_NOT_FOUND: + case GST_RESOURCE_ERROR_FAILED: + case GST_RESOURCE_ERROR_TOO_LAZY: + case GST_RESOURCE_ERROR_BUSY: + case GST_RESOURCE_ERROR_OPEN_READ: + case GST_RESOURCE_ERROR_OPEN_READ_WRITE: + case GST_RESOURCE_ERROR_CLOSE: + case GST_RESOURCE_ERROR_READ: + case GST_RESOURCE_ERROR_SYNC: + case GST_RESOURCE_ERROR_SETTINGS: + default: + _mmcam_dbg_err("Resource error(%d)", code); + return MM_ERROR_CAMCORDER_GST_RESOURCE; + } +} + + +static gint __mmcamcorder_gst_handle_stream_error(MMHandleType handle, int code, GstMessage *message) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + GstElement *element =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); + + _mmcam_dbg_log(""); + + /* Specific plugin */ + /* video encoder */ + element = GST_ELEMENT_CAST(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst); + if (GST_ELEMENT_CAST(message->src) == element) { + switch (code) { + case GST_STREAM_ERROR_WRONG_TYPE: + _mmcam_dbg_err("Video encoder [wrong stream type]"); + return MM_ERROR_CAMCORDER_ENCODER_WRONG_TYPE; + case GST_STREAM_ERROR_ENCODE: + _mmcam_dbg_err("Video encoder [encode error]"); + return MM_ERROR_CAMCORDER_ENCODER_WORKING; + case GST_STREAM_ERROR_FAILED: + _mmcam_dbg_err("Video encoder [stream failed]"); + return MM_ERROR_CAMCORDER_ENCODER_WORKING; + default: + _mmcam_dbg_err("Video encoder [General(%d)]", code); + return MM_ERROR_CAMCORDER_ENCODER; + } + } + + /* General plugin */ + switch (code) { + case GST_STREAM_ERROR_FORMAT: + _mmcam_dbg_err("General [negotiation error(%d)]", code); + return MM_ERROR_CAMCORDER_GST_NEGOTIATION; + case GST_STREAM_ERROR_FAILED: + _mmcam_dbg_err("General [flow error(%d)]", code); + return MM_ERROR_CAMCORDER_GST_FLOW_ERROR; + case GST_STREAM_ERROR_TYPE_NOT_FOUND: + case GST_STREAM_ERROR_DECODE: + case GST_STREAM_ERROR_CODEC_NOT_FOUND: + case GST_STREAM_ERROR_NOT_IMPLEMENTED: + case GST_STREAM_ERROR_TOO_LAZY: + case GST_STREAM_ERROR_ENCODE: + case GST_STREAM_ERROR_DEMUX: + case GST_STREAM_ERROR_MUX: + case GST_STREAM_ERROR_DECRYPT: + case GST_STREAM_ERROR_DECRYPT_NOKEY: + case GST_STREAM_ERROR_WRONG_TYPE: + default: + _mmcam_dbg_err("General [error(%d)]", code); + return MM_ERROR_CAMCORDER_GST_STREAM; + } +} + + +static gboolean __mmcamcorder_handle_gst_warning (MMHandleType handle, GstMessage *message, GError *error) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + gchar *debug = NULL; + GError *err = NULL; + + return_val_if_fail(hcamcorder, FALSE); + return_val_if_fail(error, FALSE); + + _mmcam_dbg_log(""); + + gst_message_parse_warning(message, &err, &debug); + + if (error->domain == GST_CORE_ERROR) { + _mmcam_dbg_warn("GST warning: GST_CORE domain"); + } else if (error->domain == GST_LIBRARY_ERROR) { + _mmcam_dbg_warn("GST warning: GST_LIBRARY domain"); + } else if (error->domain == GST_RESOURCE_ERROR) { + _mmcam_dbg_warn("GST warning: GST_RESOURCE domain"); + __mmcamcorder_gst_handle_resource_warning(handle, message, error); + } else if (error->domain == GST_STREAM_ERROR ) { + _mmcam_dbg_warn("GST warning: GST_STREAM domain"); + } else { + _mmcam_dbg_warn("This error domain(%d) is not defined.", error->domain); + } + + if (err != NULL) { + g_error_free(err); + err = NULL; + } + if (debug != NULL) { + _mmcam_dbg_err ("Debug: %s", debug); + g_free(debug); + debug = NULL; + } + + return TRUE; +} + + +static gint __mmcamcorder_gst_handle_resource_warning(MMHandleType handle, GstMessage *message , GError *error) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + GstElement *element =NULL; + gchar *msg_src_element; + + 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); + + _mmcam_dbg_log(""); + + /* Special message handling */ + /* video source */ + element = GST_ELEMENT_CAST(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); + if (GST_ELEMENT_CAST(message->src) == element) { + if (error->code == GST_RESOURCE_ERROR_FAILED) { + msg_src_element = GST_ELEMENT_NAME(GST_ELEMENT_CAST(message->src)); + _mmcam_dbg_warn("-Msg src:[%s] Domain:[%s] Error:[%s]", + msg_src_element, g_quark_to_string(error->domain), error->message); + return MM_ERROR_NONE; + } + } + + /* General plugin */ + switch (error->code) { + case GST_RESOURCE_ERROR_WRITE: + case GST_RESOURCE_ERROR_NO_SPACE_LEFT: + case GST_RESOURCE_ERROR_SEEK: + case GST_RESOURCE_ERROR_NOT_FOUND: + case GST_RESOURCE_ERROR_FAILED: + case GST_RESOURCE_ERROR_TOO_LAZY: + case GST_RESOURCE_ERROR_BUSY: + case GST_RESOURCE_ERROR_OPEN_READ: + case GST_RESOURCE_ERROR_OPEN_WRITE: + case GST_RESOURCE_ERROR_OPEN_READ_WRITE: + case GST_RESOURCE_ERROR_CLOSE: + case GST_RESOURCE_ERROR_READ: + case GST_RESOURCE_ERROR_SYNC: + case GST_RESOURCE_ERROR_SETTINGS: + default: + _mmcam_dbg_warn("General GST warning(%d)", error->code); + break; + } + + return MM_ERROR_NONE; +} diff --git a/src/mm_camcorder_platform.c b/src/mm_camcorder_platform.c new file mode 100644 index 0000000..3497ab5 --- /dev/null +++ b/src/mm_camcorder_platform.c @@ -0,0 +1,977 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*=========================================================================================== +| | +| INCLUDE FILES | +| | +========================================================================================== */ +#include "mm_camcorder_internal.h" +#include "mm_camcorder_platform.h" +#include "mm_camcorder_configure.h" + +/*--------------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------*/ +#define MM_CAMCORDER_ATTR_NONE -1 + + +// Rule 1. 1:1 match except NONE. +// Rule 2. MSL should be Superset. +// Rule 3. sensor value should not be same as _MMCAMCORDER_SENSOR_ENUM_NONE. + +static int __enum_conv_whitebalance[MM_CAMCORDER_WHITE_BALANCE_NUM] ; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_whitebalance = +{ + MM_CAMCORDER_WHITE_BALANCE_NUM, + __enum_conv_whitebalance, + CONFIGURE_CATEGORY_CTRL_EFFECT, + "WhiteBalance" +}; + + +static int __enum_conv_colortone[MM_CAMCORDER_COLOR_TONE_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_colortone = +{ + MM_CAMCORDER_COLOR_TONE_NUM, + __enum_conv_colortone, + CONFIGURE_CATEGORY_CTRL_EFFECT, + "ColorTone" +}; + + +static int __enum_conv_iso[MM_CAMCORDER_ISO_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_iso = +{ + MM_CAMCORDER_ISO_NUM, + __enum_conv_iso, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + "ISO" +}; + + +static int __enum_conv_prgrm[MM_CAMCORDER_SCENE_MODE_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_prgrm = +{ + MM_CAMCORDER_SCENE_MODE_NUM, + __enum_conv_prgrm, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + "ProgramMode" +}; + + +static int __enum_conv_focus_mode[MM_CAMCORDER_FOCUS_MODE_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_focus_mode = +{ + MM_CAMCORDER_FOCUS_MODE_NUM, + __enum_conv_focus_mode, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + "FocusMode" +}; + + +static int __enum_conv_focus_type[MM_CAMCORDER_AUTO_FOCUS_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_focus_type = +{ + MM_CAMCORDER_AUTO_FOCUS_NUM, + __enum_conv_focus_type, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + "AFType" +}; + + +static int __enum_conv_ae_type[MM_CAMCORDER_AUTO_EXPOSURE_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_ae_type = +{ + MM_CAMCORDER_AUTO_EXPOSURE_NUM, + __enum_conv_ae_type, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + "AEType" +}; + + +static int __enum_conv_strobe_ctrl[MM_CAMCORDER_STROBE_CONTROL_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_strobe_ctrl = +{ + MM_CAMCORDER_STROBE_CONTROL_NUM, + __enum_conv_strobe_ctrl, + CONFIGURE_CATEGORY_CTRL_STROBE, + "StrobeControl" +}; + + +static int __enum_conv_strobe_mode[MM_CAMCORDER_STROBE_MODE_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_strobe_mode = +{ + MM_CAMCORDER_STROBE_MODE_NUM, + __enum_conv_strobe_mode, + CONFIGURE_CATEGORY_CTRL_STROBE, + "StrobeMode" +}; + + +static int __enum_conv_wdr_ctrl[MM_CAMCORDER_WDR_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_wdr_ctrl = +{ + MM_CAMCORDER_WDR_NUM, + __enum_conv_wdr_ctrl, + CONFIGURE_CATEGORY_CTRL_EFFECT, + "WDR" +}; + + +static int __enum_conv_ahs[MM_CAMCORDER_AHS_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_ahs = +{ + MM_CAMCORDER_AHS_NUM, + __enum_conv_ahs, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + "AntiHandshake" +}; + +static int __enum_conv_picture_format[MM_PIXEL_FORMAT_NUM]; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_picture_format = +{ + MM_PIXEL_FORMAT_NUM, + __enum_conv_picture_format, + CONFIGURE_CATEGORY_CTRL_CAMERA, + "PictureFormat" +}; + +static int __enum_conv_vid_dev[MM_VIDEO_DEVICE_NUM] = +{ + //{Enum of (Plugin or Kernel) , Enum of MSL Camcorder} + 2, //MM_VIDEO_DEVICE_CAMERA0 + 1, //MM_VIDEO_DEVICE_CAMERA1 +}; + +_MMCamcorderEnumConvert _mmcamcorder_enum_conv_vid_dev = +{ + MM_VIDEO_DEVICE_NUM, + __enum_conv_vid_dev, + 0, + NULL +}; + + +/** + * Matching table of caminfo index with category enum of attribute. + * If predefined item is changed, this static variables should be changed. + * For detail information, refer below documents. + * + */ +static _MMCamcorderInfoConverting g_display_info[] = { + { + CONFIGURE_TYPE_MAIN, + CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT, + MM_CAM_DISPLAY_DEVICE, + MM_CAMCORDER_ATTR_NONE, + "DisplayDevice", + MM_CAMCONVERT_TYPE_INT_ARRAY, + NULL, + }, + { + CONFIGURE_TYPE_MAIN, + CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT, + MM_CAM_DISPLAY_SURFACE, + MM_CAMCORDER_ATTR_NONE, + "Videosink", + MM_CAMCONVERT_TYPE_INT_ARRAY, + NULL, + }, +}; + +static _MMCamcorderInfoConverting g_caminfo_convert[] = { + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_CAMERA, + MM_CAM_CAMERA_DEVICE, + MM_CAMCORDER_ATTR_NONE, + "InputIndex", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_vid_dev, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_CAMERA, + MM_CAM_CAMERA_DEVICE_NAME, + MM_CAMCORDER_ATTR_NONE, + "DeviceName", + MM_CAMCONVERT_TYPE_STRING, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_CAMERA, + MM_CAM_CAMERA_WIDTH, + MM_CAM_CAMERA_HEIGHT, + "PreviewResolution", + MM_CAMCONVERT_TYPE_INT_PAIR_ARRAY, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_CAMERA, + MM_CAM_CAPTURE_WIDTH, + MM_CAM_CAPTURE_HEIGHT, + "CaptureResolution", + MM_CAMCONVERT_TYPE_INT_PAIR_ARRAY, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_CAMERA, + MM_CAM_CAMERA_FPS, + MM_CAMCORDER_ATTR_NONE, + "FPS", + MM_CAMCONVERT_TYPE_INT_ARRAY, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_CAMERA, + MM_CAM_CAMERA_FORMAT, + MM_CAMCORDER_ATTR_NONE, + "PictureFormat", + MM_CAMCONVERT_TYPE_INT_ARRAY, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_STROBE, + MM_CAM_STROBE_CONTROL, + MM_CAMCORDER_ATTR_NONE, + "StrobeControl", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_strobe_ctrl, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_STROBE, + MM_CAM_STROBE_CAPABILITIES, + MM_CAMCORDER_ATTR_NONE, + "StrobeCapabilities", + MM_CAMCONVERT_TYPE_INT_ARRAY, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_STROBE, + MM_CAM_STROBE_MODE, + MM_CAMCORDER_ATTR_NONE, + "StrobeMode", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_strobe_mode, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_EFFECT, + MM_CAM_FILTER_BRIGHTNESS, + MM_CAMCORDER_ATTR_NONE, + "Brightness", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_EFFECT, + MM_CAM_FILTER_CONTRAST, + MM_CAMCORDER_ATTR_NONE, + "Contrast", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_EFFECT, + MM_CAM_FILTER_SATURATION, + MM_CAMCORDER_ATTR_NONE, + "Saturation", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_EFFECT, + MM_CAM_FILTER_HUE, + MM_CAMCORDER_ATTR_NONE, + "Hue", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_EFFECT, + MM_CAM_FILTER_SHARPNESS, + MM_CAMCORDER_ATTR_NONE, + "Sharpness", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_EFFECT, + MM_CAM_FILTER_WB, + MM_CAMCORDER_ATTR_NONE, + "WhiteBalance", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_whitebalance, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_EFFECT, + MM_CAM_FILTER_COLOR_TONE, + MM_CAMCORDER_ATTR_NONE, + "ColorTone", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_colortone, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_EFFECT, + MM_CAM_CAMERA_WDR, + MM_CAMCORDER_ATTR_NONE, + "WDR", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_wdr_ctrl, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_DIGITAL_ZOOM, + MM_CAMCORDER_ATTR_NONE, + "DigitalZoom", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_OPTICAL_ZOOM, + MM_CAMCORDER_ATTR_NONE, + "OpticalZoom", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_FOCUS_MODE, + MM_CAMCORDER_ATTR_NONE, + "FocusMode", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_focus_mode, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_AF_SCAN_RANGE, + MM_CAMCORDER_ATTR_NONE, + "AFType", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_focus_type, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_EXPOSURE_MODE, + MM_CAMCORDER_ATTR_NONE, + "AEType", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_ae_type, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_EXPOSURE_VALUE, + MM_CAMCORDER_ATTR_NONE, + "ExposureValue", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_F_NUMBER, + MM_CAMCORDER_ATTR_NONE, + "FNumber", + MM_CAMCONVERT_TYPE_INT_ARRAY, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_SHUTTER_SPEED, + MM_CAMCORDER_ATTR_NONE, + "ShutterSpeed", + MM_CAMCONVERT_TYPE_INT_ARRAY, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_ISO, + MM_CAMCORDER_ATTR_NONE, + "ISO", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_iso, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_FILTER_SCENE_MODE, + MM_CAMCORDER_ATTR_NONE, + "ProgramMode", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_prgrm, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_PHOTOGRAPH, + MM_CAM_CAMERA_ANTI_HANDSHAKE, + MM_CAMCORDER_ATTR_NONE, + "AntiHandshake", + MM_CAMCONVERT_TYPE_INT_ARRAY, + &_mmcamcorder_enum_conv_ahs, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_CAPTURE, + MM_CAM_CAPTURE_FORMAT, + MM_CAMCORDER_ATTR_NONE, + "OutputMode", + MM_CAMCONVERT_TYPE_INT_ARRAY, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_CAPTURE, + MM_CAM_IMAGE_ENCODER_QUALITY, + MM_CAMCORDER_ATTR_NONE, + "JpegQuality", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_CAPTURE, + MM_CAM_CAPTURE_COUNT, + MM_CAMCORDER_ATTR_NONE, + "MultishotNumber", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_DETECT, + MM_CAM_DETECT_MODE, + MM_CAMCORDER_ATTR_NONE, + "DetectMode", + MM_CAMCONVERT_TYPE_INT_ARRAY, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_DETECT, + MM_CAM_DETECT_NUMBER, + MM_CAMCORDER_ATTR_NONE, + "DetectNumber", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_DETECT, + MM_CAM_DETECT_FOCUS_SELECT, + MM_CAMCORDER_ATTR_NONE, + "DetectFocusSelect", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_DETECT, + MM_CAM_DETECT_SELECT_NUMBER, + MM_CAMCORDER_ATTR_NONE, + "DetectSelectNumber", + MM_CAMCONVERT_TYPE_INT_RANGE, + NULL, + }, + { + CONFIGURE_TYPE_CTRL, + CONFIGURE_CATEGORY_CTRL_DETECT, + MM_CAM_DETECT_STATUS, + MM_CAMCORDER_ATTR_NONE, + "DetectStatus", + MM_CAMCONVERT_TYPE_INT_ARRAY, + NULL, + }, +}; + +/*--------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------*/ +/* STATIC INTERNAL FUNCTION */ +static int __mmcamcorder_set_info_to_attr( MMHandleType handle, _MMCamcorderInfoConverting *info, int table_size ); +static int __mmcamcorder_get_valid_array(int * original_array, int original_count, int ** valid_array, int * valid_default ); + +/*=========================================================================================== +| | +| FUNCTION DEFINITIONS | +| | +========================================================================================== */ +/*--------------------------------------------------------------------------- +| GLOBAL FUNCTION DEFINITIONS: | +---------------------------------------------------------------------------*/ +//convert MSL value to sensor value +int _mmcamcorder_convert_msl_to_sensor( int attr_idx, int mslval ) +{ + _MMCamcorderInfoConverting *info = NULL; + int i =0; + int size = sizeof(g_caminfo_convert) / sizeof(_MMCamcorderInfoConverting); + + //_mmcam_dbg_log("attr_idx(%d), mslval(%d)", attr_idx, mslval); + + info = g_caminfo_convert; + + for (i = 0; i < size; i++) + { + if (info[i].attr_idx == attr_idx) + { + _MMCamcorderEnumConvert * enum_convert = NULL; + enum_convert = info[i].enum_convert; + + if (enum_convert == NULL) + { + //_mmcam_dbg_log("enum_convert is NULL. Just return the original value."); + return mslval; + } + + if (enum_convert->enum_arr == NULL) + { + _mmcam_dbg_warn("Unexpected error. Array pointer of enum_convert is NULL. Just return the original value."); + return mslval; + } + + if( enum_convert->total_enum_num > mslval && mslval >= 0 ) + { + //_mmcam_dbg_log("original value(%d) -> converted value(%d)", mslval, enum_convert->enum_arr[mslval]); + return enum_convert->enum_arr[mslval]; + } + else + { + _mmcam_dbg_warn( "Input mslval[%d] is invalid(out of array[idx:%d,size:%d]), so can not convert. Just return the original value.", mslval, attr_idx, enum_convert->total_enum_num ); + return 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 i = 0, j = 0; + int size = sizeof(g_caminfo_convert) / sizeof(_MMCamcorderInfoConverting); + + _MMCamcorderInfoConverting *info = NULL; + + info = g_caminfo_convert; + + for( i = 0 ; i < size ; i++ ) + { + if( info[i].attr_idx == attr_idx ) + { + _MMCamcorderEnumConvert * enum_convert = NULL; + enum_convert = info[i].enum_convert; + + if( enum_convert == NULL ) + { + //_mmcam_dbg_log("enum_convert is NULL. Just return the original value."); + return sensval; + } + + if( enum_convert->enum_arr == NULL ) + { + _mmcam_dbg_warn("Unexpected error. Array pointer of enum_convert is NULL. Just return the original value."); + return sensval; + } + + for( j = 0 ; j < enum_convert->total_enum_num ; j++ ) + { + if( sensval == enum_convert->enum_arr[j] ) + { + //_mmcam_dbg_log("original value(%d) -> converted value(%d)", sensval, j); + return j; + } + } + + _mmcam_dbg_warn("There is no sensor value matched with input param. Just return the original value."); + return sensval; + + } + } + + _mmcam_dbg_log("There is no category to match. Just return the original value."); + return sensval; +} + +static int +__mmcamcorder_get_valid_array(int * original_array, int original_count, int ** valid_array, int * valid_default ) +{ + int i = 0; + int valid_count = 0; + int new_default = _MMCAMCORDER_SENSOR_ENUM_NONE; + + for (i = 0; i < original_count; i++) + { + if (original_array[i] != _MMCAMCORDER_SENSOR_ENUM_NONE) + valid_count++; + } + + if (valid_count > 0) + { + *valid_array = (int*)malloc(sizeof(int) * valid_count); + + valid_count = 0; + for (i = 0; i < original_count; i++) + { + if (original_array[i] != _MMCAMCORDER_SENSOR_ENUM_NONE) + { + (*valid_array)[valid_count++] = i; + //_mmcam_dbg_log( "valid_array[%d] = %d", valid_count-1, (*valid_array)[valid_count-1] ); + + if( original_array[i] == *valid_default ) + { + new_default = i; + //_mmcam_dbg_log( "converted MSL default[%d]", new_default ); + } + } + } + } + + if( new_default != _MMCAMCORDER_SENSOR_ENUM_NONE ) + { + *valid_default = new_default; + } + + return valid_count; +} + + +int _mmcamcorder_init_attr_from_configure(MMHandleType handle) +{ + _MMCamcorderInfoConverting *info = NULL; + + int table_size = 0; + int ret = MM_ERROR_NONE; + + _mmcam_dbg_log(""); + + /* Initialize attribute related to camera control */ + info = g_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 ) + { + _mmcam_dbg_err( "ret : %x", ret ); + return ret; + } + + /* Initialize attribute related to display */ + info = g_display_info; + table_size = sizeof(g_display_info) / sizeof(_MMCamcorderInfoConverting); + ret = __mmcamcorder_set_info_to_attr( handle, info, table_size ); + _mmcam_dbg_log( "result: %x", ret ); + + return ret; +} + +static int +__mmcamcorder_set_info_to_attr( MMHandleType handle, _MMCamcorderInfoConverting *info, int table_size ) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + MMHandleType attrs = 0; + + int i; + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + attrs = MMF_CAMCORDER_ATTRS (handle); + mmf_return_val_if_fail(attrs, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + camera_conf *conf_info = NULL; + + for (i = 0; i < table_size ; i++ ) + { + int ret = MM_ERROR_NONE; + + /* + _mmcam_dbg_log( "%d,%d,%d,%d,%s,%d", + info[i].type, + info[i].category, + info[i].attr_idx, + info[i].attr_idx_sub, + info[i].keyword, + info[i].conv_type ); + */ + + if( info[i].type == CONFIGURE_TYPE_MAIN ) + { + conf_info = hcamcorder->conf_main; + _mmcam_dbg_log( "MAIN configure [%s]", info[i].keyword ); + } + else + { + conf_info = hcamcorder->conf_ctrl; + _mmcam_dbg_log( "CTRL configure [%s]", info[i].keyword ); + } + + switch(info[i].conv_type) + { + case MM_CAMCONVERT_TYPE_INT: + { + int iarray = (int)NULL; + + if (!_mmcamcorder_conf_get_value_int( conf_info, info[i].category, info[i].keyword, &iarray )) + { + ret = MM_ERROR_CAMCORDER_CREATE_CONFIGURE; + break; //skip to set + } + + ret = mm_attrs_set_int(MMF_CAMCORDER_ATTRS(hcamcorder), info[i].attr_idx, iarray); + + //_mmcam_dbg_log("INT . m:%d, s:%d, arr=%d", info[i].main_key, info[i].sub_key1, iarray); + break; + } + case MM_CAMCONVERT_TYPE_INT_ARRAY: + { + int *iarray = NULL; + int iarray_size = 0; + int idefault = 0; + type_int_array *tarray = NULL; + + if (!_mmcamcorder_conf_get_value_int_array( conf_info, info[i].category, info[i].keyword, &tarray )) + { + ret = MM_ERROR_CAMCORDER_CREATE_CONFIGURE; + break; //skip to set + } + + if( tarray ) + { + idefault = tarray->default_value; + + if( info[i].enum_convert ) + { + iarray_size = __mmcamcorder_get_valid_array(tarray->value, tarray->count, &iarray, &idefault); + } + else + { + iarray = tarray->value; + iarray_size = tarray->count; + } + + if( iarray_size > 0 ) + { + /* + _mmcam_dbg_log("INT Array. m:%d, s:%d, arr=%x, size=%d, default=%d", + 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); + } + + ret = mm_attrs_set_int(MMF_CAMCORDER_ATTRS(hcamcorder), info[i].attr_idx, idefault); + } + + if (iarray && iarray != tarray->value ) + free(iarray); + + break; + } + case MM_CAMCONVERT_TYPE_INT_RANGE: + { + type_int_range *irange = NULL; + + if (!_mmcamcorder_conf_get_value_int_range(conf_info, info[i].category, info[i].keyword, &irange)) + { + ret = MM_ERROR_CAMCORDER_CREATE_CONFIGURE; + break; //skip to set + } + + if( irange ) + { + //_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); + + ret = mm_attrs_set_int(MMF_CAMCORDER_ATTRS(hcamcorder), info[i].attr_idx, irange->default_value); + } + + break; + } + case MM_CAMCONVERT_TYPE_STRING: + { + char* cString = NULL; + unsigned int iString_len = 0; + + if (!_mmcamcorder_conf_get_value_string(conf_info, info[i].category, info[i].keyword, &cString )) + { + ret = MM_ERROR_CAMCORDER_CREATE_CONFIGURE; + break; //skip to set + } + + //_mmcam_dbg_log("String. m:%d, s:%d, cString=%s", info[i].main_key, info[i].sub_key1, cString); + //strlen makes a crash when null pointer is passed. + if (cString) + iString_len = strlen(cString); + else + iString_len = 0; + + ret = mm_attrs_set_string(attrs, info[i].attr_idx, cString, iString_len); + break; + } + case MM_CAMCONVERT_TYPE_INT_PAIR_ARRAY: + { + type_int_pair_array *pair_array = NULL; + + //_mmcam_dbg_log("INT PAIR Array. type:%d, attr_idx:%d, attr_idx_pair:%d", info[i].type, info[i].attr_idx, info[i].attr_idx_pair); + + if (!_mmcamcorder_conf_get_value_int_pair_array(conf_info, info[i].category, info[i].keyword, &pair_array)) + { + ret = MM_ERROR_CAMCORDER_CREATE_CONFIGURE; + break; //skip to set + } + + 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); + + 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]); + } + break; + } + + case MM_CAMCONVERT_TYPE_USER: + default: + _mmcam_dbg_log("default : s:%d", info[i].attr_idx); + break; + } + + if (ret != MM_ERROR_NONE) + { + _mmcam_dbg_warn("Setting error. ( s:%d, ret:%x)", info[i].attr_idx, ret); + } + } + + if (mmf_attrs_commit(attrs) == -1) + return MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + else + return MM_ERROR_NONE; +} + + +int _mmcamcorder_set_converted_value(MMHandleType handle, _MMCamcorderEnumConvert * convert) +{ + mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle); + type_int_array *array = NULL; + + mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcamcorder_conf_get_value_int_array( hcamcorder->conf_ctrl, convert->category, convert->keyword, &array ); + + if( array ) + { + convert->enum_arr = array->value; + } + + return MM_ERROR_NONE; +} + + +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); + + return MM_ERROR_NONE; +} + + +double _mmcamcorder_convert_volume(int mslVal) +{ + double newVal = -1; + switch (mslVal) + { + case 0: + newVal = 0; + break; + case 1: + newVal = 1; + break; + default: + _mmcam_dbg_warn("out of range"); + break; + } + + return newVal; +} + + + diff --git a/src/mm_camcorder_sound.c b/src/mm_camcorder_sound.c new file mode 100644 index 0000000..c582349 --- /dev/null +++ b/src/mm_camcorder_sound.c @@ -0,0 +1,491 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include <mm_sound.h> +#include <mm_sound_private.h> +#include <audio-session-manager.h> +#include "mm_camcorder_internal.h" +#include "mm_camcorder_sound.h" + +/*--------------------------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------------------*/ +#define BLOCK_SIZE 2048 + +/*--------------------------------------------------------------------------------------- +| 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) +{ + mmf_return_val_if_fail(info, FALSE); + mmf_return_val_if_fail(filename, FALSE); + + info->infile = sf_open(filename, SFM_READ, &info->sfinfo); + if (!(info->infile)) { + _mmcam_dbg_err("failed to open file [%s]", filename); + return FALSE; + } + + _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; + } + sf_read_short(info->infile, info->pcm_buf, info->pcm_size); + + return TRUE; +} + + +static gboolean __cleanup_buffer(SOUND_INFO *info) +{ + mmf_return_val_if_fail(info, FALSE); + + if (info->infile) { + sf_close(info->infile); + info->infile = NULL; + } + + if (info->pcm_buf) { + free(info->pcm_buf); + info->pcm_buf = NULL; + } + + _mmcam_dbg_log("Done"); + + return TRUE; +} + + +static void *__sound_open_thread_func(void *data) +{ + int ret = 0; + system_audio_route_t route = SYSTEM_AUDIO_ROUTE_POLICY_HANDSET_ONLY; + SOUND_INFO *info = NULL; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data); + + mmf_return_val_if_fail(hcamcorder, NULL); + + MMTA_ACUM_ITEM_BEGIN(" __sound_open_thread_func", FALSE); + + info = &(hcamcorder->snd_info); + + __ta__(" __prepare_buffer", + ret = __prepare_buffer(info, info->filename); + ); + if (ret == FALSE) { + goto EXIT_FUNC; + } + + __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); + } + + 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; + } + + _mmcam_dbg_log("current policy [%d]", route); + + 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; + } + + info->route_policy_backup = route; + } + +EXIT_FUNC: + pthread_cond_signal(&(info->open_cond)); + pthread_mutex_unlock(&(info->open_mutex)); + + _mmcam_dbg_log("Done"); + + MMTA_ACUM_ITEM_END(" __sound_open_thread_func", FALSE); + + return NULL; + +POLICY_ERROR: + pthread_mutex_unlock(&(info->open_mutex)); + _mmcamcorder_sound_finalize((MMHandleType)hcamcorder); + + return NULL; +} + + +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); + + mmf_return_val_if_fail(hcamcorder, NULL); + + info = &(hcamcorder->snd_info); + + _mmcam_dbg_log("RUN sound write thread"); + + pthread_mutex_lock(&(info->play_mutex)); + + do { + pthread_cond_wait(&(info->play_cond), &(info->play_mutex)); + + _mmcam_dbg_log("Signal received. Play sound."); + + if (info->thread_run == FALSE) { + _mmcam_dbg_log("Exit thread command is detected"); + break; + } + + 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); + + 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; + } + + info->route_policy_backup = route; + } + + buffer_to_write = (char *)info->pcm_buf; + remain_bytes = info->pcm_size; + bytes_to_write = 0; + + 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); + } + remain_bytes -= bytes_to_write; + buffer_to_write += bytes_to_write; + } + } while (TRUE); + + pthread_mutex_unlock(&(info->play_mutex)); + + _mmcam_dbg_log("END sound write thread"); + + return NULL; +} + + +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); + + info = &(hcamcorder->snd_info); + + 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 FALSE; + } + + if (info->filename) { + free(info->filename); + info->filename = NULL; + } + + 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; + } + } + + pthread_mutex_unlock(&(info->open_mutex)); + + return ret; +} + + +gboolean _mmcamcorder_sound_prepare(MMHandleType handle) +{ + int ret = FALSE; + pthread_t open_thread; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + SOUND_INFO *info = NULL; + + mmf_return_val_if_fail(hcamcorder, FALSE); + + 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; + pthread_mutex_unlock(&(info->open_mutex)); + } + + return ret; +} + + +gboolean _mmcamcorder_sound_play(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + SOUND_INFO *info = NULL; + + mmf_return_val_if_fail(hcamcorder, FALSE); + + info = &(hcamcorder->snd_info); + + pthread_mutex_lock(&(info->open_mutex)); + + if (info->state < _MMCAMCORDER_SOUND_STATE_PREPARE) { + _mmcam_dbg_log("not initialized state:[%d]", info->state); + pthread_mutex_unlock(&(info->open_mutex)); + return FALSE; + } + + _mmcam_dbg_log("Play start"); + + pthread_mutex_lock(&(info->play_mutex)); + pthread_cond_signal(&(info->play_cond)); + pthread_mutex_unlock(&(info->play_mutex)); + + pthread_mutex_unlock(&(info->open_mutex)); + + _mmcam_dbg_log("Done"); + + return TRUE; +} + + +gboolean _mmcamcorder_sound_finalize(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + SOUND_INFO *info = NULL; + + mmf_return_val_if_fail(hcamcorder, FALSE); + + info = &(hcamcorder->snd_info); + + 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; + } + + info->thread_run = 0; + pthread_cond_signal(&(info->play_cond)); + + if (info->thread) { + _mmcam_dbg_log("wait for sound write thread join"); + pthread_join(info->thread, NULL); + _mmcam_dbg_log("join done"); + } + + if (info->state == _MMCAMCORDER_SOUND_STATE_PREPARE) { + _mmcam_dbg_log("restore route policy [%d]", info->route_policy_backup); + + if (info->route_policy_backup != -1) { + mm_sound_route_set_system_policy(info->route_policy_backup); + } + + mm_sound_pcm_play_close(info->handle); + __cleanup_buffer(info); + } + + if (info->filename) { + free(info->filename); + info->filename = NULL; + } + + info->state = _MMCAMCORDER_SOUND_STATE_NONE; + info->route_policy_backup = -1; + + pthread_mutex_destroy(&(info->play_mutex)); + pthread_cond_destroy(&(info->play_cond)); + + pthread_mutex_unlock(&(info->open_mutex)); + + _mmcam_dbg_log("Done"); + + return TRUE; +} + + +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 sound_enable = TRUE; + + mmf_return_if_fail( filepath ); + + _mmcam_dbg_log( "START" ); + + 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); + } + + ret = pthread_mutex_trylock(&(hcamcorder->sound_lock)); + if (ret != 0) { + _mmcam_dbg_warn("g_mutex_trylock failed.[%s]", strerror(ret)); + return; + } + + MMTA_ACUM_ITEM_BEGIN("CAPTURE SOUND:mm_sound_play_loud_solo_sound", FALSE); + + ret = mm_sound_play_loud_solo_sound(filepath, VOLUME_TYPE_FIXED, __solo_sound_callback, + (void*)hcamcorder, &sound_handle); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err( "Capture sound play FAILED.[%x]", ret ); + } else { + if (sync) { + struct timespec timeout; + struct timeval tv; + + gettimeofday( &tv, NULL ); + timeout.tv_sec = tv.tv_sec + 2; + timeout.tv_nsec = tv.tv_usec * 1000; + + _mmcam_dbg_log("Wait for signal"); + + if (!pthread_cond_timedwait(&(hcamcorder->sound_cond), &(hcamcorder->sound_lock), &timeout)) { + _mmcam_dbg_log("signal received."); + } else { + _mmcam_dbg_warn("capture sound play timeout."); + if (sound_handle > 0) { + mm_sound_stop_sound(sound_handle); + } + } + } + } + + MMTA_ACUM_ITEM_END("CAPTURE SOUND:mm_sound_play_loud_solo_sound", FALSE); + + pthread_mutex_unlock(&(hcamcorder->sound_lock)); + + _mmcam_dbg_log("DONE"); + + return; +} + +static void __solo_sound_callback(void *data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(data); + + mmf_return_if_fail(hcamcorder); + + _mmcam_dbg_log("START"); + + _mmcam_dbg_log("Signal SEND"); + pthread_cond_broadcast(&(hcamcorder->sound_cond)); + + _mmcam_dbg_log("DONE"); + + return; +} + diff --git a/src/mm_camcorder_stillshot.c b/src/mm_camcorder_stillshot.c new file mode 100644 index 0000000..f6ef4fe --- /dev/null +++ b/src/mm_camcorder_stillshot.c @@ -0,0 +1,2815 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include <sys/time.h> +#include <sys/times.h> +#include <gst/interfaces/cameracontrol.h> +#include "mm_camcorder_internal.h" +#include "mm_camcorder_stillshot.h" +#include "mm_camcorder_exifinfo.h" +#include "mm_camcorder_exifdef.h" + +/*--------------------------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------------------*/ +#define EXIF_SET_ERR( return_type,tag_id) \ + _mmcam_dbg_err("error=%x,tag=%x",return_type,tag_id); \ + if (return_type == MM_ERROR_CAMCORDER_LOW_MEMORY) { \ + goto exit; \ + } + +/*--------------------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------------------*/ + + +/*--------------------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------------------*/ +/** STATIC INTERNAL FUNCTION **/ +/* Functions for JPEG capture without Encode bin */ +int _mmcamcorder_image_cmd_capture(MMHandleType handle); +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); +static gboolean __mmcamcorder_encodesink_handoff_callback(GstElement *fakesink, GstBuffer *buffer, GstPad *pad, gpointer u_data); + +/*======================================================================================= +| FUNCTION DEFINITIONS | +=======================================================================================*/ + +/*--------------------------------------------------------------------------------------- +| GLOBAL FUNCTION DEFINITIONS: | +---------------------------------------------------------------------------------------*/ + + +int _mmcamcorder_add_stillshot_pipeline(MMHandleType handle) +{ + int err = MM_ERROR_UNKNOWN; + + GstPad *srcpad = NULL; + GstPad *sinkpad = NULL; + + 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); + + info = sc->info; + + _mmcam_dbg_log(""); + + //Create gstreamer element + //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; + } + + _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); + + /* 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_ENCSINK_SINK].gst, + _MMCAMCORDER_HANDLER_STILLSHOT, "handoff", + G_CALLBACK(__mmcamcorder_encodesink_handoff_callback), + hcamcorder); + } else { + _mmcam_dbg_log("NOT using Encodebin for capturing"); + + /*set video source element*/ + 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; + +element_link_error: + if (sc->bencbin_capture) { + _mmcam_dbg_err("Link encodebin failed!"); + + 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; */ + } + + 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); + + _mmcam_dbg_log("Encodebin removed"); + } + } + + return MM_ERROR_CAMCORDER_GST_LINK; + +pipeline_creation_error: + return err; +} + + +int _mmcamcorder_remove_stillshot_pipeline(MMHandleType 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); + + info = sc->info; + + _mmcam_dbg_log(""); + + /* Check pipeline */ + if (sc->element[_MMCAMCORDER_MAIN_PIPE].gst) { + _mmcamcorder_remove_all_handlers(handle, _MMCAMCORDER_HANDLER_STILLSHOT); + + if (sc->bencbin_capture) { + GstPad *srcpad = NULL, *sinkpad = NULL; + if (!sc->element[_MMCAMCORDER_ENCSINK_BIN].gst) { + _mmcam_dbg_log("ENCSINK_BIN is already removed"); + } else { + /* 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); + + 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); + } + } + } else { + _mmcam_dbg_log("MAIN_PIPE is already removed"); + } + + return MM_ERROR_NONE; +} + + +void _mmcamcorder_destroy_image_pipeline(MMHandleType handle) +{ + GstPad *reqpad1 = NULL; + GstPad *reqpad2 = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_if_fail(hcamcorder); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_if_fail(sc && sc->element); + + _mmcam_dbg_log(""); + + if (sc->element[_MMCAMCORDER_MAIN_PIPE].gst) { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE); + _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_NULL); + + _mmcamcorder_remove_all_handlers(handle, _MMCAMCORDER_HANDLER_CATEGORY_ALL); + + reqpad1 = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, "src0"); + reqpad2 = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, "src1"); + gst_element_release_request_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, reqpad1); + gst_element_release_request_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, reqpad2); + 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; */ + } +} + + +int _mmcamcorder_image_cmd_capture(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_NV12; + int cap_jpeg_quality = 0; + int image_encoder = MM_IMAGE_CODEC_JPEG; + unsigned int cap_fourcc = 0; + + char *err_name = NULL; + char *videosrc_name = NULL; + + GstElement *pipeline = NULL; + GstCameraControl *control = NULL; + GstCaps *caps = NULL; + GstClock *clock = 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(handle); + 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); + + /* 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; + } + + 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->next_shot_time = 0; + info->multi_shot_stop = FALSE; + } + + 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")) { + /* 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; + } + + cap_fourcc = _mmcamcorder_get_fourcc(raw_capture_format, image_encoder, hcamcorder->use_zero_copy_format); + sc->internal_encode = TRUE; + + _mmcam_dbg_log("MSL JPEG Capture"); + } + } else { + cap_fourcc = _mmcamcorder_get_fourcc(cap_format, MM_IMAGE_CODEC_INVALID, hcamcorder->use_zero_copy_format); + if (info->type == _MMCamcorder_SINGLE_SHOT && !strcmp(videosrc_name, "camerasrc")) { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE ); + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", TRUE ); + } + } + + _mmcam_dbg_log("capture format (%d), jpeg quality (%d)", cap_format, cap_jpeg_quality); + + /* 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); + + 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; + } + + 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; + + 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; + } + } + + if (need_change) { + _mmcam_dbg_log("Need to change resolution"); + + if (UseCaptureMode) { + set_width = MMFCAMCORDER_HIGHQUALITY_WIDTH; + set_height = MMFCAMCORDER_HIGHQUALITY_HEIGHT; + } else { + set_width = info->width; + set_height = info->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, fps, 1, + "rotate", G_TYPE_INT, 0, + NULL); + if (caps == NULL) { + _mmcam_dbg_err("failed to create caps"); + ret = MM_ERROR_CAMCORDER_LOW_MEMORY; + 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, "num-buffers", info->count);*/ + 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)); + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", FALSE); + + _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); + } + } + + /* 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(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; + gboolean fps_auto = FALSE; + char *err_name = NULL; + char *videosrc_name = NULL; + + GstState state; + 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(handle); + 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_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE); + + _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; + + /* 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; + } + + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "fps-auto", fps_auto); + + if (_mmcamcorder_get_state(handle) == 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; + } + + control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst); + gst_camera_control_set_capture_command(control, GST_CAMERA_CONTROL_CAPTURE_COMMAND_STOP); + + current_framecount = sc->kpi.video_framecount; + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "stop-video", FALSE); + if (info->type == _MMCamcorder_SINGLE_SHOT) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); + } + } + } 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; + } + + if (_mmcamcorder_get_state((MMHandleType)hcamcorder) == 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) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_FILT].gst, "caps", caps); + gst_caps_unref(caps); + _mmcam_dbg_log("Rollback to original resolution(%d, %d)", width, height); + } else { + _mmcam_dbg_err("failed to create caps"); + ret = MM_ERROR_CAMCORDER_LOW_MEMORY; + goto cmd_error; + } + } + } + + gst_element_get_state(pipeline, &state, NULL, -1); + + if (state == GST_STATE_PLAYING) { + 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->type == _MMCamcorder_MULTI_SHOT) { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); + } + + _mmcam_dbg_log("Wait Frame Done. count before[%d],after[%d], try_count[%d]", + current_framecount, sc->kpi.video_framecount, try_count); + } else { + 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); + 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); + + 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); + + 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; + } + + 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; + + 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; + } + } + + if (need_change) { + _mmcam_dbg_log("Need to change resolution"); + + if (UseCaptureMode) { + set_width = MMFCAMCORDER_HIGHQUALITY_WIDTH; + set_height = MMFCAMCORDER_HIGHQUALITY_HEIGHT; + } else { + set_width = info->width; + set_height = info->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, fps, 1, + "rotate", G_TYPE_INT, 0, + NULL); + if (caps == NULL) { + _mmcam_dbg_err("failed to create caps"); + ret = MM_ERROR_CAMCORDER_LOW_MEMORY; + 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; + } + + /* 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; + + 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); + 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); + } + } + + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", FALSE); + + gst_element_get_state(pipeline, &state, NULL, -1); + + 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); + } + ); + + _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; + } + + 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); + } + } 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; + } + } + +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 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; + + /* 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); + ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_READY); + if (ret != MM_ERROR_NONE) { + goto cmd_error; + } + +cmd_error: + return ret; +} + + +int _mmcamcorder_image_command(MMHandleType handle, int command) +{ + int ret = MM_ERROR_NONE; + + 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); + + _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? */ + 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); + } + /* 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); + } + break; + default: + ret = MM_ERROR_CAMCORDER_INVALID_ARGUMENT; + break; + } + + if (ret != MM_ERROR_NONE && sc->element && 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); + } + + return ret; +} + + +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; + + mmf_return_if_fail(hcamcorder); + + sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + mmf_return_if_fail(sc && sc->info); + + info = sc->info; + type = info->type; + + _mmcam_dbg_log("capture type[%d], capture send count[%d]", type, info->capture_send_count); + + if (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 ret = MM_ERROR_NONE; + unsigned char *data = NULL; + unsigned int datalen = 0; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + + mmf_return_val_if_fail(hcamcorder, FALSE); + + _mmcam_dbg_log(""); + + if (!original || original->data == NULL || original->length == 0) { + _mmcam_dbg_err("original=%p, data=%p, length=%d", original, original->data, original->length); + return FALSE; + } 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) { + _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); + ); + 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); + } + } + + /* 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; + } +} + + +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; +} + + +void __mmcamcorder_get_capture_data_from_buffer(MMCamcorderCaptureDataType *capture_data, int pixtype, GstBuffer *buffer) +{ + GstCaps *caps = NULL; + const GstStructure *structure; + + mmf_return_if_fail(capture_data && buffer); + + caps = gst_buffer_get_caps(buffer); + if (caps == NULL) { + _mmcam_dbg_err("failed to get caps"); + goto GET_FAILED; + } + + structure = gst_caps_get_structure(caps, 0); + if (caps == NULL) { + _mmcam_dbg_err("failed to get structure"); + goto GET_FAILED; + } + + capture_data->data = GST_BUFFER_DATA(buffer); + capture_data->format = pixtype; + gst_structure_get_int(structure, "width", &capture_data->width); + 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); + gst_caps_unref(caps); + caps = NULL; + + return; + +GET_FAILED: + capture_data->data = NULL; + capture_data->format = MM_PIXEL_FORMAT_INVALID; + capture_data->length = 0; + + return; +} + + +gboolean __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); + + sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + mmf_return_val_if_fail(sc, FALSE); + + _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; + } + } + } + + return TRUE; +} + + +void __mmcamcorder_release_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType *dest) +{ + int tag_enable = 0; + int provide_exif = FALSE; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_if_fail(hcamcorder); + mmf_return_if_fail(dest); + + sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + mmf_return_if_fail(sc); + + _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); + + /* if dest->data is allocated in MSL, release it */ + if (tag_enable && !provide_exif) { + if (dest->data) { + free(dest->data); + dest->length = 0; + dest->data = NULL; + _mmcam_dbg_log("Jpeg is released!"); + } + } else { + _mmcam_dbg_log("No need to release"); + } + + return; +} + + +static void __mmcamcorder_image_capture_cb(GstElement *element, GstBuffer *buffer1, GstBuffer *buffer2, GstBuffer *buffer3, gpointer u_data) +{ + int ret = MM_ERROR_NONE; + 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; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); + _MMCamcorderImageInfo *info = NULL; + _MMCamcorderSubContext *sc = NULL; + MMCamcorderCaptureDataType dest = {0,}; + MMCamcorderCaptureDataType thumb = {0,}; + MMCamcorderCaptureDataType scrnail = {0,}; + + mmf_attrs_t *attrs = NULL; + mmf_attribute_t *item = NULL; + + void *encoded_data = NULL; + char *err_attr_name = NULL; + + mmf_return_if_fail(hcamcorder); + + sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + mmf_return_if_fail(sc && sc->info); + + info = sc->info; + + _mmcam_dbg_err("START"); + + 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; + } + + /* play capture sound here if multi capture */ + if (info->type == _MMCamcorder_MULTI_SHOT) { + _mmcamcorder_sound_play((MMHandleType)hcamcorder); + } + + /* Prepare main, thumbnail buffer */ + pixtype = _mmcamcorder_get_pixel_format(buffer1); + if (pixtype == MM_PIXEL_FORMAT_INVALID) { + _mmcam_dbg_err("Unsupported pixel type"); + goto error; + } + + /* Main image buffer */ + if (buffer1 && GST_BUFFER_DATA(buffer1) && (GST_BUFFER_SIZE(buffer1) !=0)) { + __mmcamcorder_get_capture_data_from_buffer(&dest, pixtype, buffer1); + } else { + _mmcam_dbg_err("buffer1 has wrong pointer. (buffer1=%p)",buffer1); + 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", + ret = _mmcamcorder_encode_jpeg(GST_BUFFER_DATA(buffer1), dest.width, dest.height, + pixtype, dest.length, capture_quality, &(dest.data), &(dest.length)); + ); + if (ret == FALSE) { + goto error; + } + + encoded_data = dest.data; + 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); + + __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]; + + if (buffer3 && GST_BUFFER_DATA(buffer3) && GST_BUFFER_SIZE(buffer3) != 0) { + _mmcam_dbg_log("Screennail (buffer3=%p,size=%d)", buffer3, GST_BUFFER_SIZE(buffer3)); + + pixtype_sub = _mmcamcorder_get_pixel_format(buffer3); + __mmcamcorder_get_capture_data_from_buffer(&scrnail, pixtype_sub, buffer3); + + /* Set screennail attribute for application */ + mmf_attribute_set_data(item, &scrnail, sizeof(scrnail)); + } else { + mmf_attribute_set_data(item, NULL, 0); + + _mmcam_dbg_log("buffer3 has wrong pointer. Not Error. (buffer3=%p)",buffer3); + } + + mmf_attrs_commit_err((MMHandleType)attrs, &err_attr_name); + + /* Set extra data for jpeg */ + if (dest.format == MM_PIXEL_FORMAT_ENCODED) { + int err = 0; + char *err_attr_name = NULL; + + 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; + } + + switch (codectype) { + case MM_IMAGE_CODEC_JPEG: + case MM_IMAGE_CODEC_SRW: + case MM_IMAGE_CODEC_JPEG_SRW: + __ta__( " __mmcamcorder_set_jpeg_data", + ret = __mmcamcorder_set_jpeg_data((MMHandleType)hcamcorder, &dest, &thumb); + ); + if (!ret) { + _mmcam_dbg_err("Error on setting extra data to jpeg"); + goto error; + } + break; + default: + _mmcam_dbg_err("The codectype is not supported. (%d)", codectype); + goto error; + } + } + + /* Handle Capture Callback */ + _MMCAMCORDER_LOCK_VCAPTURE_CALLBACK(hcamcorder); + + if (hcamcorder->vcapture_cb) { + _mmcam_dbg_log("APPLICATION CALLBACK START"); + MMTA_ACUM_ITEM_BEGIN(" Application capture callback", 0); + if (thumb.data) { + ret = hcamcorder->vcapture_cb(&dest, &thumb, hcamcorder->vcapture_cb_param); + } else { + ret = hcamcorder->vcapture_cb(&dest, NULL, hcamcorder->vcapture_cb_param); + } + MMTA_ACUM_ITEM_END(" Application capture callback", 0); + _mmcam_dbg_log("APPLICATION CALLBACK END"); + } else { + _mmcam_dbg_err("Capture callback is NULL."); + goto err_release_exif; + } + + /* Set send msg flag and capture count */ + send_msg = TRUE; + type = info->type; + count = ++(info->capture_send_count); + +err_release_exif: + _MMCAMCORDER_UNLOCK_VCAPTURE_CALLBACK(hcamcorder); + + /* Release jpeg data */ + if (pixtype == MM_PIXEL_FORMAT_ENCODED) { + __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); + } + + /* release internal allocated data */ + if (encoded_data) { + if (dest.data == encoded_data) { + dest.data = NULL; + } + + free(encoded_data); + encoded_data = NULL; + } + + /*free GstBuffer*/ + if (buffer1) { + gst_buffer_unref(buffer1); + } + if (buffer2) { + gst_buffer_unref(buffer2); + } + if (buffer3) { + gst_buffer_unref(buffer3); + } + + MMTA_ACUM_ITEM_END( " MSL capture callback", FALSE ); + + _mmcam_dbg_err("END"); + + return; +} + + +static gboolean __mmcamcorder_encodesink_handoff_callback(GstElement *fakesink, GstBuffer *buffer, GstPad *pad, gpointer u_data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); + _MMCamcorderSubContext *sc = NULL; + + mmf_return_val_if_fail(hcamcorder, FALSE); + + sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder); + mmf_return_val_if_fail(sc && sc->element, FALSE); + + _mmcam_dbg_log(""); + + /* FIXME. How could you get a thumbnail? */ + __mmcamcorder_image_capture_cb(fakesink, buffer, NULL, NULL, u_data); + + if (sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst) { + 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 TRUE; +} + + +/* Take a picture with capture mode */ +int _mmcamcorder_set_resize_property(MMHandleType handle, int capture_width, int capture_height) +{ + int ELEMENT_CROP = 0; + int ELEMENT_FILTER = 0; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + _mmcam_dbg_log(""); + + 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); + + ELEMENT_CROP = _MMCAMCORDER_ENCSINK_ICROP; + ELEMENT_FILTER = _MMCAMCORDER_ENCSINK_IFILT; + + /*TODO: this is not needed now. */ + + return MM_ERROR_NONE; +} + + +int __mmcamcorder_set_exif_basic_info(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + int value; + int str_val_len = 0; + int gps_enable = TRUE; + int cntl = 0; + int cnts = 0; + double f_latitude = INVALID_GPS_VALUE; + double f_longitude = INVALID_GPS_VALUE; + double f_altitude = INVALID_GPS_VALUE; + char *str_value = NULL; + char *maker = NULL; + char *user_comment = NULL; + char *err_name = NULL; + ExifData *ed = NULL; + ExifLong config; + ExifLong ExifVersion; + static ExifShort eshort[20]; + static ExifLong elong[10]; + + GstCameraControl *control = NULL; + GstCameraControlExifInfo avsys_exif_info = {0,}; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + _mmcam_dbg_log(""); + + 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); + + 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; + } + + 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 */ + 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; + } + + /* Receive attribute info */ + + /* START INSERT IFD_0 */ + + /*0. EXIF_TAG_EXIF_VERSION */ + ExifVersion = MM_EXIF_VERSION; + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_EXIF_VERSION, + EXIF_FORMAT_UNDEFINED, 4, (unsigned char *)&ExifVersion); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_EXIF_VERSION); + } + + /*1. EXIF_TAG_IMAGE_WIDTH */ /*EXIF_TAG_PIXEL_X_DIMENSION*/ + mm_camcorder_get_attributes(handle, NULL, MMCAM_CAPTURE_WIDTH, &value, NULL); + + 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, + EXIF_FORMAT_LONG, 1, (unsigned char *)&elong[cntl]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_IMAGE_WIDTH); + } + + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_PIXEL_X_DIMENSION, + EXIF_FORMAT_LONG, 1, (unsigned char *)&elong[cntl++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_PIXEL_X_DIMENSION); + } + _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); + + 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, + EXIF_FORMAT_LONG, 1, (unsigned char *)&elong[cntl]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_IMAGE_LENGTH); + } + + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_PIXEL_Y_DIMENSION, + EXIF_FORMAT_LONG, 1, (unsigned char *)&elong[cntl++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_PIXEL_Y_DIMENSION); + } + _mmcam_dbg_log("height[%d]", value); + + /*4. EXIF_TAG_DATE_TIME */ + + /*12. EXIF_TAG_DATE_TIME_ORIGINAL */ + + /*13. EXIF_TAG_DATE_TIME_DIGITIZED*/ + { + unsigned char *b; + time_t t; + struct tm tm; + + b = malloc(20 * sizeof(unsigned char)); + if (b == NULL) { + _mmcam_dbg_err("failed to alloc b"); + ret = MM_ERROR_CAMCORDER_LOW_MEMORY; + EXIF_SET_ERR(ret, EXIF_TAG_DATE_TIME); + } + + memset(b, '\0', 20); + + t = time(NULL); + tzset(); + localtime_r(&t, &tm); + + snprintf((char *)b, 20, "%04i:%02i:%02i %02i:%02i:%02i", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + + ret = mm_exif_set_add_entry(ed, EXIF_IFD_0, EXIF_TAG_DATE_TIME, EXIF_FORMAT_ASCII, 20, b); + if (ret != MM_ERROR_NONE) { + if (ret == MM_ERROR_CAMCORDER_LOW_MEMORY) { + free(b); + } + EXIF_SET_ERR(ret, EXIF_TAG_DATE_TIME); + } + + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_FORMAT_ASCII, 20, b); + if (ret != MM_ERROR_NONE) { + if (ret == MM_ERROR_CAMCORDER_LOW_MEMORY) { + free(b); + } + EXIF_SET_ERR(ret, EXIF_TAG_DATE_TIME_ORIGINAL); + } + + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_FORMAT_ASCII, 20, b); + if (ret != MM_ERROR_NONE) { + if (ret == MM_ERROR_CAMCORDER_LOW_MEMORY) { + free(b); + } + EXIF_SET_ERR(ret, EXIF_TAG_DATE_TIME_DIGITIZED); + } + + free(b); + } + + /*5. EXIF_TAG_MAKE */ + maker = strdup(MM_MAKER_NAME); + if (maker) { + _mmcam_dbg_log("maker [%s]", maker); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_0, EXIF_TAG_MAKE, + EXIF_FORMAT_ASCII, strlen(maker), (unsigned char *)maker); + free(maker); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_MAKE); + } + } else { + ret = MM_ERROR_CAMCORDER_LOW_MEMORY; + EXIF_SET_ERR(ret, EXIF_TAG_MAKE); + } + + /*6. EXIF_TAG_MODEL */ + _mmcamcorder_conf_get_value_string(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_GENERAL, + "ModelName", + &str_value); + _mmcam_dbg_log("model_name [%s]", str_value); + if (str_value) { + char *model = strdup(str_value); + mm_exif_set_add_entry(ed,EXIF_IFD_0,EXIF_TAG_MODEL,EXIF_FORMAT_ASCII,strlen(model)+1, (unsigned char*)model); + free(model); + str_value = NULL; + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_MODEL); + } + } else { + _mmcam_dbg_warn("failed to get model name"); + } + + /*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); + if (str_value && str_val_len > 0) { + char *description = strdup(str_value); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_0, EXIF_TAG_IMAGE_DESCRIPTION, + EXIF_FORMAT_ASCII, strlen(description), (unsigned char *)description); + free(description); + str_value = NULL; + str_val_len = 0; + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_IMAGE_DESCRIPTION); + } + } else { + _mmcam_dbg_warn("failed to get description"); + } + + /*7. EXIF_TAG_SOFTWARE*/ +/* + { + char software[50] = {0,}; + unsigned int len = 0; + + len = snprintf(software, sizeof(software), "%x.%x ", avsys_exif_info.software_used>>8,(avsys_exif_info.software_used & 0xff)); + _mmcam_dbg_log("software [%s], len [%d]", software, len); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_0, EXIF_TAG_SOFTWARE, + EXIF_FORMAT_ASCII, len, software); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_SOFTWARE); + } + } +*/ + + /*8. EXIF_TAG_ORIENTATION */ + mm_camcorder_get_attributes(handle, NULL, MMCAM_TAG_ORIENTATION, &value, NULL); + + _mmcam_dbg_log("orientation [%d]",value); + if (value == 0) { + value = MM_EXIF_ORIENTATION; + } + + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed), value); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_0, EXIF_TAG_ORIENTATION, + EXIF_FORMAT_SHORT, 1, (unsigned char*)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_ORIENTATION); + } + + /* START INSERT EXIF_IFD */ + + /*3. User Comment*/ + /*FIXME : get user comment from real user */ + user_comment = strdup(MM_USER_COMMENT); + if (user_comment) { + _mmcam_dbg_log("user_comment=%s",user_comment); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_USER_COMMENT, + EXIF_FORMAT_ASCII, strlen(user_comment), (unsigned char *)user_comment); + free(user_comment); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_USER_COMMENT); + } + } else { + ret = MM_ERROR_CAMCORDER_LOW_MEMORY; + EXIF_SET_ERR(ret, EXIF_TAG_USER_COMMENT); + } + + /*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); + } + + /*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); + } + + /*11. EXIF_TAG_COMPRESSED_BITS_PER_PIXEL */ + /* written the device_info */ + + /*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; + ExifRational rData; + + _mmcam_dbg_log("EXIF_TAG_EXPOSURE_TIME numerator [%d], denominator [%d]", + avsys_exif_info.exposure_time_numerator, avsys_exif_info.exposure_time_denominator) + + b = malloc(sizeof(ExifRational)); + if (b) { + rData.numerator = avsys_exif_info.exposure_time_numerator; + rData.denominator = avsys_exif_info.exposure_time_denominator; + + exif_set_rational(b, exif_data_get_byte_order(ed), rData); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, + EXIF_FORMAT_RATIONAL, 1, b); + free(b); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_EXPOSURE_TIME); + } + } else { + _mmcam_dbg_warn("malloc failed."); + } + } else { + _mmcam_dbg_log("Skip set EXIF_TAG_EXPOSURE_TIME numerator [%d], denominator [%d]", + avsys_exif_info.exposure_time_numerator, avsys_exif_info.exposure_time_denominator); + } + + /*15. EXIF_TAG_FNUMBER */ + if (avsys_exif_info.aperture_f_num_numerator && avsys_exif_info.aperture_f_num_denominator) { + unsigned char *b = NULL; + ExifRational rData; + + _mmcam_dbg_log("EXIF_TAG_FNUMBER numerator [%d], denominator [%d]", + avsys_exif_info.aperture_f_num_numerator, avsys_exif_info.aperture_f_num_denominator); + + b = malloc(sizeof(ExifRational)); + if (b) { + rData.numerator = avsys_exif_info.aperture_f_num_numerator; + rData.denominator = avsys_exif_info.aperture_f_num_denominator; + exif_set_rational(b, exif_data_get_byte_order(ed), rData); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, + EXIF_FORMAT_RATIONAL, 1, b); + free(b); + if(ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_FNUMBER); + } + } else { + _mmcam_dbg_warn( "malloc failed." ); + } + } else { + _mmcam_dbg_log("Skip set EXIF_TAG_FNUMBER numerator [%d], denominator [%d]", + avsys_exif_info.aperture_f_num_numerator, avsys_exif_info.aperture_f_num_denominator); + } + + /*16. EXIF_TAG_EXPOSURE_PROGRAM*/ + /*FIXME*/ + value = MM_EXPOSURE_PROGRAM; + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed), value); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_PROGRAM, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_EXPOSURE_PROGRAM); + } + + /*17. EXIF_TAG_ISO_SPEED_RATINGS*/ + if (avsys_exif_info.iso) { + _mmcam_dbg_log("EXIF_TAG_ISO_SPEED_RATINGS [%d]", avsys_exif_info.iso); + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed), avsys_exif_info.iso); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_ISO_SPEED_RATINGS, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_ISO_SPEED_RATINGS); + } + } + + /*18. EXIF_TAG_SHUTTER_SPEED_VALUE*/ + if (avsys_exif_info.shutter_speed_numerator && avsys_exif_info.shutter_speed_denominator) { + unsigned char *b = NULL; + ExifSRational rsData; + + _mmcam_dbg_log("EXIF_TAG_SHUTTER_SPEED_VALUE numerator [%d], denominator [%d]", + avsys_exif_info.shutter_speed_numerator, avsys_exif_info.shutter_speed_denominator); + + b = malloc(sizeof(ExifSRational)); + if (b) { + rsData.numerator = avsys_exif_info.shutter_speed_numerator; + rsData.denominator = avsys_exif_info.shutter_speed_denominator; + exif_set_srational(b, exif_data_get_byte_order(ed), rsData); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_SHUTTER_SPEED_VALUE, + EXIF_FORMAT_SRATIONAL, 1, b); + free(b); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_SHUTTER_SPEED_VALUE); + } + } else { + _mmcam_dbg_warn("malloc failed."); + } + } else { + _mmcam_dbg_log("Skip set EXIF_TAG_SHUTTER_SPEED_VALUE numerator [%d], denominator [%d]", + avsys_exif_info.shutter_speed_numerator, avsys_exif_info.shutter_speed_denominator); + } + + /*19. EXIF_TAG_APERTURE_VALUE*/ + if (avsys_exif_info.aperture_in_APEX) { + unsigned char *b = NULL; + ExifRational rData; + + _mmcam_dbg_log("EXIF_TAG_APERTURE_VALUE [%d]", avsys_exif_info.aperture_in_APEX); + + b = malloc(sizeof(ExifRational)); + if (b) { + rData.numerator = avsys_exif_info.aperture_in_APEX; + rData.denominator = 1; + exif_set_rational(b, exif_data_get_byte_order(ed), rData); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_APERTURE_VALUE, + EXIF_FORMAT_RATIONAL, 1, b); + free(b); + if(ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_APERTURE_VALUE); + } + } else { + _mmcam_dbg_warn("malloc failed."); + } + } else { + _mmcam_dbg_log("Skip set EXIF_TAG_APERTURE_VALUE [%d]", avsys_exif_info.aperture_in_APEX); + } + + /*20. EXIF_TAG_BRIGHTNESS_VALUE*/ + if (avsys_exif_info.brigtness_numerator && avsys_exif_info.brightness_denominator) { + unsigned char *b = NULL; + ExifSRational rsData; + + _mmcam_dbg_log("EXIF_TAG_BRIGHTNESS_VALUE numerator [%d], denominator [%d]", + avsys_exif_info.brigtness_numerator, avsys_exif_info.brightness_denominator); + + b = malloc(sizeof(ExifSRational)); + if (b) { + rsData.numerator = avsys_exif_info.brigtness_numerator; + rsData.denominator = avsys_exif_info.brightness_denominator; + exif_set_srational(b, exif_data_get_byte_order(ed), rsData); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_BRIGHTNESS_VALUE, + EXIF_FORMAT_SRATIONAL, 1, b); + free(b); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_BRIGHTNESS_VALUE); + } + } else { + _mmcam_dbg_warn( "malloc failed." ); + } + } else { + _mmcam_dbg_log("Skip set EXIF_TAG_BRIGHTNESS_VALUE numerator [%d], denominatorr [%d]", + avsys_exif_info.brigtness_numerator, avsys_exif_info.brightness_denominator); + } + + /*21. EXIF_TAG_EXPOSURE_BIAS_VALUE*/ + value = 0; + ret = mm_camcorder_get_attributes(handle, NULL, MMCAM_FILTER_BRIGHTNESS, &value, NULL); + if (ret == MM_ERROR_NONE) { + unsigned char *b = NULL; + ExifSRational rsData; + + _mmcam_dbg_log("EXIF_TAG_BRIGHTNESS_VALUE %d",value); + + b = malloc(sizeof(ExifSRational)); + if (b) { + rsData.numerator = value - 5; + rsData.denominator = 10; + exif_set_srational(b, exif_data_get_byte_order(ed), rsData); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_BIAS_VALUE, + EXIF_FORMAT_SRATIONAL, 1, b); + free(b); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_EXPOSURE_BIAS_VALUE); + } + } else { + _mmcam_dbg_warn("malloc failed."); + } + } else { + _mmcam_dbg_log("failed to get MMCAM_FILTER_BRIGHTNESS [%x]", ret); + } + + /*22 EXIF_TAG_MAX_APERTURE_VALUE*/ +/* + if (avsys_exif_info.max_lens_aperture_in_APEX) { + unsigned char *b = NULL; + ExifRational rData; + + _mmcam_dbg_log("EXIF_TAG_MAX_APERTURE_VALUE [%d]", avsys_exif_info.max_lens_aperture_in_APEX); + + b = malloc(sizeof(ExifRational)); + if (b) { + rData.numerator = avsys_exif_info.max_lens_aperture_in_APEX; + rData.denominator = 1; + exif_set_rational(b, exif_data_get_byte_order(ed), rData); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_MAX_APERTURE_VALUE, + EXIF_FORMAT_RATIONAL, 1, b); + free(b); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_MAX_APERTURE_VALUE); + } + } else { + _mmcam_dbg_warn("failed to alloc for MAX aperture value"); + } + } +*/ + + /*23. EXIF_TAG_SUBJECT_DISTANCE*/ + /* 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); + } + + /*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); + } + + /*27. EXIF_TAG_FOCAL_LENGTH*/ + if (avsys_exif_info.focal_len_numerator && avsys_exif_info.focal_len_denominator) { + unsigned char *b = NULL; + ExifRational rData; + + _mmcam_dbg_log("EXIF_TAG_FOCAL_LENGTH numerator [%d], denominator [%d]", + avsys_exif_info.focal_len_numerator, avsys_exif_info.focal_len_denominator); + + b = malloc(sizeof(ExifRational)); + if (b) { + rData.numerator = avsys_exif_info.focal_len_numerator; + rData.denominator = avsys_exif_info.focal_len_denominator; + exif_set_rational(b, exif_data_get_byte_order(ed), rData); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, + EXIF_FORMAT_RATIONAL, 1, b); + free(b); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_FOCAL_LENGTH); + } + } else { + _mmcam_dbg_warn("malloc failed."); + } + } else { + _mmcam_dbg_log("Skip set EXIF_TAG_FOCAL_LENGTH numerator [%d], denominator [%d]", + avsys_exif_info.focal_len_numerator, avsys_exif_info.focal_len_denominator); + } + + /*28. EXIF_TAG_SENSING_METHOD*/ + /*FIXME*/ + value = MM_SENSING_MODE; + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order (ed),value); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_SENSING_METHOD, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_SENSING_METHOD); + } + + /*29. EXIF_TAG_FILE_SOURCE*/ +/* + value = MM_FILE_SOURCE; + exif_set_long(&elong[cntl], exif_data_get_byte_order(ed),value); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_FILE_SOURCE, + EXIF_FORMAT_UNDEFINED, 4, (unsigned char *)&elong[cntl++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_FILE_SOURCE); + } +*/ + + /*30. EXIF_TAG_SCENE_TYPE*/ +/* + value = MM_SCENE_TYPE; + exif_set_long(&elong[cntl], exif_data_get_byte_order(ed),value); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_SCENE_TYPE, + EXIF_FORMAT_UNDEFINED, 4, (unsigned char *)&elong[cntl++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_SCENE_TYPE); + } +*/ + + /*31. EXIF_TAG_EXPOSURE_MODE*/ + /*FIXME*/ + value = MM_EXPOSURE_MODE; + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed),value); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_MODE, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_EXPOSURE_MODE); + } + + + /*32. EXIF_TAG_WHITE_BALANCE*/ + ret = mm_camcorder_get_attributes(handle, NULL, MMCAM_FILTER_WB, &value, NULL); + if (ret == MM_ERROR_NONE) { + int set_value = 0; + _mmcam_dbg_log("WHITE BALANCE [%d]", value); + + if (value == MM_CAMCORDER_WHITE_BALANCE_AUTOMATIC) { + set_value = 0; + } else { + set_value = 1; + } + + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed), set_value); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_WHITE_BALANCE, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_WHITE_BALANCE); + } + } else { + _mmcam_dbg_warn("failed to get white balance [%x]", ret); + } + + /*33. EXIF_TAG_DIGITAL_ZOOM_RATIO*/ +/* + ret = mm_camcorder_get_attributes(handle, NULL, MMCAM_CAMERA_DIGITAL_ZOOM, &value, NULL); + if (ret == MM_ERROR_NONE) { + _mmcam_dbg_log("DIGITAL ZOOM [%d]", value); + + exif_set_long(&elong[cntl], exif_data_get_byte_order(ed), value); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_DIGITAL_ZOOM_RATIO, + EXIF_FORMAT_LONG, 1, (unsigned char *)&elong[cntl++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_DIGITAL_ZOOM_RATIO); + } + } else { + _mmcam_dbg_warn("failed to get digital zoom [%x]", ret); + } +*/ + + /*34. EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM*/ + /*FIXME*/ +/* + value = MM_FOCAL_LENGTH_35MMFILM; + exif_set_short(&eshort[cnts], exif_data_get_byte_order(ed),value); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM); + } +*/ + + /*35. EXIF_TAG_SCENE_CAPTURE_TYPE*/ + { + int scene_capture_type; + + ret = mm_camcorder_get_attributes(handle, NULL, MMCAM_FILTER_SCENE_MODE, &value, NULL); + if (ret == MM_ERROR_NONE) { + _mmcam_dbg_log("Scene mode(program mode) [%d]", value); + + if (value == MM_CAMCORDER_SCENE_MODE_NORMAL) { + scene_capture_type = 0; /* standard */ + } else if (value == MM_CAMCORDER_SCENE_MODE_PORTRAIT) { + scene_capture_type = 2; /* portrait */ + } else if (value == MM_CAMCORDER_SCENE_MODE_LANDSCAPE) { + scene_capture_type = 1; /* landscape */ + } else if (value == MM_CAMCORDER_SCENE_MODE_NIGHT_SCENE) { + scene_capture_type = 3; /* night scene */ + } else { + scene_capture_type = 4; /* Others */ + } + + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed), scene_capture_type); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_SCENE_CAPTURE_TYPE, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_SCENE_CAPTURE_TYPE); + } + } else { + _mmcam_dbg_warn("failed to get scene mode [%x]", ret); + } + } + + /*36. EXIF_TAG_GAIN_CONTROL*/ + /*FIXME*/ +/* + value = MM_GAIN_CONTROL; + exif_set_long(&elong[cntl], exif_data_get_byte_order(ed), value); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_GAIN_CONTROL, + EXIF_FORMAT_LONG, 1, (unsigned char *)&elong[cntl++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_GAIN_CONTROL); + } +*/ + + + /*37. EXIF_TAG_CONTRAST */ + { + type_int_range *irange = NULL; + int level = 0; + + _mmcamcorder_conf_get_value_int_range(hcamcorder->conf_ctrl, + CONFIGURE_CATEGORY_CTRL_EFFECT, + "Contrast", + &irange); + if (irange != NULL) { + mm_camcorder_get_attributes(handle, NULL, MMCAM_FILTER_CONTRAST, &value, NULL); + + _mmcam_dbg_log("CONTRAST currentt [%d], default [%d]", value, irange->default_value); + + if (value == irange->default_value) { + level = MM_VALUE_NORMAL; + } else if (value < irange->default_value) { + level = MM_VALUE_LOW; + } else { + level = MM_VALUE_HARD; + } + + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed), level); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_CONTRAST, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_CONTRAST); + } + } else { + _mmcam_dbg_warn("failed to get range of contrast"); + } + } + + /*38. EXIF_TAG_SATURATION*/ + { + type_int_range *irange = NULL; + int level = 0; + + _mmcamcorder_conf_get_value_int_range(hcamcorder->conf_ctrl, + CONFIGURE_CATEGORY_CTRL_EFFECT, + "Saturation", + &irange); + if (irange != NULL) { + mm_camcorder_get_attributes(handle, NULL, MMCAM_FILTER_SATURATION, &value, NULL); + + _mmcam_dbg_log("SATURATION current [%d], default [%d]", value, irange->default_value); + + if (value == irange->default_value) { + level = MM_VALUE_NORMAL; + } else if (value < irange->default_value) { + level = MM_VALUE_LOW; + } else { + level=MM_VALUE_HARD; + } + + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed), level); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_SATURATION, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_SATURATION); + } + } else { + _mmcam_dbg_warn("failed to get range of saturation"); + } + } + + /*39. EXIF_TAG_SHARPNESS*/ + { + type_int_range *irange = NULL; + int level = 0; + + _mmcamcorder_conf_get_value_int_range(hcamcorder->conf_ctrl, + CONFIGURE_CATEGORY_CTRL_EFFECT, + "Sharpness", + &irange); + if (irange != NULL) { + mm_camcorder_get_attributes(handle, NULL, MMCAM_FILTER_SHARPNESS, &value, NULL); + + _mmcam_dbg_log("SHARPNESS current [%d], default [%d]", value, irange->default_value); + + if (value == irange->default_value) { + level = MM_VALUE_NORMAL; + } else if (value < irange->default_value) { + level = MM_VALUE_LOW; + } else { + level = MM_VALUE_HARD; + } + + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed), level); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_SHARPNESS, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_SHARPNESS); + } + } else { + _mmcam_dbg_warn("failed to get range of sharpness"); + } + } + + /*40. EXIF_TAG_SUBJECT_DISTANCE_RANGE*/ + /*FIXME*/ + value = MM_SUBJECT_DISTANCE_RANGE; + _mmcam_dbg_log("DISTANCE_RANGE [%d]", value); + exif_set_short((unsigned char *)&eshort[cnts], exif_data_get_byte_order(ed), value); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_SUBJECT_DISTANCE_RANGE, + EXIF_FORMAT_SHORT, 1, (unsigned char *)&eshort[cnts++]); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_SUBJECT_DISTANCE_RANGE); + } + + /* GPS information */ + ret = mm_camcorder_get_attributes(handle, NULL, MMCAM_TAG_GPS_ENABLE, &gps_enable, NULL); + if (ret == MM_ERROR_NONE && gps_enable) { + ExifByte GpsVersion[4]={2,2,0,0}; + + _mmcam_dbg_log("Tag for GPS is ENABLED."); + + ret = mm_exif_set_add_entry(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_VERSION_ID, + EXIF_FORMAT_BYTE, 4, (unsigned char *)&GpsVersion); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_GPS_VERSION_ID); + } + + /*41. Latitude*/ + ret = mm_camcorder_get_attributes(handle, &err_name, + MMCAM_TAG_LATITUDE, &f_latitude, + MMCAM_TAG_LONGITUDE, &f_longitude, + MMCAM_TAG_ALTITUDE, &f_altitude, NULL); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("failed to get gps info [%x][%s]", ret, err_name); + SAFE_FREE(err_name); + goto exit; + } + + _mmcam_dbg_log("f_latitude [%f]", f_latitude); + if (f_latitude != INVALID_GPS_VALUE) { + unsigned char *b = NULL; + unsigned int deg; + unsigned int min; + unsigned int sec; + ExifRational rData; + + if (f_latitude < 0) { + ret = mm_exif_set_add_entry(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF, + EXIF_FORMAT_ASCII, 2, (unsigned char *)"S"); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_GPS_LATITUDE_REF); + } + f_latitude = -f_latitude; + } else if (f_latitude > 0) { + ret = mm_exif_set_add_entry(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE_REF, + EXIF_FORMAT_ASCII, 2, (unsigned char *)"N"); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_GPS_LATITUDE_REF); + } + } + + deg = (unsigned int)(f_latitude); + min = (unsigned int)((f_latitude-deg)*60); + sec = (unsigned int)(((f_latitude-deg)*3600)-min*60); + + _mmcam_dbg_log("f_latitude deg[%d], min[%d], sec[%d]", deg, min, sec); + b = malloc(3 * sizeof(ExifRational)); + if (b) { + rData.numerator = deg; + rData.denominator = 1; + exif_set_rational(b, exif_data_get_byte_order(ed), rData); + rData.numerator = min; + exif_set_rational(b+8, exif_data_get_byte_order(ed), rData); + rData.numerator = sec; + exif_set_rational(b+16, exif_data_get_byte_order(ed), rData); + + ret = mm_exif_set_add_entry(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LATITUDE, + EXIF_FORMAT_RATIONAL, 3, (unsigned char *)b); + free(b); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_GPS_LATITUDE); + } + } else { + _mmcam_dbg_warn("malloc failed"); + } + } + + /*42. Longitude*/ + _mmcam_dbg_log("f_longitude [%f]", f_longitude); + if (f_longitude != INVALID_GPS_VALUE) { + unsigned char *b = NULL; + unsigned int deg; + unsigned int min; + unsigned int sec; + ExifRational rData; + + if (f_longitude < 0) { + ret = mm_exif_set_add_entry(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF, + EXIF_FORMAT_ASCII, 2, (unsigned char *)"W"); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_GPS_LONGITUDE_REF); + } + f_longitude = -f_longitude; + } else if (f_longitude > 0) { + ret = mm_exif_set_add_entry(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE_REF, + EXIF_FORMAT_ASCII, 2, (unsigned char *)"E"); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_GPS_LONGITUDE_REF); + } + } + + deg = (unsigned int)(f_longitude); + min = (unsigned int)((f_longitude-deg)*60); + sec = (unsigned int)(((f_longitude-deg)*3600)-min*60); + + _mmcam_dbg_log("f_longitude deg[%d], min[%d], sec[%d]", deg, min, sec); + b = malloc(3 * sizeof(ExifRational)); + if (b) { + rData.numerator = deg; + rData.denominator = 1; + exif_set_rational(b, exif_data_get_byte_order(ed), rData); + rData.numerator = min; + exif_set_rational(b+8, exif_data_get_byte_order(ed), rData); + rData.numerator = sec; + exif_set_rational(b+16, exif_data_get_byte_order(ed), rData); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_LONGITUDE, + EXIF_FORMAT_RATIONAL, 3, (unsigned char *)b); + free(b); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_GPS_LONGITUDE); + } + } else { + _mmcam_dbg_warn("malloc failed"); + } + } + + /*43. Altitude*/ + _mmcam_dbg_log("f_altitude [%f]", f_altitude); + if (f_altitude != INVALID_GPS_VALUE) { + ExifByte alt_ref = 0; + unsigned char *b = NULL; + ExifRational rData; + b = malloc(sizeof(ExifRational)); + if (b) { + if (f_altitude < 0) { + alt_ref = 1; + f_altitude = -f_altitude; + } + + ret = mm_exif_set_add_entry(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_ALTITUDE_REF, + EXIF_FORMAT_BYTE, 1, (unsigned char *)&alt_ref); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("error [%x], tag [%x]", ret, EXIF_TAG_GPS_ALTITUDE_REF); + if (ret == MM_ERROR_CAMCORDER_LOW_MEMORY) { + free(b); + b = NULL; + goto exit; + } + } + + rData.numerator = (unsigned int)(f_altitude + 0.5)*100; + rData.denominator = 100; + exif_set_rational(b, exif_data_get_byte_order(ed), rData); + ret = mm_exif_set_add_entry(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_ALTITUDE, + EXIF_FORMAT_RATIONAL, 1, (unsigned char *)b); + free(b); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_GPS_ALTITUDE); + } + } else { + _mmcam_dbg_warn("malloc failed"); + } + } + + /*44. EXIF_TAG_GPS_TIME_STAMP*/ + { + double gps_timestamp = INVALID_GPS_VALUE; + mm_camcorder_get_attributes(handle, NULL, "tag-gps-time-stamp", &gps_timestamp, NULL); + _mmcam_dbg_log("Gps timestamp [%f]", gps_timestamp); + if (gps_timestamp > 0.0) { + unsigned char *b = NULL; + unsigned int hour; + unsigned int min; + unsigned int microsec; + ExifRational rData; + + hour = (unsigned int)(gps_timestamp / 3600); + min = (unsigned int)((gps_timestamp - 3600 * hour) / 60); + microsec = (unsigned int)(((double)((double)gps_timestamp -(double)(3600 * hour)) -(double)(60 * min)) * 1000000); + + _mmcam_dbg_log("Gps timestamp hour[%d], min[%d], microsec[%d]", hour, min, microsec); + b = malloc(3 * sizeof(ExifRational)); + if (b) { + rData.numerator = hour; + rData.denominator = 1; + exif_set_rational(b, exif_data_get_byte_order(ed), rData); + + rData.numerator = min; + rData.denominator = 1; + exif_set_rational(b + 8, exif_data_get_byte_order(ed), rData); + + rData.numerator = microsec; + rData.denominator = 1000000; + exif_set_rational(b + 16, exif_data_get_byte_order(ed), rData); + + ret = mm_exif_set_add_entry(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_TIME_STAMP, + EXIF_FORMAT_RATIONAL, 3, b); + free(b); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_GPS_TIME_STAMP); + } + } else { + _mmcam_dbg_warn( "malloc failed." ); + } + } + } + + /*45. EXIF_TAG_GPS_DATE_STAMP*/ + { + unsigned char *date_stamp = NULL; + int date_stamp_len = 0; + + mm_camcorder_get_attributes(handle, NULL, "tag-gps-date-stamp", &date_stamp, &date_stamp_len, NULL); + + if (date_stamp) { + _mmcam_dbg_log("Date stamp [%s]", date_stamp); + + /* cause it should include NULL char */ + ret = mm_exif_set_add_entry(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_DATE_STAMP, + EXIF_FORMAT_ASCII, date_stamp_len + 1, date_stamp); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_GPS_DATE_STAMP); + } + } + } + + /*46. EXIF_TAG_GPS_PROCESSING_METHOD */ + { + unsigned char *processing_method = NULL; + int processing_method_len = 0; + + mm_camcorder_get_attributes(handle, NULL, "tag-gps-processing-method", &processing_method, &processing_method_len, NULL); + + if (processing_method) { + _mmcam_dbg_log("Processing method [%s]", processing_method); + + ret = mm_exif_set_add_entry(ed, EXIF_IFD_GPS, EXIF_TAG_GPS_PROCESSING_METHOD, + EXIF_FORMAT_UNDEFINED, processing_method_len, processing_method); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_GPS_PROCESSING_METHOD); + } + } + } + } else { + _mmcam_dbg_log( "Tag for GPS is DISABLED." ); + } + + + /*47. EXIF_TAG_MAKER_NOTE*/ + ret = mm_exif_set_add_entry(ed, EXIF_IFD_EXIF, EXIF_TAG_MAKER_NOTE, + EXIF_FORMAT_UNDEFINED, 8, (unsigned char *)"SAMSUNG"); + if (ret != MM_ERROR_NONE) { + EXIF_SET_ERR(ret, EXIF_TAG_MAKER_NOTE); + } + + /* create and link samsung maker note */ + ret = mm_exif_mnote_create(ed); + if (ret != MM_ERROR_NONE){ + EXIF_SET_ERR(ret, EXIF_TAG_MAKER_NOTE); + } else { + _mmcam_dbg_log("Samsung makernote created"); + + /* add samsung maker note entries (param : data, tag, index, subtag index1, subtag index2) */ + ret = mm_exif_mnote_set_add_entry(ed, MNOTE_SAMSUNG_TAG_MNOTE_VERSION, 0, _MNOTE_VALUE_NONE, _MNOTE_VALUE_NONE); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("mm_exif_mnote_set_add_entry error! [%x]", ret); + } + /* + ret = mm_exif_mnote_set_add_entry(ed, MNOTE_SAMSUNG_TAG_DEVICE_ID, 2, _MNOTE_VALUE_NONE, _MNOTE_VALUE_NONE); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("mm_exif_mnote_set_add_entry error! [%x]", ret); + } + + ret = mm_exif_mnote_set_add_entry(ed, MNOTE_SAMSUNG_TAG_SERIAL_NUM, _MNOTE_VALUE_NONE, _MNOTE_VALUE_NONE, _MNOTE_VALUE_NONE); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("mm_exif_mnote_set_add_entry error! [%x]", ret); + } + + ret = mm_exif_mnote_set_add_entry(ed, MNOTE_SAMSUNG_TAG_COLOR_SPACE, 1, _MNOTE_VALUE_NONE, _MNOTE_VALUE_NONE); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("mm_exif_mnote_set_add_entry error! [%x]", ret); + } + */ + ret = mm_exif_mnote_set_add_entry(ed, MNOTE_SAMSUNG_TAG_FACE_DETECTION, 0, _MNOTE_VALUE_NONE, _MNOTE_VALUE_NONE); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("mm_exif_mnote_set_add_entry error! ret=%x", ret); + } + /* + ret = mm_exif_mnote_set_add_entry(ed, MNOTE_SAMSUNG_TAG_MODEL_ID, _MNOTE_VALUE_NONE, 3, 2); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("mm_exif_mnote_set_add_entry error! [%x]", ret); + } + */ + } + + _mmcam_dbg_log(""); + + ret = mm_exif_set_exif_to_info(hcamcorder->exif_info, ed); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("mm_exif_set_exif_to_info err!! [%x]", ret); + } + +exit: + _mmcam_dbg_log("finished!! [%x]", ret); + + if (ed) { + exif_data_unref (ed); + } + + return ret; +} diff --git a/src/mm_camcorder_util.c b/src/mm_camcorder_util.c new file mode 100644 index 0000000..688cc31 --- /dev/null +++ b/src/mm_camcorder_util.c @@ -0,0 +1,1092 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*=========================================================================================== +| | +| INCLUDE FILES | +| | +========================================================================================== */ +#include <stdio.h> +#include <stdarg.h> +#include <camsrcjpegenc.h> +#include <sys/vfs.h> /* struct statfs */ + +#include "mm_camcorder_internal.h" +#include "mm_camcorder_util.h" + +/*--------------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- +| 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) \ + {\ + _mmcam_dbg_err("[Critical] fputc() returns fail.\n"); \ + return FALSE;\ + }\ +} +#define FPUTS_CHECK(x_str, x_file)\ +{\ + if (fputs(x_str, x_file) == EOF) \ + {\ + _mmcam_dbg_err("[Critical] fputs() returns fail.\n");\ + SAFE_FREE(str); \ + return FALSE;\ + }\ +} + +/*--------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------*/ +/* STATIC INTERNAL FUNCTION */ + +//static gint skip_mdat(FILE *f); +static guint16 get_language_code(const char *str); +static gchar* str_to_utf8(const gchar *str); +static inline gboolean write_tag(FILE *f, const gchar *tag); +static inline gboolean write_to_32(FILE *f, guint val); +static inline gboolean write_to_16(FILE *f, guint val); +static inline gboolean write_to_24(FILE *f, guint val); + +/*=========================================================================================== +| | +| FUNCTION DEFINITIONS | +| | +========================================================================================== */ +/*--------------------------------------------------------------------------- +| GLOBAL FUNCTION DEFINITIONS: | +---------------------------------------------------------------------------*/ + +gint32 _mmcamcorder_double_to_fix(gdouble d_number) +{ + return (gint32) (d_number * 65536.0); +} + +// find top level tag only, do not use this function for finding sub level tags +gint _mmcamcorder_find_tag(FILE *f, guint32 tag_fourcc) +{ + guchar buf[8]; + + 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]); + + 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; + } + } + } + _mmcam_dbg_log("cannot find tag : %c%c%c%c", MMCAM_FOURCC_ARGS(tag_fourcc)); + return 0; +} + +gboolean _mmcamcorder_update_size(FILE *f, gint64 prev_pos, gint64 curr_pos) +{ + _mmcam_dbg_log("size : %"G_GINT64_FORMAT"", curr_pos-prev_pos); + if(fseek(f, prev_pos, SEEK_SET) != 0) + { + _mmcam_dbg_err("fseek() fail"); + return FALSE; + } + + if (!write_to_32(f, curr_pos -prev_pos)) + return FALSE; + + if(fseek(f, curr_pos, SEEK_SET) != 0) + { + _mmcam_dbg_err("fseek() fail"); + return FALSE; + } + + return TRUE; +} + +gboolean _mmcamcorder_write_loci(FILE *f, _MMCamcorderLocationInfo info) +{ + gint64 current_pos, pos; + gchar *str = NULL; + + _mmcam_dbg_log(""); + + if((pos = ftell(f))<0) + { + _mmcam_dbg_err("ftell() returns negative value"); + return FALSE; + } + + if(!write_to_32(f, 0)) //size + return FALSE; + + if(!write_tag(f, "loci")) // type + return FALSE; + + FPUTC_CHECK(0, f); // version + + if(!write_to_24(f, 0)) // flags + return FALSE; + + if(!write_to_16(f, get_language_code("eng"))) // language + return FALSE; + + str = str_to_utf8("location_name"); + + FPUTS_CHECK(str, f); // name + SAFE_FREE(str); + + FPUTC_CHECK('\0', f); + FPUTC_CHECK(0, f); //role + + if(!write_to_32(f, info.longitude)) // Longitude + return FALSE; + + if(!write_to_32(f, info.latitude)) // Latitude + return FALSE; + + if(! write_to_32(f, info.altitude)) // Altitude + return FALSE; + + str = str_to_utf8("Astronomical_body"); + FPUTS_CHECK(str, f);//Astronomical_body + SAFE_FREE(str); + + FPUTC_CHECK('\0', f); + + str = str_to_utf8("Additional_notes"); + FPUTS_CHECK(str, f); // Additional_notes + SAFE_FREE(str); + + FPUTC_CHECK('\0', f); + + if((current_pos = ftell(f))<0) + { + _mmcam_dbg_err("ftell() returns negative value"); + return FALSE; + } + + if(! _mmcamcorder_update_size(f, pos, current_pos)) + return FALSE; + + return TRUE; +} + +gboolean _mmcamcorder_write_udta(FILE *f, _MMCamcorderLocationInfo info) +{ + gint64 current_pos, pos; + + _mmcam_dbg_log(""); + + if((pos = ftell(f))<0) + { + _mmcam_dbg_err("ftell() returns negative value"); + return FALSE; + } + + if(!write_to_32(f, 0)) //size + return FALSE; + + if(!write_tag(f, "udta")) // type + return FALSE; + + if(! _mmcamcorder_write_loci(f, info)) + return FALSE; + + if((current_pos = ftell(f))<0) + { + _mmcam_dbg_err("ftell() returns negative value"); + return FALSE; + } + + if(! _mmcamcorder_update_size(f, pos, current_pos)) + return FALSE; + + + return TRUE; +} + + +gulong _mmcamcorder_get_container_size(const guchar *size) +{ + gulong result = 0; + gulong 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]; + return result; +} + + +int _mmcamcorder_get_freespace(const gchar *path, guint64 *free_space) +{ + struct statfs fs; + + g_assert(path); + + if (!g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) { + _mmcam_dbg_log("File(%s) doesn't exist.", path); + return -2; + } + + if (-1 == statfs(path, &fs)) { + _mmcam_dbg_log("Getting free space is failed.(%s)", path); + return -1; + } + + *free_space = (guint64)fs.f_bsize * fs.f_bavail; + return 1; +} + + +int _mmcamcorder_get_file_size(const char *filename, guint64 *size) +{ + struct stat buf; + + if (stat(filename, &buf) != 0) + return -1; + *size = (guint64)buf.st_size; + return 1; +} + + +void _mmcamcorder_remove_buffer_probe(MMHandleType handle, _MMCamcorderHandlerCategory category) +{ + mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle); + GList *list = NULL; + MMCamcorderHandlerItem *item = NULL; + + mmf_return_if_fail(hcamcorder); + + if(!hcamcorder->buffer_probes) + { + _mmcam_dbg_err("Fail to remove buffer probe, list for buffer probe is NULL"); + } + + list = hcamcorder->buffer_probes; + + while(list) + { + item = list->data; + + if(!item) + { + _mmcam_dbg_err("Remove buffer probe faild, the item is NULL"); + list = g_list_next(list); + continue; + } + + if(item->category & category) + { + + if(item->object && GST_IS_PAD(item->object)) + { + _mmcam_dbg_log("Remove buffer probe on [%s:%s] - [ID : %lu], [Category : %x]", + GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category); + gst_pad_remove_buffer_probe(GST_PAD(item->object), item->handler_id); + } + else + { + _mmcam_dbg_warn("Remove buffer probe faild, the pad is null or not pad, just remove item from list and free it"); + } + + list = g_list_next(list); + hcamcorder->buffer_probes = g_list_remove(hcamcorder->buffer_probes, item); + SAFE_FREE(item); + } + else + { + _mmcam_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category); + list = g_list_next(list); + } + } + + if( category == _MMCAMCORDER_HANDLER_CATEGORY_ALL) + { + g_list_free(hcamcorder->buffer_probes); + hcamcorder->buffer_probes = NULL; + } +} + +void _mmcamcorder_remove_event_probe(MMHandleType handle, _MMCamcorderHandlerCategory category) +{ + mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle); + GList *list = NULL; + MMCamcorderHandlerItem *item = NULL; + + mmf_return_if_fail(hcamcorder); + + if(!hcamcorder->event_probes) + { + _mmcam_dbg_err("Fail to remove event probe, list for event probe is NULL"); + } + + list = hcamcorder->event_probes; + + while(list) + { + item = list->data; + + if(!item) + { + _mmcam_dbg_err("Remove event probe faild, the item is NULL"); + list = g_list_next(list); + continue; + } + + if(item->category & category) + { + + if(item->object && GST_IS_PAD(item->object)) + { + _mmcam_dbg_log("Remove event probe on [%s:%s] - [ID : %lu], [Category : %x]", + GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category); + gst_pad_remove_event_probe(GST_PAD(item->object), item->handler_id); + } + else + { + _mmcam_dbg_warn("Remove event probe faild, the pad is null or not pad, just remove item from list and free it"); + } + + list = g_list_next(list); + hcamcorder->event_probes = g_list_remove(hcamcorder->event_probes, item); + SAFE_FREE(item); + } + else + { + _mmcam_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category); + list = g_list_next(list); + } + } + + if( category == _MMCAMCORDER_HANDLER_CATEGORY_ALL) + { + g_list_free(hcamcorder->event_probes); + hcamcorder->event_probes = NULL; + } +} + +void _mmcamcorder_remove_data_probe(MMHandleType handle, _MMCamcorderHandlerCategory category) +{ + mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle); + GList *list = NULL; + MMCamcorderHandlerItem *item = NULL; + + mmf_return_if_fail(hcamcorder); + + if(!hcamcorder->data_probes) + { + _mmcam_dbg_err("Fail to remove data probe, list for data probe is NULL"); + } + + list = hcamcorder->data_probes; + + while(list) + { + item = list->data; + + if(!item) + { + _mmcam_dbg_err("Remove data probe faild, the item is NULL"); + list = g_list_next(list); + continue; + } + + if(item->category & category) + { + + if(item->object && GST_IS_PAD(item->object)) + { + _mmcam_dbg_log("Remove data probe on [%s:%s] - [ID : %lu], [Category : %x]", + GST_DEBUG_PAD_NAME(item->object), item->handler_id, item->category); + gst_pad_remove_data_probe(GST_PAD(item->object), item->handler_id); + } + else + { + _mmcam_dbg_warn("Remove data probe faild, the pad is null or not pad, just remove item from list and free it"); + } + + list = g_list_next(list); + hcamcorder->data_probes = g_list_remove(hcamcorder->data_probes, item); + SAFE_FREE(item); + } + else + { + _mmcam_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category); + list = g_list_next(list); + } + } + + if( category == _MMCAMCORDER_HANDLER_CATEGORY_ALL) + { + g_list_free(hcamcorder->data_probes); + hcamcorder->data_probes = NULL; + } +} + +void _mmcamcorder_disconnect_signal(MMHandleType handle, _MMCamcorderHandlerCategory category) +{ + mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle); + GList *list = NULL; + MMCamcorderHandlerItem *item = NULL; + + mmf_return_if_fail(hcamcorder); + + if(!hcamcorder->signals) + { + _mmcam_dbg_err("Fail to disconnect signals, list for signal is NULL"); + } + + list = hcamcorder->signals; + + while(list) + { + item = list->data; + + if(!item) + { + _mmcam_dbg_err("Fail to Disconnecting signal, the item is NULL"); + list = g_list_next(list); + continue; + } + + if(item->category & category) + { + + if(item->object && GST_IS_ELEMENT(item->object)) + { + if ( g_signal_handler_is_connected ( item->object, item->handler_id ) ) + { + _mmcam_dbg_log("Disconnect signal from [%s] : [ID : %lu], [Category : %x]", + GST_OBJECT_NAME(item->object), item->handler_id, item->category); + g_signal_handler_disconnect ( item->object, item->handler_id ); + } + else + { + _mmcam_dbg_warn("Signal was not connected, cannot disconnect it : [%s] [ID : %lu], [Category : %x]", + GST_OBJECT_NAME(item->object), item->handler_id, item->category); + } + + } + else + { + _mmcam_dbg_err("Fail to Disconnecting signal, the element is null or not element, just remove item from list and free it"); + } + + list = g_list_next(list); + hcamcorder->signals = g_list_remove(hcamcorder->signals, item); + SAFE_FREE(item); + } + else + { + _mmcam_dbg_log("Skip item : [ID : %lu], [Category : %x] ", item->handler_id, item->category); + list = g_list_next(list); + } + } + + if( category == _MMCAMCORDER_HANDLER_CATEGORY_ALL) + { + g_list_free(hcamcorder->signals); + hcamcorder->signals = NULL; + } +} + +void _mmcamcorder_remove_all_handlers(MMHandleType handle, _MMCamcorderHandlerCategory category) +{ + mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle); + + _mmcam_dbg_log("ENTER"); + + if(hcamcorder->signals) + _mmcamcorder_disconnect_signal((MMHandleType)hcamcorder, category); + if(hcamcorder->data_probes) + _mmcamcorder_remove_data_probe((MMHandleType)hcamcorder, category); + if(hcamcorder->event_probes) + _mmcamcorder_remove_event_probe((MMHandleType)hcamcorder, category); + if(hcamcorder->buffer_probes) + _mmcamcorder_remove_buffer_probe((MMHandleType)hcamcorder, category); + + _mmcam_dbg_log("LEAVE"); +} + +void _mmcamcorder_element_release_noti(gpointer data, GObject *where_the_object_was) +{ + int i=0; + _MMCamcorderSubContext *sc = (_MMCamcorderSubContext *)data; + 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)) + { + _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; + break; + } + } +} + + +gboolean +_mmcamcroder_msg_callback(void *data) +{ + _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 ); + +// _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 ); + + if ((hcamcorder) && (hcamcorder->msg_cb)) { + hcamcorder->msg_cb(item->id, (MMMessageParamType*)(&(item->param)), hcamcorder->msg_cb_param); + } + + _MMCAMCORDER_UNLOCK_MESSAGE_CALLBACK( hcamcorder ); + + _MMCAMCORDER_LOCK((MMHandleType)hcamcorder); + + if (hcamcorder->msg_data) + hcamcorder->msg_data = g_list_remove(hcamcorder->msg_data, item); + + SAFE_FREE(item); + + _MMCAMCORDER_UNLOCK((MMHandleType)hcamcorder); + + return FALSE; //For not being called again +} + + +gboolean +_mmcamcroder_send_message(MMHandleType handle, _MMCamcorderMsgItem *data) +{ + mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderMsgItem *item = NULL; + + mmf_return_val_if_fail(hcamcorder, FALSE); + mmf_return_val_if_fail(data, FALSE); + + switch (data->id) + { + case MM_MESSAGE_CAMCORDER_STATE_CHANGED: + case MM_MESSAGE_CAMCORDER_STATE_CHANGED_BY_ASM: + data->param.union_type = MM_MSG_UNION_STATE; + break; + case MM_MESSAGE_CAMCORDER_RECORDING_STATUS: + data->param.union_type = MM_MSG_UNION_RECORDING_STATUS; + break; + case MM_MESSAGE_CAMCORDER_FIRMWARE_UPDATE: + data->param.union_type = MM_MSG_UNION_FIRMWARE; + break; + case MM_MESSAGE_CAMCORDER_CURRENT_VOLUME: + data->param.union_type = MM_MSG_UNION_REC_VOLUME_DB; + break; + case MM_MESSAGE_CAMCORDER_TIME_LIMIT: + case MM_MESSAGE_CAMCORDER_MAX_SIZE: + case MM_MESSAGE_CAMCORDER_NO_FREE_SPACE: + case MM_MESSAGE_CAMCORDER_ERROR: + case MM_MESSAGE_CAMCORDER_FOCUS_CHANGED: + case MM_MESSAGE_CAMCORDER_CAPTURED: + case MM_MESSAGE_READY_TO_RESUME: + default: + data->param.union_type = MM_MSG_UNION_CODE; + break; + } + + item = g_malloc(sizeof(_MMCamcorderMsgItem)); + memcpy(item, data, sizeof(_MMCamcorderMsgItem)); + item->handle = handle; + + _MMCAMCORDER_LOCK(handle); + hcamcorder->msg_data = g_list_append(hcamcorder->msg_data, item); +// _mmcam_dbg_log("item[%p]", item); + + g_idle_add(_mmcamcroder_msg_callback, item); + + _MMCAMCORDER_UNLOCK(handle); + + return TRUE; +} + + +void +_mmcamcroder_remove_message_all(MMHandleType handle) +{ + mmf_camcorder_t* hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderMsgItem *item = NULL; + gboolean ret = TRUE; + GList *list = NULL; + + mmf_return_if_fail(hcamcorder); + + _MMCAMCORDER_LOCK(handle); + + if(!hcamcorder->msg_data) + { + _mmcam_dbg_log("No message data is remained."); + } + else + { + list = hcamcorder->msg_data; + + while(list) + { + item = list->data; + list = g_list_next(list); + + if(!item) + { + _mmcam_dbg_err("Fail to remove message. The item is NULL"); + } + else + { + ret = g_idle_remove_by_data (item); + _mmcam_dbg_log("Remove item[%p]. ret[%d]", item, ret); + + hcamcorder->msg_data = g_list_remove(hcamcorder->msg_data, item); + + SAFE_FREE(item); + } + } + + g_list_free(hcamcorder->msg_data); + hcamcorder->msg_data = NULL; + } + + _MMCAMCORDER_UNLOCK(handle); + + return; +} + + +void +_mmcamcorder_err_trace_write( char *str_filename, char *func_name, int line_num, char *fmt, ... ) +{ + FILE *f = NULL; + va_list ap = {0}; + char time_string[TIME_STRING_MAX_LEN] = {'\0',}; + + time_t current_time; + struct tm new_time; + + mmf_return_if_fail( str_filename ); + + current_time = time( NULL ); + localtime_r( ¤t_time, &new_time ); + + f = fopen( str_filename, "a" ); + if( f == NULL ) + { + _mmcam_dbg_warn( "Failed to open file.[%s]", str_filename ); + return; + } + + asctime_r(&new_time, time_string); + fprintf( f, "[%.19s][%05d][%s]", time_string, line_num, func_name ); + + va_start( ap, fmt ); + vfprintf( f, fmt, ap ); + va_end( ap ); + + fprintf( f, "\n" ); + + fclose( f ); +} + +int +_mmcamcorder_get_pixel_format(GstBuffer *buffer) +{ + GstCaps *caps = NULL; + const GstStructure *structure; + const char *media_type; + MMPixelFormatType type = 0; + unsigned int fourcc = 0; + + mmf_return_val_if_fail( buffer != NULL, MM_PIXEL_FORMAT_INVALID ); + + caps = gst_buffer_get_caps (buffer); + structure = gst_caps_get_structure (caps, 0); + media_type = gst_structure_get_name (structure); + + if (!strcmp (media_type, "image/jpeg") ) + { + _mmcam_dbg_log("It is jpeg."); + type = MM_PIXEL_FORMAT_ENCODED; + } + else if (!strcmp (media_type, "video/x-raw-yuv")) + { + _mmcam_dbg_log("It is yuv."); + gst_structure_get_fourcc (structure, "format", &fourcc); + type = _mmcamcorder_get_pixtype(fourcc); + } + else + { + _mmcam_dbg_err("Not supported format"); + type = MM_PIXEL_FORMAT_INVALID; + } + + _mmcam_dbg_log( "Type [%d]", type ); + + gst_caps_unref( caps ); + caps = NULL; + + return type; +} + +unsigned int _mmcamcorder_get_fourcc(int pixtype, int codectype, int use_zero_copy_format) +{ + unsigned int fourcc = 0; + + _mmcam_dbg_log("pixtype(%d)", pixtype); + + switch (pixtype) { + case MM_PIXEL_FORMAT_NV12: + if (use_zero_copy_format) { + fourcc = GST_MAKE_FOURCC ('S', 'N', '1', '2'); + } else { + fourcc = GST_MAKE_FOURCC ('N', 'V', '1', '2'); + } + break; + case MM_PIXEL_FORMAT_YUYV: + if (use_zero_copy_format) { + fourcc = GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'); + } else { + fourcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'); + } + break; + case MM_PIXEL_FORMAT_UYVY: + if (use_zero_copy_format) { + fourcc = GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'); + } else { + fourcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'); + } + break; + case MM_PIXEL_FORMAT_I420: + if (use_zero_copy_format) { + fourcc = GST_MAKE_FOURCC ('S', '4', '2', '0'); + } else { + fourcc = GST_MAKE_FOURCC ('I', '4', '2', '0'); + } + break; + case MM_PIXEL_FORMAT_YV12: + fourcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2'); + break; + case MM_PIXEL_FORMAT_422P: + fourcc = GST_MAKE_FOURCC ('4', '2', '2', 'P'); + break; + case MM_PIXEL_FORMAT_RGB565: + fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', 'P'); + break; + case MM_PIXEL_FORMAT_RGB888: + fourcc = GST_MAKE_FOURCC ('R', 'G', 'B', '3'); + break; + case MM_PIXEL_FORMAT_ENCODED: + if (codectype == MM_IMAGE_CODEC_JPEG) { + fourcc = GST_MAKE_FOURCC ('J', 'P', 'E', 'G'); + } else if (codectype == MM_IMAGE_CODEC_JPEG_SRW) { + fourcc = GST_MAKE_FOURCC ('J', 'P', 'E', 'G'); /*TODO: JPEG+SamsungRAW format */ + } else if (codectype == MM_IMAGE_CODEC_SRW) { + fourcc = GST_MAKE_FOURCC ('J', 'P', 'E', 'G'); /*TODO: SamsungRAW format */ + } else if (codectype == MM_IMAGE_CODEC_PNG) { + fourcc = GST_MAKE_FOURCC ('P', 'N', 'G', ' '); + } else { + /* Please let us know what other fourcces are. ex) BMP, GIF?*/ + fourcc = GST_MAKE_FOURCC ('J', 'P', 'E', 'G'); + } + break; + default: + _mmcam_dbg_log("Not proper pixel type. Set default."); + fourcc = GST_MAKE_FOURCC ('S', '4', '2', '0'); + break; + } + + return fourcc; +} + + +int _mmcamcorder_get_pixtype(unsigned int fourcc) +{ + int pixtype = MM_PIXEL_FORMAT_INVALID; + char *pfourcc = (char*)&fourcc; + _mmcam_dbg_log("fourcc(%c%c%c%c)", pfourcc[0], pfourcc[1], pfourcc[2], pfourcc[3]); + + switch (fourcc) { + case GST_MAKE_FOURCC ('S', 'N', '1', '2'): + case GST_MAKE_FOURCC ('N', 'V', '1', '2'): + pixtype = MM_PIXEL_FORMAT_NV12; + break; + case GST_MAKE_FOURCC ('S', 'U', 'Y', 'V'): + case GST_MAKE_FOURCC ('Y', 'U', 'Y', 'V'): + case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'): + pixtype = MM_PIXEL_FORMAT_YUYV; + break; + case GST_MAKE_FOURCC ('S', 'Y', 'V', 'Y'): + case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'): + pixtype = MM_PIXEL_FORMAT_UYVY; + break; + case GST_MAKE_FOURCC ('S', '4', '2', '0'): + case GST_MAKE_FOURCC ('I', '4', '2', '0'): + pixtype = MM_PIXEL_FORMAT_I420; + break; + case GST_MAKE_FOURCC ('Y', 'V', '1', '2'): + pixtype = MM_PIXEL_FORMAT_YV12; + break; + case GST_MAKE_FOURCC ('4', '2', '2', 'P'): + pixtype = MM_PIXEL_FORMAT_422P; + break; + case GST_MAKE_FOURCC ('R', 'G', 'B', 'P'): + pixtype = MM_PIXEL_FORMAT_RGB565; + break; + case GST_MAKE_FOURCC ('R', 'G', 'B', '3'): + pixtype = MM_PIXEL_FORMAT_RGB888; + break; + case GST_MAKE_FOURCC ('A', 'R', 'G', 'B'): + case GST_MAKE_FOURCC ('x', 'R', 'G', 'B'): + pixtype = MM_PIXEL_FORMAT_ARGB; + break; + case GST_MAKE_FOURCC ('B', 'G', 'R', 'A'): + case GST_MAKE_FOURCC ('B', 'G', 'R', 'x'): + pixtype = MM_PIXEL_FORMAT_RGBA; + break; + case GST_MAKE_FOURCC ('J', 'P', 'E', 'G'): + case GST_MAKE_FOURCC ('P', 'N', 'G', ' '): + pixtype = MM_PIXEL_FORMAT_ENCODED; + break; + default: + _mmcam_dbg_log("Not supported fourcc type(%x)", fourcc); + pixtype = MM_PIXEL_FORMAT_INVALID; + break; + } + + return pixtype; +} + + +gboolean +_mmcamcorder_add_elements_to_bin( GstBin *bin, GList *element_list ) +{ + GList *local_list = element_list; + _MMCamcorderGstElement *element = NULL; + + mmf_return_val_if_fail( bin && local_list, FALSE ); + + while( local_list ) + { + element = (_MMCamcorderGstElement*)local_list->data; + if( element && element->gst ) + { + if( !gst_bin_add( bin, GST_ELEMENT(element->gst) ) ) + { + _mmcam_dbg_err( "Add element [%s] to bin [%s] FAILED", + GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), + GST_ELEMENT_NAME(GST_ELEMENT(bin)) ); + return FALSE; + } + else + { + _mmcam_dbg_log( "Add element [%s] to bin [%s] OK", + GST_ELEMENT_NAME(GST_ELEMENT(element->gst)), + GST_ELEMENT_NAME(GST_ELEMENT(bin)) ); + } + } + + local_list = local_list->next; + } + + return TRUE; +} + +gboolean +_mmcamcorder_link_elements( GList *element_list ) +{ + GList *local_list = element_list; + _MMCamcorderGstElement *element = NULL; + _MMCamcorderGstElement *pre_element = NULL; + + mmf_return_val_if_fail( local_list, FALSE ); + + pre_element = (_MMCamcorderGstElement*)local_list->data; + local_list = local_list->next; + + while( local_list ) + { + element = (_MMCamcorderGstElement*)local_list->data; + if( element && element->gst ) + { + if( _MM_GST_ELEMENT_LINK( GST_ELEMENT(pre_element->gst), GST_ELEMENT(element->gst) ) ) + { + _mmcam_dbg_log( "Link [%s] to [%s] OK", + GST_ELEMENT_NAME(GST_ELEMENT(pre_element->gst)), + GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) ); + } + else + { + _mmcam_dbg_err( "Link [%s] to [%s] FAILED", + GST_ELEMENT_NAME(GST_ELEMENT(pre_element->gst)), + GST_ELEMENT_NAME(GST_ELEMENT(element->gst)) ); + return FALSE; + } + } + + pre_element = element; + local_list = local_list->next; + } + + 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; + guint32 src_fourcc = 0; + gboolean do_encode = FALSE; + jpegenc_parameter enc_param; + static jpegenc_info enc_info = {-1,}; + + _mmcam_dbg_log("START"); + + mmf_return_val_if_fail(src_data && result_data && result_length, FALSE); + + CLEAR(enc_param); + + if (enc_info.sw_support == -1) { + CLEAR(enc_info); + __ta__("camsrcjpegenc_get_info", + camsrcjpegenc_get_info(&enc_info); + ); + } + + 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) { + /* 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]) { + do_encode = TRUE; + break; + } + } + + 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; + } + } else { + _mmcam_dbg_err("S/W JPEG codec does NOT support format [%d]", src_format); + 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; + } +} + + +static guint16 get_language_code(const char *str) +{ + return (guint16) (((str[0]-0x60) & 0x1F) << 10) + (((str[1]-0x60) & 0x1F) << 5) + ((str[2]-0x60) & 0x1F); +} + +static gchar * str_to_utf8(const gchar *str) +{ + return g_convert (str, -1, "UTF-8", "ASCII", NULL, NULL, NULL); +} + +static inline gboolean write_tag(FILE *f, const gchar *tag) +{ + while(*tag) + FPUTC_CHECK(*tag++, f); + + return TRUE; +} + +static inline gboolean write_to_32(FILE *f, guint val) +{ + FPUTC_CHECK(val >> 24, f); + FPUTC_CHECK(val >> 16, f); + FPUTC_CHECK(val >> 8, f); + FPUTC_CHECK(val, f); + return TRUE; +} + +static inline gboolean write_to_16(FILE *f, guint val) +{ + FPUTC_CHECK(val >> 8, f); + FPUTC_CHECK(val, f); + return TRUE; +} + +static inline gboolean write_to_24(FILE *f, guint val) +{ + write_to_16(f, val >> 8); + FPUTC_CHECK(val, f); + return TRUE; +} diff --git a/src/mm_camcorder_videorec.c b/src/mm_camcorder_videorec.c new file mode 100644 index 0000000..631f389 --- /dev/null +++ b/src/mm_camcorder_videorec.c @@ -0,0 +1,1496 @@ +/* + * libmm-camcorder + * + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Contact: Jeongmo Yang <jm80.yang@samsung.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*======================================================================================= +| INCLUDE FILES | +=======================================================================================*/ +#include "mm_camcorder_internal.h" +#include "mm_camcorder_videorec.h" + +/*--------------------------------------------------------------------------------------- +| GLOBAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------------------*/ +#define _MMCAMCORDER_LOCATION_INFO // for add gps information + +/*--------------------------------------------------------------------------------------- +| LOCAL VARIABLE DEFINITIONS for internal | +---------------------------------------------------------------------------------------*/ +#define _MMCAMCORDER_MINIMUM_FRAME 10 +#define _MMCAMCORDER_RETRIAL_COUNT 10 +#define _MMCAMCORDER_FRAME_WAIT_TIME 200000 /* ms */ +#define _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL 5 + +/*--------------------------------------------------------------------------------------- +| LOCAL FUNCTION PROTOTYPES: | +---------------------------------------------------------------------------------------*/ +/* STATIC INTERNAL FUNCTION */ +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_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); +static gboolean __mmcamcorder_eventprobe_monitor(GstPad *pad, GstEvent *event, gpointer u_data); + +/*======================================================================================= +| FUNCTION DEFINITIONS | +=======================================================================================*/ +/*--------------------------------------------------------------------------------------- +| GLOBAL FUNCTION DEFINITIONS: | +---------------------------------------------------------------------------------------*/ +int _mmcamcorder_add_recorder_pipeline(MMHandleType handle) +{ + int err = MM_ERROR_NONE; + char* gst_element_rsink_name = NULL; + + GstPad *srcpad = NULL; + GstPad *sinkpad = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + + type_element *RecordsinkElement = 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); + + _mmcam_dbg_log(""); + + err = _mmcamcorder_check_videocodec_fileformat_compatibility( handle ); + if( err != MM_ERROR_NONE ) + { + return err; + } + + /* Create gstreamer element */ + /* Check main pipeline */ + if (!sc->element[_MMCAMCORDER_MAIN_PIPE].gst) { + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + if (sc->is_slow == FALSE) { + /* Sub pipeline */ + __ta__(" __mmcamcorder_create_audiosrc_bin", + err = _mmcamcorder_create_audiosrc_bin((MMHandleType)hcamcorder); + ); + if (err != MM_ERROR_NONE) { + return err; + } + + gst_bin_add(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), + sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst); + } + + __ta__(" _mmcamcorder_create_encodesink_bin", + err = _mmcamcorder_create_encodesink_bin((MMHandleType)hcamcorder); + ); + if (err != MM_ERROR_NONE) { + return err; + } + + gst_bin_add(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), + sc->element[_MMCAMCORDER_ENCSINK_BIN].gst); + + /* 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, "video_sink0"); + _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error); + + if (sc->is_slow == 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); + } + + _mmcamcorder_conf_get_element(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_RECORD, + "RecordsinkElement", + &RecordsinkElement); + _mmcamcorder_conf_get_value_element_name(RecordsinkElement, &gst_element_rsink_name); + + /* set data probe function */ + + /* register message cb */ + + /* set data probe function for audio */ + + if (sc->is_slow == 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); + gst_object_unref(sinkpad); + sinkpad = NULL; + + /* for voice mute */ + srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src"); + MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC, + __mmcamcorder_audio_dataprobe_audio_mute, hcamcorder); + gst_object_unref(srcpad); + srcpad = NULL; + + if (sc->element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst) { + srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC_QUE].gst, "src"); + MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC, + __mmcamcorder_eventprobe_monitor, hcamcorder); + gst_object_unref(srcpad); + srcpad = NULL; + } + } + + if (sc->element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst) { + srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_VENC_QUE].gst, "src"); + MMCAMCORDER_ADD_EVENT_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC, + __mmcamcorder_eventprobe_monitor, hcamcorder); + gst_object_unref(srcpad); + srcpad = NULL; + } + + if (sc->is_slow) { + 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); + gst_object_unref(sinkpad); + sinkpad = NULL; + } + + if (!strcmp(gst_element_rsink_name, "filesink")) { + srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "src"); + MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC, + __mmcamcorder_video_dataprobe_record, hcamcorder); + gst_object_unref(srcpad); + srcpad = NULL; + + srcpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_AENC].gst, "src"); + MMCAMCORDER_ADD_BUFFER_PROBE(srcpad, _MMCAMCORDER_HANDLER_VIDEOREC, + __mmcamcorder_audio_dataprobe_check, hcamcorder); + gst_object_unref(srcpad); + srcpad = NULL; + } + + return MM_ERROR_NONE; + +pipeline_creation_error: + return err; +} + + +int _mmcamcorder_remove_audio_pipeline(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + GstPad *srcpad = NULL; + GstPad *sinkpad = NULL; + 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, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log(""); + + if (sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst != NULL) { + __ta__( " AudiosrcBin Set NULL", + ret = _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst, GST_STATE_NULL); + ); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Faile to change audio source state[%d]", ret); + return ret; + } + + 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_UNLINK_UNREF(srcpad, sinkpad); + + gst_bin_remove(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), + sc->element[_MMCAMCORDER_AUDIOSRC_BIN].gst); + + /* + To avoid conflicting between old elements and newly created elements, + I clean element handles here. Real elements object will be finalized as the 'unref' process goes on. + This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements. + So I clean handles first, make them unref later. Audio recording, however, isn't needed this process. + It's because the pipeline of audio recording destroys at the same time, + and '_mmcamcorder_element_release_noti' will perfom removing handle. + */ + _mmcamcorder_remove_element_handle(handle, _MMCAMCORDER_AUDIOSRC_BIN, _MMCAMCORDER_AUDIOSRC_NS); + + _mmcam_dbg_log("Audio pipeline removed"); + } + + return MM_ERROR_NONE; +} + + +int _mmcamcorder_remove_encoder_pipeline(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + GstPad *srcpad = NULL; + GstPad *sinkpad = NULL; + GstPad *reqpad = NULL; + 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, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log(""); + + if (sc->element[_MMCAMCORDER_ENCSINK_BIN].gst != NULL) { + __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); + return ret; + } + + 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, "video_sink0"); + _MM_GST_PAD_UNLINK_UNREF(srcpad, sinkpad); + + /* release request pad */ + reqpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "audio"); + if (reqpad) { + gst_element_release_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad); + gst_object_unref(reqpad); + reqpad = NULL; + } + + reqpad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "video"); + if (reqpad) { + gst_element_release_request_pad(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, reqpad); + gst_object_unref(reqpad); + reqpad = NULL; + } + + gst_bin_remove(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), + sc->element[_MMCAMCORDER_ENCSINK_BIN].gst); + + /* + To avoid conflicting between old elements and newly created elements, + I clean element handles here. Real elements object will be finalized as the 'unref' process goes on. + This is a typical problem of unref. Even though I unref bin here, it takes much time to finalize each elements. + So I clean handles first, make them unref later. Audio recording, however, isn't needed this process. + It's because the pipeline of audio recording destroys at the same time, + and '_mmcamcorder_element_release_noti' will perfom removing handle. + */ + _mmcamcorder_remove_element_handle(handle, _MMCAMCORDER_AUDIOSRC_QUE, _MMCAMCORDER_AUDIOSRC_ENC); /* Encode bin has audio encoder too. */ + _mmcamcorder_remove_element_handle(handle, _MMCAMCORDER_ENCSINK_BIN, _MMCAMCORDER_ENCSINK_SINK); + + _mmcam_dbg_log("Encoder pipeline removed"); + } + + return MM_ERROR_NONE; +} + + +int _mmcamcorder_remove_recorder_pipeline(MMHandleType handle) +{ + int ret = MM_ERROR_NONE; + 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, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log(""); + + if (!sc->element[_MMCAMCORDER_MAIN_PIPE].gst) { + _mmcam_dbg_warn("pipeline is not existed."); + return MM_ERROR_NONE; + } + + _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_VIDEOREC); + + ret = _mmcamcorder_remove_encoder_pipeline(handle); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Fail to remove encoder pipeline"); + return ret; + } + + ret = _mmcamcorder_remove_audio_pipeline(handle); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_err("Fail to remove audio pipeline"); + return ret; + } + + return ret; +} + + +void _mmcamcorder_destroy_video_pipeline(MMHandleType handle) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + GstPad *reqpad1 = NULL; + GstPad *reqpad2 = NULL; + + mmf_return_if_fail(hcamcorder); + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + + mmf_return_if_fail(sc); + mmf_return_if_fail(sc->element); + + _mmcam_dbg_log(""); + + if (sc->element[_MMCAMCORDER_MAIN_PIPE].gst) { + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSINK_QUE].gst, "empty-buffers", TRUE); + _mmcamcorder_gst_set_state(handle, sc->element[_MMCAMCORDER_MAIN_PIPE].gst, GST_STATE_NULL); + + _mmcamcorder_remove_all_handlers((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_CATEGORY_ALL); + + reqpad1 = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, "src0"); + reqpad2 = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, "src1"); + gst_element_release_request_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, reqpad1); + gst_element_release_request_pad(sc->element[_MMCAMCORDER_VIDEOSRC_TEE].gst, reqpad2); + gst_object_unref(reqpad1); + gst_object_unref(reqpad2); + + /* object disposing problem happen. */ + _mmcam_dbg_log("Reference count of pipeline(%d)", GST_OBJECT_REFCOUNT_VALUE(sc->element[_MMCAMCORDER_MAIN_PIPE].gst)); + gst_object_unref(sc->element[_MMCAMCORDER_MAIN_PIPE].gst); + } +} + + +int _mmcamcorder_video_command(MMHandleType handle, int command) +{ + int size = 0; + int fileformat = 0; + int ret = MM_ERROR_NONE; + char *temp_filename = NULL; + char *err_name = NULL; + + gint fps = 0; + gint slow_fps = 0; + GstElement *pipeline = NULL; + GstPad *pad = NULL; + + _MMCamcorderVideoInfo *info = NULL; + _MMCamcorderSubContext *sc = NULL; + mmf_camcorder_t *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->info, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + info = sc->info; + + _mmcam_dbg_log("Command(%d)", command); + + pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; + + switch (command) { + case _MMCamcorder_CMD_RECORD: + { + if (_mmcamcorder_get_state((MMHandleType)hcamcorder) != MM_CAMCORDER_STATE_PAUSED) { + guint imax_time = 0; + + /* Play record start sound */ + _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_START_SND, TRUE); + + /* Recording */ + _mmcam_dbg_log("Record Start"); + + ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED); + if (ret != MM_ERROR_NONE) { + goto _ERR_CAMCORDER_VIDEO_COMMAND; + } + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_RECORD, + "DropVideoFrame", + &(sc->drop_vframe)); + + _mmcamcorder_conf_get_value_int(hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_RECORD, + "PassFirstVideoFrame", + &(sc->pass_first_vframe)); + + _mmcam_dbg_log("Drop video frame count[%d], Pass fisrt video frame count[%d]", + sc->drop_vframe, sc->pass_first_vframe); + + ret = mm_camcorder_get_attributes(handle, &err_name, + MMCAM_CAMERA_FPS, &fps, + "camera-slow-motion-fps", &slow_fps, + MMCAM_FILE_FORMAT, &fileformat, + MMCAM_TARGET_FILENAME, &temp_filename, &size, + MMCAM_TARGET_TIME_LIMIT, &imax_time, + MMCAM_FILE_FORMAT, &(info->fileformat), + NULL); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, ret); + SAFE_FREE (err_name); + goto _ERR_CAMCORDER_VIDEO_COMMAND; + } + + /* set max time */ + if (imax_time <= 0) { + info->max_time = 0; /* do not check */ + } else { + 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); + } + + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hold-af-after-capturing", TRUE); + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "req-negotiation", TRUE); + + ret =_mmcamcorder_add_recorder_pipeline((MMHandleType)hcamcorder); + if (ret != MM_ERROR_NONE) { + goto _ERR_CAMCORDER_VIDEO_COMMAND; + } + + info->filename = strdup(temp_filename); + if (!info->filename) { + _mmcam_dbg_err("strdup was failed"); + goto _ERR_CAMCORDER_VIDEO_COMMAND; + } + + _mmcam_dbg_log("Record start : set file name using attribute - %s ",info->filename); + + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_SINK].gst, "location", info->filename); + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", 0); + + /* Adjust display FPS */ + sc->display_interval = 0; + sc->previous_slot_time = 0; + + /* gst_element_set_base_time(GST_ELEMENT(pipeline), (GstClockTime)0); + if you want to use audio clock, enable this block + for change recorder_pipeline state to paused. */ + __ta__(" _MMCamcorder_CMD_RECORD:GST_STATE_PAUSED2", + ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PAUSED); + ); + if (ret != MM_ERROR_NONE) { + /* Remove recorder pipeline and recording file which size maybe zero */ + __ta__(" record fail:remove_recorder_pipeline", + _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder); + ); + if (info->filename) { + _mmcam_dbg_log("file delete(%s)", info->filename); + unlink(info->filename); + g_free(info->filename); + info->filename = NULL; + } + goto _ERR_CAMCORDER_VIDEO_COMMAND; + } + + /**< To fix video recording hanging + 1. use gst_element_set_start_time() instead of gst_pipeline_set_new_stream_time() + 2. Set (GstClockTime)1 instead of (GstClockTime)0. Because of strict check in gstreamer 0.25, + basetime wouldn't change if you set (GstClockTime)0. + 3. Move set start time position below PAUSED of pipeline. + */ + gst_element_set_start_time(GST_ELEMENT(pipeline), (GstClockTime)1); + info->video_frame_count = 0; + info->audio_frame_count = 0; + info->filesize = 0; + sc->ferror_send = FALSE; + sc->ferror_count = 0; + sc->error_occurs = FALSE; + sc->bget_eos = FALSE; + + __ta__(" _MMCamcorder_CMD_RECORD:GST_STATE_PLAYING2", + ret = _mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); + ); + if (ret != MM_ERROR_NONE) { + /* Remove recorder pipeline and recording file which size maybe zero */ + __ta__(" record fail:remove_recorder_pipeline", + _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder); + ); + if (info->filename) { + _mmcam_dbg_log("file delete(%s)", info->filename); + unlink(info->filename); + g_free(info->filename); + info->filename = NULL; + } + goto _ERR_CAMCORDER_VIDEO_COMMAND; + } + } else { + /* Resume case */ + int video_enc = 0; + + MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", FALSE); + + mm_camcorder_get_attributes(handle, NULL, MMCAM_VIDEO_ENCODER, &video_enc, NULL); + if (video_enc == MM_VIDEO_CODEC_MPEG4) { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "force-intra", TRUE); + } + + _mmcam_dbg_log("Object property settings done"); + } + } + break; + case _MMCamcorder_CMD_PAUSE: + { + int count = 0; + + if (info->b_commiting) { + _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", command); + return MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + } + + for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) { + if (sc->is_slow) { + /* check only video frame */ + if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) { + break; + } else if (count == _MMCAMCORDER_RETRIAL_COUNT) { + _mmcam_dbg_err("Pause fail, frame count %" G_GUINT64_FORMAT "", + info->video_frame_count); + return MM_ERROR_CAMCORDER_INVALID_CONDITION; + } else { + _mmcam_dbg_warn("Waiting for enough video frame, retrial[%d], frame %" G_GUINT64_FORMAT "", + count, info->video_frame_count); + } + + usleep(_MMCAMCORDER_FRAME_WAIT_TIME); + } else { + /* check both of video and audio frame */ + if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) { + break; + } else if (count == _MMCAMCORDER_RETRIAL_COUNT) { + _mmcam_dbg_err("Pause fail, frame count VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]", + info->video_frame_count, info->audio_frame_count); + return MM_ERROR_CAMCORDER_INVALID_CONDITION; + } else { + _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]", + count, info->video_frame_count, info->audio_frame_count); + } + + usleep(_MMCAMCORDER_FRAME_WAIT_TIME); + } + } + /* tee block */ + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "runtime-pause", TRUE); + + break; + } + case _MMCamcorder_CMD_CANCEL: + { + if (info->b_commiting) { + _mmcam_dbg_warn("now on commiting previous file!!(command : %d)", 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"); + } + + __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); + if (ret != MM_ERROR_NONE) { + goto _ERR_CAMCORDER_VIDEO_COMMAND; + } + + __ta__(" __mmcamcorder_remove_recorder_pipeline", + _mmcamcorder_remove_recorder_pipeline((MMHandleType)hcamcorder); + ); + + /* remove target file */ + if (info->filename) { + _mmcam_dbg_log("file delete(%s)", info->filename); + unlink(info->filename); + g_free(info->filename); + info->filename = NULL; + } + + sc->isMaxsizePausing = FALSE; + sc->isMaxtimePausing = FALSE; + + sc->display_interval = 0; + sc->previous_slot_time = 0; + info->video_frame_count = 0; + info->audio_frame_count = 0; + info->filesize =0; + + __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: + { + int count = 0; + + if (info->b_commiting) { + _mmcam_dbg_err("now on commiting previous file!!(command : %d)", command); + return MM_ERROR_CAMCORDER_CMD_IS_RUNNING; + } else { + _mmcam_dbg_log("_MMCamcorder_CMD_COMMIT : start"); + info->b_commiting = TRUE; + } + + for (count = 0 ; count <= _MMCAMCORDER_RETRIAL_COUNT ; count++) { + if (sc->is_slow) { + /* check only video frame */ + if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME) { + break; + } else if (count == _MMCAMCORDER_RETRIAL_COUNT) { + _mmcam_dbg_err("Commit fail, frame count is %" G_GUINT64_FORMAT "", + info->video_frame_count); + info->b_commiting = FALSE; + return MM_ERROR_CAMCORDER_INVALID_CONDITION; + } else { + _mmcam_dbg_warn("Waiting for enough video frame, retrial [%d], frame %" G_GUINT64_FORMAT "", + count, info->video_frame_count); + } + + usleep(_MMCAMCORDER_FRAME_WAIT_TIME); + } else { + /* check both of video and audio frame */ + if (info->video_frame_count >= _MMCAMCORDER_MINIMUM_FRAME && info->audio_frame_count) { + break; + } else if (count == _MMCAMCORDER_RETRIAL_COUNT) { + _mmcam_dbg_err("Commit fail, VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]", + info->video_frame_count, info->audio_frame_count); + + info->b_commiting = FALSE; + return MM_ERROR_CAMCORDER_INVALID_CONDITION; + } else { + _mmcam_dbg_warn("Waiting for enough frames, retrial [%d], VIDEO[%" G_GUINT64_FORMAT "], AUDIO [%" G_GUINT64_FORMAT "]", + count, info->video_frame_count, info->audio_frame_count); + } + + usleep(_MMCAMCORDER_FRAME_WAIT_TIME); + } + } + + 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; + int ret = 0; + + _mmcam_dbg_err("Committing Error case"); + + video = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSINK_SINK].gst, "sink"); + ret = gst_pad_send_event (video, gst_event_new_eos()); + _mmcam_dbg_err("Sending EOS video sink : %d", ret); + gst_object_unref(video); + + video = gst_element_get_static_pad(sc->element[_MMCAMCORDER_ENCSINK_VENC].gst, "src"); + gst_pad_push_event (video, gst_event_new_flush_start()); + gst_pad_push_event (video, gst_event_new_flush_stop()); + ret = gst_pad_push_event (video, gst_event_new_eos()); + _mmcam_dbg_err("Sending EOS video encoder src pad : %d", ret); + gst_object_unref(video); + + if (!sc->is_slow) { + 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()); + ret = gst_element_send_event(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos()); + _mmcam_dbg_err("Sending EOS audio encoder src pad : %d", ret); + gst_object_unref(audio); + } + } else { + if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst != NULL) { + ret = gst_element_send_event(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, gst_event_new_eos()); + _mmcam_dbg_warn("send eos to videosrc result : %d", ret); + } + + if (sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst != NULL) { + pad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, "src"); + ret = gst_element_send_event(sc->element[_MMCAMCORDER_AUDIOSRC_SRC].gst, gst_event_new_eos()); + gst_object_unref(pad); + pad = NULL; + + _mmcam_dbg_warn("send eos to audiosrc result : %d", ret); + } + } + + if (hcamcorder->quick_device_close) { + _mmcam_dbg_warn("quick_device_close"); + /* close device quickly */ + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "quick-device-close",TRUE); + } + + /* sc */ + sc->display_interval = 0; + sc->previous_slot_time = 0; + + /* 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; + } + + /* 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) { + 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; + goto _ERR_CAMCORDER_VIDEO_COMMAND; + } + + return MM_ERROR_NONE; + +_ERR_CAMCORDER_VIDEO_COMMAND: + if (ret != MM_ERROR_NONE && sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst != NULL) { + 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); + } + + return ret; +} + + +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; + GstElement *pipeline = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle); + _MMCamcorderSubContext *sc = NULL; + _MMCamcorderVideoInfo *info = NULL; + _MMCamcorderMsgItem msg; + MMCamRecordingReport *report = NULL; + + mmf_return_val_if_fail(hcamcorder, FALSE); + + sc = MMF_CAMCORDER_SUBCONTEXT(handle); + mmf_return_val_if_fail(sc, FALSE); + mmf_return_val_if_fail(sc->info, FALSE); + + info = sc->info; + + _mmcam_dbg_err(""); + + MMTA_ACUM_ITEM_BEGIN(" _mmcamcorder_video_handle_eos", 0); + + pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; + + /* remove blocking part */ + 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); + + _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); + } + + 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); + ); + if (ret != MM_ERROR_NONE) { + _mmcam_dbg_warn("_MMCamcorder_CMD_COMMIT:__mmcamcorder_remove_recorder_pipeline failed. error[%x]", ret); + } + + if (enabletag && !(sc->ferror_send)) { + __ta__( " _MMCamcorder_CMD_COMMIT:__mmcamcorder_add_locationinfo", + ret = __mmcamcorder_add_locationinfo((MMHandleType)hcamcorder, info->fileformat); + ); + if (ret) { + _mmcam_dbg_log("Writing location information SUCCEEDED !!"); + } else { + _mmcam_dbg_err("Writing location information FAILED !!"); + } + } + + /* 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; + } + + _mmcam_dbg_log("Set state as PLAYING"); + __ta__(" _MMCamcorder_CMD_COMMIT:GST_STATE_PLAYING", + ret =_mmcamcorder_gst_set_state(handle, pipeline, GST_STATE_PLAYING); + ); + /* Do not return when error is occurred. + Recording file was created successfully, but starting pipeline failed */ + if (ret != MM_ERROR_NONE) { + msg.id = MM_MESSAGE_CAMCORDER_ERROR; + msg.param.code = ret; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + _mmcam_dbg_err("Failed to set state PLAYING[%x]", ret); + } + + if (hcamcorder->state_change_by_system != _MMCAMCORDER_STATE_CHANGE_BY_ASM) { + /* Play record stop sound */ + __ta__(" _MMCamcorder_CMD_COMMIT:_mmcamcorder_sound_solo_play", + _mmcamcorder_sound_solo_play(handle, _MMCAMCORDER_FILEPATH_REC_STOP_SND, TRUE); + ); + } else { + _mmcam_dbg_log("Do NOT play recording stop sound because of ASM stop"); + } + + /* Send recording report to application */ + msg.id = MM_MESSAGE_CAMCORDER_CAPTURED; + report = (MMCamRecordingReport *)malloc(sizeof(MMCamRecordingReport)); + if (!report) { + _mmcam_dbg_err("Recording report fail(%s). Out of memory.", info->filename); + } else { + report->recording_filename = strdup(info->filename); + msg.param.data= report; + msg.param.code = 1; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + } + + /* Finishing */ + sc->pipeline_time = 0; + sc->pause_time = 0; + sc->isMaxsizePausing = FALSE; /*In async function, this variable should set in callback function. */ + sc->isMaxtimePausing = FALSE; + sc->error_occurs = FALSE; + + info->video_frame_count = 0; + info->audio_frame_count = 0; + info->filesize = 0; + g_free(info->filename); + info->filename = NULL; + info->b_commiting = FALSE; + + MMTA_ACUM_ITEM_END(" _mmcamcorder_video_handle_eos", 0); + MMTA_ACUM_ITEM_END("Real Commit Time", 0); + + _mmcam_dbg_err("_MMCamcorder_CMD_COMMIT : end"); + + return TRUE; +} + +/** + * This function is record video data probing function. + * If this function is linked with certain pad by gst_pad_add_buffer_probe(), + * this function will be called when data stream pass through the pad. + * + * @param[in] pad probing pad which calls this function. + * @param[in] buffer buffer which contains stream data. + * @param[in] u_data user data. + * @return This function returns true on success, or false value with error + * @remarks + * @see + */ +static gboolean __mmcamcorder_eventprobe_monitor(GstPad *pad, GstEvent *event, gpointer u_data) +{ + switch (GST_EVENT_TYPE(event)) { + case GST_EVENT_UNKNOWN: + /* upstream events */ + case GST_EVENT_QOS: + case GST_EVENT_SEEK: + case GST_EVENT_NAVIGATION: + case GST_EVENT_LATENCY: + /* downstream serialized events */ + case GST_EVENT_NEWSEGMENT : + case GST_EVENT_TAG: + case GST_EVENT_BUFFERSIZE: + _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event)); + break; + case GST_EVENT_EOS: + _mmcam_dbg_warn("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event)); + break; + /* bidirectional events */ + case GST_EVENT_FLUSH_START: + case GST_EVENT_FLUSH_STOP: + _mmcam_dbg_err("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event)); + break; + default: + _mmcam_dbg_log("[%s:%s] gots %s", GST_DEBUG_PAD_NAME(pad), GST_EVENT_TYPE_NAME(event)); + break; + } + + return TRUE; +} + + +static gboolean __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstBuffer *buffer, gpointer u_data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); + _MMCamcorderSubContext *sc = 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; + + /*_mmcam_dbg_err("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/ + + if (info->audio_frame_count == 0) { + info->filesize += (guint64)GST_BUFFER_SIZE(buffer); + info->audio_frame_count++; + return TRUE; + } + + if (sc->ferror_send || sc->isMaxsizePausing) { + _mmcam_dbg_warn("Recording is paused, drop frames"); + return FALSE; + } + + info->filesize += (guint64)GST_BUFFER_SIZE(buffer); + info->audio_frame_count++; + + return TRUE; +} + + +static gboolean __mmcamcorder_video_dataprobe_record(GstPad *pad, GstBuffer *buffer, gpointer u_data) +{ + static int count = 0; + gint ret = 0; + guint vq_size = 0; + guint aq_size = 0; + guint64 free_space = 0; + guint64 buffer_size = 0; + guint64 trailer_size = 0; + guint64 queued_buffer = 0; + char *filename = NULL; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); + _MMCamcorderMsgItem msg; + _MMCamcorderSubContext *sc = 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; + + /*_mmcam_dbg_log("[%" GST_TIME_FORMAT "]", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/ + if (sc->ferror_send) { + _mmcam_dbg_warn("file write error, drop frames"); + return FALSE; + } + + info->video_frame_count++; + if (info->video_frame_count <= (guint64)_MMCAMCORDER_MINIMUM_FRAME) { + /* _mmcam_dbg_log("Pass minimum frame: info->video_frame_count: %" G_GUINT64_FORMAT " ", + info->video_frame_count); */ + info->filesize += (guint64)GST_BUFFER_SIZE(buffer); + return TRUE; + } + + 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); + } else { + trailer_size = 0; + } + + /* to minimizing free space check overhead */ + count = count % _MMCAMCORDER_FREE_SPACE_CHECK_INTERVAL; + if (count++ == 0) { + filename = info->filename; + ret = _mmcamcorder_get_freespace(filename, &free_space); + + /*_mmcam_dbg_log("check free space for recording");*/ + + switch (ret) { + case -2: /* file not exist */ + case -1: /* failed to get free space */ + _mmcam_dbg_err("Error occured. [%d]", ret); + if (sc->ferror_count == 2 && sc->ferror_send == FALSE) { + sc->ferror_send = TRUE; + msg.id = MM_MESSAGE_CAMCORDER_ERROR; + if (ret == -2) { + msg.param.code = MM_ERROR_FILE_NOT_FOUND; + } else { + msg.param.code = MM_ERROR_FILE_READ; + } + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + } else { + sc->ferror_count++; + } + + return FALSE; /* skip this buffer */ + break; + 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); + queued_buffer = aq_size + vq_size; + + /* check free space */ + if (free_space < (_MMCAMCORDER_MINIMUM_SPACE + buffer_size + trailer_size + queued_buffer)) { + _mmcam_dbg_warn("No more space for recording!!! Recording is paused."); + _mmcam_dbg_warn("Free Space : [%" G_GUINT64_FORMAT "], trailer size : [%" G_GUINT64_FORMAT "]," \ + " buffer size : [%" G_GUINT64_FORMAT "], queued buffer size : [%" G_GUINT64_FORMAT "]", \ + free_space, trailer_size, buffer_size, queued_buffer); + + if (!sc->isMaxsizePausing) { + MMCAMCORDER_G_OBJECT_SET( sc->element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE); + sc->isMaxsizePausing = TRUE; + + msg.id = MM_MESSAGE_CAMCORDER_NO_FREE_SPACE; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + } + + return FALSE; + } + break; + } + } + + info->filesize += (guint64)buffer_size; + + return TRUE; +} + + +static gboolean __mmcamcorder_video_dataprobe_slow(GstPad *pad, GstBuffer *buffer, gpointer u_data) +{ + guint min_fps = 15; + guint64 trailer_size = 0; + static guint count = 0; + + GstClockTime b_time; + + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); + _MMCamcorderMsgItem msg; + _MMCamcorderSubContext *sc = NULL; + _MMCamcorderVideoInfo *info = NULL; + + 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); + + 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; + } + + 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); + } + + count++; + + GST_BUFFER_TIMESTAMP(buffer) = b_time * (info->multiple_fps); + + return TRUE; +} + + +static gboolean __mmcamcorder_audioque_dataprobe(GstPad *pad, GstBuffer *buffer, gpointer u_data) +{ + _MMCamcorderMsgItem msg; + guint64 trailer_size = 0; + guint64 rec_pipe_time = 0; + _MMCamcorderSubContext *sc = NULL; + GstElement *pipeline = NULL; + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); + _MMCamcorderVideoInfo *info = NULL; + + 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->element, TRUE); + + info = sc->info; + pipeline = sc->element[_MMCAMCORDER_MAIN_PIPE].gst; + + if (!GST_CLOCK_TIME_IS_VALID(GST_BUFFER_TIMESTAMP(buffer))) { + _mmcam_dbg_err( "Buffer timestamp is invalid, check it"); + return TRUE; + } + + rec_pipe_time = GST_TIME_AS_MSECONDS(GST_BUFFER_TIMESTAMP(buffer)); + + 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; + } + + 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 int)rec_pipe_time; + msg.param.recording_status.filesize = (unsigned int)((info->filesize + trailer_size) >> 10); + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + + msg.id = MM_MESSAGE_CAMCORDER_TIME_LIMIT; + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + } + + 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); + _mmcamcroder_send_message((MMHandleType)hcamcorder, &msg); + + return TRUE; +} + + +static gboolean __mmcamcorder_audio_dataprobe_audio_mute(GstPad *pad, GstBuffer *buffer, gpointer u_data) +{ + mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data); + double volume = 0.0; + int format = 0; + int channel = 0; + int err = MM_ERROR_UNKNOWN; + char *err_name = NULL; + + mmf_return_val_if_fail(buffer, FALSE); + mmf_return_val_if_fail(hcamcorder, FALSE); + + /*_mmcam_dbg_log("AUDIO SRC time stamp : [%" GST_TIME_FORMAT "] \n", GST_TIME_ARGS(GST_BUFFER_TIMESTAMP(buffer)));*/ + err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, &err_name, + MMCAM_AUDIO_VOLUME, &volume, + MMCAM_AUDIO_FORMAT, &format, + MMCAM_AUDIO_CHANNEL, &channel, + NULL); + if (err != MM_ERROR_NONE) { + _mmcam_dbg_warn("Get attrs fail. (%s:%x)", err_name, err); + SAFE_FREE(err_name); + return err; + } + + /* Set audio stream NULL */ + if (volume == 0.0) { + memset(GST_BUFFER_DATA(buffer), 0, GST_BUFFER_SIZE(buffer)); + } + + /* CALL audio stream callback */ + if (hcamcorder->astream_cb && buffer && GST_BUFFER_DATA(buffer)) { + MMCamcorderAudioStreamDataType stream; + + if (_mmcamcorder_get_state((MMHandleType)hcamcorder) < MM_CAMCORDER_STATE_PREPARE) { + _mmcam_dbg_warn("Not ready for stream callback"); + return TRUE; + } + + /*_mmcam_dbg_log("Call video steramCb, data[%p], Width[%d],Height[%d], Format[%d]", + GST_BUFFER_DATA(buffer), width, height, format);*/ + + stream.data = (void *)GST_BUFFER_DATA(buffer); + stream.format = format; + stream.channel = channel; + stream.length = GST_BUFFER_SIZE(buffer); + stream.timestamp = (unsigned int)(GST_BUFFER_TIMESTAMP(buffer)/1000000); /* nano -> milli second */ + + _MMCAMCORDER_LOCK_ASTREAM_CALLBACK(hcamcorder); + + if (hcamcorder->astream_cb) { + hcamcorder->astream_cb(&stream, hcamcorder->astream_cb_param); + } + + _MMCAMCORDER_UNLOCK_ASTREAM_CALLBACK(hcamcorder); + } + + return TRUE; +} + + +static gboolean __mmcamcorder_add_locationinfo(MMHandleType handle, int fileformat) +{ + gboolean bret = FALSE; + + switch (fileformat) { + case MM_FILE_FORMAT_3GP: + case MM_FILE_FORMAT_MP4: + bret = __mmcamcorder_add_locationinfo_mp4(handle); + break; + default: + _mmcam_dbg_warn("Unsupported fileformat to insert location info (%d)", fileformat); + break; + } + + return bret; +} + + +static gboolean __mmcamcorder_add_locationinfo_mp4(MMHandleType handle) +{ + FILE *f = NULL; + guchar buf[4]; + guint64 udta_size = 0; + gint64 current_pos = 0; + gint64 moov_pos = 0; + gint64 udta_pos = 0; + gdouble longitude = 0; + gdouble latitude = 0; + gdouble altitude = 0; + int err = 0; + char *err_name = NULL; + _MMCamcorderLocationInfo location_info = {0,}; + + _MMCamcorderVideoInfo *info = NULL; + 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, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + mmf_return_val_if_fail(sc->info, MM_ERROR_CAMCORDER_NOT_INITIALIZED); + + _mmcam_dbg_log(""); + + info = sc->info; + + f = fopen(info->filename, "rb+"); + if (f == NULL) { + 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) { + _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); + location_info.latitude = _mmcamcorder_double_to_fix(latitude); + location_info.altitude = _mmcamcorder_double_to_fix(altitude); + + /* 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'))) { + _mmcam_dbg_log("find udta container"); + + /* read size */ + if (fseek(f, -8L, SEEK_CUR) != 0) { + goto fail; + } + + udta_pos = ftell(f); + if (udta_pos < 0) { + goto ftell_fail; + } + + fread(&buf, sizeof(char), sizeof(buf), f); + udta_size = _mmcamcorder_get_container_size(buf); + + /* goto end of udta and write 'loci' box */ + if (fseek(f, (udta_size-4L), SEEK_CUR) != 0) { + goto fail; + } + + if (!_mmcamcorder_write_loci(f, location_info)) { + goto fail; + } + + current_pos = ftell(f); + if (current_pos < 0) { + goto ftell_fail; + } + + if (!_mmcamcorder_update_size(f, udta_pos, current_pos)) { + goto fail; + } + } else { + _mmcam_dbg_log("No udta container"); + if (fseek(f, 0, SEEK_END) != 0) { + goto fail; + } + + if (!_mmcamcorder_write_udta(f, location_info)) { + goto fail; + } + } + + /* find moov container. + 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 (fseek(f, -8L, SEEK_CUR) !=0) { + goto fail; + } + + moov_pos = ftell(f); + if (moov_pos < 0) { + goto ftell_fail; + } + + if (!_mmcamcorder_update_size(f, moov_pos, current_pos)) { + goto fail; + } + } else { + _mmcam_dbg_err("No 'moov' container"); + goto fail; + } + + fclose(f); + return TRUE; + +fail: + fclose(f); + return FALSE; + +ftell_fail: + _mmcam_dbg_err("ftell() returns negative value."); + fclose(f); + return FALSE; +} |