Fix Svace issue
[platform/core/multimedia/libmm-camcorder.git] / src / mm_camcorder_stillshot.c
index 8d01346..a9b41ea 100644 (file)
 #include <libexif/exif-utils.h>
 #include <libexif/exif-data.h>
 
+#ifdef _MMCAMCORDER_CAMERA_BOOST_SUPPORT
+#include "mm_camcorder_boost.h"
+#endif /* _MMCAMCORDER_CAMERA_BOOST_SUPPORT */
+
+
 /*---------------------------------------------------------------------------------------
 |    GLOBAL VARIABLE DEFINITIONS for internal                                          |
 ---------------------------------------------------------------------------------------*/
@@ -59,15 +64,34 @@ do { \
 |    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 int __mmcamcorder_image_cmd_capture(MMHandleType handle);
+static int __mmcamcorder_image_cmd_preview_start(MMHandleType handle);
+static int __mmcamcorder_image_cmd_preview_stop(MMHandleType handle);
+
+static int __mmcamcorder_capture_mode_init_camera_control(MMHandleType handle);
+static int __mmcamcorder_capture_mode_init_encodebin(MMHandleType handle);
+static int __mmcamcorder_capture_mode_init_image_pad(MMHandleType handle);
+static int __mmcamcorder_capture_mode_deinit_encodebin(MMHandleType handle);
+
+static int __mmcamcorder_extra_preview_mode_init_camera_control(mmf_camcorder_t *hcamcorder);
+static int __mmcamcorder_extra_preview_mode_deinit_camera_control(mmf_camcorder_t *hcamcorder);
+static int __mmcamcorder_extra_preview_mode_init_pipeline(MMHandleType handle, MMCamcorderExtraPreviewMode mode);
+static int __mmcamcorder_extra_preview_mode_deinit_pipeline(MMHandleType handle, MMCamcorderExtraPreviewMode mode);
+
+static int __mmcamcorder_set_exif_basic_info(MMHandleType handle, int image_width, int image_height);
+static int __mmcamcorder_update_exif_info(MMHandleType handle, void *imagedata, int imgln);
+static void __mmcamcorder_init_stillshot_info(MMHandleType handle);
+static void __mmcamcorder_get_capture_data_from_buffer(MMCamcorderCaptureDataType *capture_data, int pixtype, GstSample *sample);
+static void __mmcamcorder_release_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType *dest, int tag_enable, int provide_exif);
+static int __mmcamcorder_capture_save_exifinfo(MMHandleType handle, MMCamcorderCaptureDataType *original, MMCamcorderCaptureDataType *thumbnail, int provide_exif);
+static int __mmcamcorder_set_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType *dest, MMCamcorderCaptureDataType *thumbnail, int provide_exif);
+
+static gboolean __mmcamcorder_handoff_callback_capture(GstElement *fakesink, GstBuffer *buffer, GstPad *pad, gpointer u_data);
+static gboolean __mmcamcorder_handoff_callback_extra_preview(GstElement *fakesink, GstBuffer *buffer, GstPad *pad, gpointer u_data);
+
 static void __mmcamcorder_image_capture_cb(GstElement *element, GstSample *sample1, GstSample *sample2, GstSample *sample3, gpointer u_data);
 static void __mmcamcorder_extra_preview_stream_cb(GstElement *element, int stream_id, GstSample *sample, gpointer u_data);
-
-/* sound status changed callback */
-static void __sound_status_changed_cb(keynode_t* node, void *data);
+static void __mmcamcorder_sound_status_changed_cb(keynode_t* node, void *data);
 
 /*=======================================================================================
 |  FUNCTION DEFINITIONS                                                                        |
@@ -78,7 +102,7 @@ static void __sound_status_changed_cb(keynode_t* node, void *data);
 ---------------------------------------------------------------------------------------*/
 
 
-int _mmcamcorder_create_stillshot_pipeline(MMHandleType handle)
+static int __mmcamcorder_capture_mode_init_encodebin(MMHandleType handle)
 {
        int err = MM_ERROR_UNKNOWN;
        GstPad *srcpad = NULL;
@@ -107,34 +131,34 @@ int _mmcamcorder_create_stillshot_pipeline(MMHandleType handle)
        /* add element and encodesink bin to encode main pipeline */
        gst_bin_add_many(GST_BIN(sc->encode_element[_MMCAMCORDER_ENCODE_MAIN_PIPE].gst),
                sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst,
-               sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst,
+               sc->encode_element[_MMCAMCORDER_ENCSINK_CAPS].gst,
                sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst,
                NULL);
 
        /* Link each element : appsrc - capsfilter - encodesink bin */
        srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src");
-       sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "sink");
+       sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_CAPS].gst, "sink");
        _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
 
-       srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "src");
+       srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_CAPS].gst, "src");
        sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "image_sink0");
        _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error);
 
        /* connect handoff signal to get capture data */
        MMCAMCORDER_SIGNAL_CONNECT(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst,
                _MMCAMCORDER_HANDLER_STILLSHOT, "handoff",
-               G_CALLBACK(__mmcamcorder_handoff_callback),
+               G_CALLBACK(__mmcamcorder_handoff_callback_capture),
                hcamcorder);
 
        return MM_ERROR_NONE;
 
 pipeline_creation_error:
-       _mmcamcorder_remove_stillshot_pipeline(handle);
+       __mmcamcorder_capture_mode_deinit_encodebin(handle);
        return err;
 }
 
 
-int _mmcamcorder_connect_capture_signal(MMHandleType handle)
+static int __mmcamcorder_capture_mode_init_camera_control(MMHandleType handle)
 {
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
        _MMCamcorderSubContext *sc = NULL;
@@ -157,55 +181,378 @@ int _mmcamcorder_connect_capture_signal(MMHandleType handle)
 }
 
 
-int _mmcamcorder_initialize_extra_preview_stream(MMHandleType handle)
+static int __mmcamcorder_capture_mode_init_image_pad(MMHandleType handle)
 {
-       int i = 0;
+       int err = MM_ERROR_NONE;
+       int capture_width = 0;
+       int capture_height = 0;
+       int capture_quality = 0;
+       char *err_name = NULL;
+       gchar *caps_string = NULL;
+       GstCaps *caps = NULL;
+       GList *element_list = NULL;
+
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
        _MMCamcorderSubContext *sc = NULL;
-       GstCameraControl *control = NULL;
-       _MMCamcorderExtraPreviewStreamFormat *e_fmt = 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);
+
+       err = mm_camcorder_get_attributes(handle, &err_name,
+               MMCAM_CAPTURE_WIDTH, &capture_width,
+               MMCAM_CAPTURE_HEIGHT, &capture_height,
+               MMCAM_IMAGE_ENCODER_QUALITY, &capture_quality,
+               NULL);
+       if (err != MM_ERROR_NONE) {
+               MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, err);
+               SAFE_FREE(err_name);
+               return err;
+       }
+
+       _MMCAMCORDER_ELEMENT_MAKE(sc, sc->element, _MMCAMCORDER_VIDEOSRC_CAP_CAPS, "capsfilter", "vsrc_c_c", element_list, err);
+       _MMCAMCORDER_ELEMENT_MAKE(sc, sc->element, _MMCAMCORDER_VIDEOSRC_CAP_SINK, "fakesink", "vsrc_c_s", element_list, err);
+
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_CAP_SINK].gst, "sync", TRUE);
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_CAP_SINK].gst, "async", FALSE);
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_CAP_SINK].gst, "enable-last-sample", FALSE);
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_CAP_SINK].gst, "signal-handoffs", TRUE);
+
+       caps = gst_caps_new_simple("image/jpeg",
+               "width", G_TYPE_INT, capture_width,
+               "height", G_TYPE_INT, capture_height,
+               NULL);
+       if (!caps) {
+               MMCAM_LOG_ERROR("caps for capture failed");
+               err = MM_ERROR_CAMCORDER_GST_LINK;
+               goto pipeline_creation_error;
+       }
+
+       caps_string = gst_caps_to_string(caps);
+       if (caps_string) {
+               MMCAM_LOG_INFO("set caps for capture[%s]", caps_string);
+               g_free(caps_string);
+               caps_string = NULL;
+       }
+
+       MMCAMCORDER_G_OBJECT_SET_POINTER(sc->element[_MMCAMCORDER_VIDEOSRC_CAP_CAPS].gst, "caps", caps);
+       gst_caps_unref(caps);
+
+       /* add elements to main pipeline */
+       if (!_mmcamcorder_add_elements_to_bin(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), element_list)) {
+               MMCAM_LOG_ERROR("element_list add error.");
+               err = MM_ERROR_CAMCORDER_RESOURCE_CREATION;
+               goto pipeline_creation_error;
+       }
+
+       /* link elements */
+       if (!gst_element_link_pads(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "image_%u",
+               sc->element[_MMCAMCORDER_VIDEOSRC_CAP_CAPS].gst, "sink")) {
+               MMCAM_LOG_ERROR("capture pad link failed");
+               err = MM_ERROR_CAMCORDER_GST_LINK;
+               goto pipeline_creation_error;
+       }
+
+       if (!_mmcamcorder_link_elements(element_list)) {
+               MMCAM_LOG_ERROR("element link error.");
+               err = MM_ERROR_CAMCORDER_GST_LINK;
+               goto pipeline_creation_error;
+       }
+
+       g_list_free(element_list);
+
+       /* connect handoff signal to get capture data */
+       MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_CAP_SINK].gst,
+               _MMCAMCORDER_HANDLER_STILLSHOT, "handoff",
+               G_CALLBACK(__mmcamcorder_handoff_callback_capture),
+               hcamcorder);
+
+       return MM_ERROR_NONE;
+
+pipeline_creation_error:
+       _MMCAMCORDER_ELEMENT_REMOVE(sc->element, _MMCAMCORDER_VIDEOSRC_CAP_CAPS);
+       _MMCAMCORDER_ELEMENT_REMOVE(sc->element, _MMCAMCORDER_VIDEOSRC_CAP_SINK);
+
+       if (element_list) {
+               g_list_free(element_list);
+               element_list = NULL;
+       }
+
+       return err;
+}
+
+
+int _mmcamcorder_initialize_capture_mode(MMHandleType handle)
+{
+       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
+
+       mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
+
+       if (hcamcorder->capture_mode == MM_CAMCORDER_CAPTURE_MODE_CAMERA_CONTROL)
+               return __mmcamcorder_capture_mode_init_camera_control(handle);
+       else if (hcamcorder->capture_mode == MM_CAMCORDER_CAPTURE_MODE_IMAGE_PAD)
+               return __mmcamcorder_capture_mode_init_image_pad(handle);
+
+       return MM_ERROR_NONE;
+}
+
+
+static int __mmcamcorder_extra_preview_mode_init_camera_control(mmf_camcorder_t *hcamcorder)
+{
+       int i = 0;
+       _MMCamcorderSubContext *sc = NULL;
+       GstCameraControl *control = NULL;
+       _MMCamcorderExtraPreviewFormat *e_fmt = NULL;
+
+       mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
+
+       sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
        mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
 
        mmf_return_val_if_fail(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
 
-       MMCAM_LOG_INFO("connect extra preview stream signal to _MMCAMCORDER_VIDEOSRC_SRC");
+       control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
+       if (!control) {
+               MMCAM_LOG_ERROR("no camera control");
+               return MM_ERROR_CAMCORDER_NOT_SUPPORTED;
+       }
+
+       MMCAM_LOG_INFO("connect extra preview stream signal and enable extra preview");
+
+       for (i = 0 ; i < MM_CAMCORDER_EXTRA_PREVIEW_STREAM_MAX ; i++) {
+               e_fmt = &hcamcorder->extra_preview.format[i];
+
+               if (e_fmt->need_to_set_format) {
+                       if (!gst_camera_control_set_extra_preview_stream_format(control,
+                               i, _mmcamcorder_get_pixel_format2(e_fmt->pixel_format),
+                               e_fmt->width, e_fmt->height, e_fmt->fps))
+                               MMCAM_LOG_WARNING("set format[%d,%dx%d,%d] failed for stream[%d]",
+                                       e_fmt->pixel_format, e_fmt->width, e_fmt->height, e_fmt->fps, i);
+
+                       e_fmt->need_to_set_format = FALSE;
+               }
+
+               if (e_fmt->need_to_set_bitrate) {
+                       if (!gst_camera_control_set_extra_preview_bitrate(control, i, e_fmt->bitrate))
+                               MMCAM_LOG_WARNING("set bitrate[%d] failed for stream[%d]", e_fmt->bitrate, i);
+
+                       e_fmt->need_to_set_bitrate = FALSE;
+               }
+
+               if (e_fmt->need_to_set_gop_interval) {
+                       if (!gst_camera_control_set_extra_preview_gop_interval(control, i, e_fmt->gop_interval))
+                               MMCAM_LOG_WARNING("set GOP interval[%d] failed for stream[%d]", e_fmt->gop_interval, i);
+
+                       e_fmt->need_to_set_gop_interval = FALSE;
+               }
+       }
 
        MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
                _MMCAMCORDER_HANDLER_EXTRA_PREVIEW, "extra-preview-stream-cb",
                G_CALLBACK(__mmcamcorder_extra_preview_stream_cb),
                hcamcorder);
 
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "extra-preview", TRUE);
+
+       MMCAM_LOG_INFO("done");
+
+       return MM_ERROR_NONE;
+}
+
+
+static int __mmcamcorder_extra_preview_mode_deinit_camera_control(mmf_camcorder_t *hcamcorder)
+{
+       _MMCamcorderSubContext *sc = NULL;
+       GstCameraControl *control = NULL;
+
+       mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
+
+       sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
+       mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
+
+       mmf_return_val_if_fail(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
+
        control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
        if (!control) {
                MMCAM_LOG_ERROR("no camera control");
                return MM_ERROR_CAMCORDER_NOT_SUPPORTED;
        }
 
-       for (i = 0 ; i < MM_CAMCORDER_EXTRA_PREVIEW_STREAM_NUM ; i++) {
-               e_fmt = &hcamcorder->extra_preview_format[i];
+       MMCAM_LOG_INFO("disable extra preview and disconnect extra preview stream signal");
 
-               if (!e_fmt->need_to_set)
-                       continue;
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "extra-preview", FALSE);
 
-               if (!gst_camera_control_set_extra_preview_stream_format(control,
-                       i, _mmcamcorder_get_pixel_format2(e_fmt->pixel_format),
-                       e_fmt->width, e_fmt->height, e_fmt->fps))
-                       MMCAM_LOG_WARNING("set format[%d,%dx%d,%d] failed for stream[%d]",
-                               e_fmt->pixel_format, e_fmt->width, e_fmt->height, e_fmt->fps, i);
+       _mmcamcorder_disconnect_signal((MMHandleType)hcamcorder, _MMCAMCORDER_HANDLER_EXTRA_PREVIEW);
+
+       MMCAM_LOG_INFO("done");
+
+       return MM_ERROR_NONE;
+}
+
+
+static int __mmcamcorder_extra_preview_mode_init_pipeline(MMHandleType handle, MMCamcorderExtraPreviewMode mode)
+{
+       int err = MM_ERROR_NONE;
+       int extra_preview_enable = 0;
+       int width = 0;
+       int height = 0;
+       int fps = 0;
+       const char *videosrc_name = NULL;
+       GstCaps *caps = NULL;
+       GList *element_list = NULL;
+
+       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
+       _MMCamcorderSubContext *sc = NULL;
+       type_element *videosrc_element = NULL;
+
+       mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
+
+       sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
+       mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
+
+       err = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
+               MMCAM_EXTRA_PREVIEW_ENABLE, &extra_preview_enable,
+               NULL);
+
+       width = hcamcorder->extra_preview.format[0].width;
+       height = hcamcorder->extra_preview.format[0].height;
+       fps = hcamcorder->extra_preview.format[0].fps;
+
+       if (!extra_preview_enable || width <= 0 || height <= 0 || fps <= 0) {
+               MMCAM_LOG_WARNING("extra preview disabled[enable:%d,res:%dx%d,fps:%d]",
+                       extra_preview_enable, width, height, fps);
+               return MM_ERROR_NONE;
+       }
+
+       if (mode == MM_CAMCORDER_EXTRA_PREVIEW_MODE_PIPELINE_ELEMENT) {
+               _mmcamcorder_conf_get_element_and_name(handle,
+                       hcamcorder->conf_main, CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT, "VideosrcElement",
+                       &videosrc_element, &videosrc_name);
+
+               _MMCAMCORDER_ELEMENT_MAKE(sc, sc->element, _MMCAMCORDER_VIDEOSRC_EXT_SRC, videosrc_name, "vsrc_e_src", element_list, err);
+
+               MMCAMCORDER_G_OBJECT_SET_POINTER(sc->element[_MMCAMCORDER_VIDEOSRC_EXT_SRC].gst, "hal-name", NULL);
+               MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_EXT_SRC].gst, "camera-id", hcamcorder->extra_preview.camera_id[0]);
+
+               _mmcamcorder_conf_set_value_element_property(sc->element[_MMCAMCORDER_VIDEOSRC_EXT_SRC].gst, videosrc_element);
+       }
+
+       _MMCAMCORDER_ELEMENT_MAKE(sc, sc->element, _MMCAMCORDER_VIDEOSRC_EXT_CAPS, "capsfilter", "vsrc_e_c", element_list, err);
+       _MMCAMCORDER_ELEMENT_MAKE(sc, sc->element, _MMCAMCORDER_VIDEOSRC_EXT_SINK, "fakesink", "vsrc_e_sink", element_list, err);
+
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_EXT_SINK].gst, "sync", TRUE);
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_EXT_SINK].gst, "async", FALSE);
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_EXT_SINK].gst, "enable-last-sample", FALSE);
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_EXT_SINK].gst, "signal-handoffs", TRUE);
+
+       caps = _mmcamcorder_get_video_caps((MMHandleType)hcamcorder,
+               hcamcorder->extra_preview.format[0].pixel_format,
+               width, height, fps, -1);
+       if (!caps) {
+               MMCAM_LOG_ERROR("caps for extra preview failed");
+               err = MM_ERROR_CAMCORDER_GST_LINK;
+               goto pipeline_creation_error;
+       }
+
+       MMCAMCORDER_G_OBJECT_SET_POINTER(sc->element[_MMCAMCORDER_VIDEOSRC_EXT_CAPS].gst, "caps", caps);
+       gst_caps_unref(caps);
+
+       /* add elements to main pipeline */
+       if (!_mmcamcorder_add_elements_to_bin(GST_BIN(sc->element[_MMCAMCORDER_MAIN_PIPE].gst), element_list)) {
+               MMCAM_LOG_ERROR("element_list add error.");
+               err = MM_ERROR_CAMCORDER_RESOURCE_CREATION;
+               goto pipeline_creation_error;
+       }
+
+       /* link elements */
+       if (mode == MM_CAMCORDER_EXTRA_PREVIEW_MODE_PIPELINE_SRCPAD) {
+               if (!gst_element_link_pads(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "video_%u",
+                       sc->element[_MMCAMCORDER_VIDEOSRC_EXT_CAPS].gst, "sink")) {
+                       MMCAM_LOG_ERROR("pad for extra preview link failed");
+                       err = MM_ERROR_CAMCORDER_GST_LINK;
+                       goto pipeline_creation_error;
+               }
+       }
+
+       if (!_mmcamcorder_link_elements(element_list)) {
+               MMCAM_LOG_ERROR("element link error.");
+               err = MM_ERROR_CAMCORDER_GST_LINK;
+               goto pipeline_creation_error;
+       }
+
+       g_list_free(element_list);
+
+       /* connect handoff signal to get capture data */
+       MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_EXT_SINK].gst,
+               _MMCAMCORDER_HANDLER_STILLSHOT, "handoff",
+               G_CALLBACK(__mmcamcorder_handoff_callback_extra_preview),
+               hcamcorder);
+
+       return MM_ERROR_NONE;
+
+pipeline_creation_error:
+       _MMCAMCORDER_ELEMENT_REMOVE(sc->element, _MMCAMCORDER_VIDEOSRC_EXT_CAPS);
+       _MMCAMCORDER_ELEMENT_REMOVE(sc->element, _MMCAMCORDER_VIDEOSRC_EXT_SINK);
 
-               if (!gst_camera_control_set_extra_preview_bitrate(control, i, e_fmt->bitrate))
-                       MMCAM_LOG_WARNING("set bitrate[%d] failed for stream[%d]", e_fmt->bitrate, i);
+       if (element_list) {
+               g_list_free(element_list);
+               element_list = NULL;
        }
 
+       return err;
+}
+
+
+static int __mmcamcorder_extra_preview_mode_deinit_pipeline(MMHandleType handle, MMCamcorderExtraPreviewMode mode)
+{
+       /* TODO */
        return MM_ERROR_NONE;
 }
 
 
-int _mmcamcorder_remove_stillshot_pipeline(MMHandleType handle)
+int _mmcamcorder_initialize_extra_preview_mode(MMHandleType handle)
+{
+       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
+
+       mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
+       mmf_return_val_if_fail(hcamcorder->extra_preview.is_supported, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
+
+       switch (hcamcorder->extra_preview.mode) {
+       case MM_CAMCORDER_EXTRA_PREVIEW_MODE_CAMERA_CONTROL:
+               return __mmcamcorder_extra_preview_mode_init_camera_control(handle);
+       case MM_CAMCORDER_EXTRA_PREVIEW_MODE_PIPELINE_SRCPAD:
+       case MM_CAMCORDER_EXTRA_PREVIEW_MODE_PIPELINE_ELEMENT:
+               return __mmcamcorder_extra_preview_mode_init_pipeline(handle, hcamcorder->extra_preview.mode);
+       default:
+               MMCAM_LOG_ERROR("unknown extra preview mode[%d]", hcamcorder->extra_preview.mode);
+               return MM_ERROR_CAMCORDER_INTERNAL;
+       }
+}
+
+
+int _mmcamcorder_deinitialize_extra_preview_mode(MMHandleType handle)
+{
+       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
+
+       mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
+       mmf_return_val_if_fail(hcamcorder->extra_preview.is_supported, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
+
+       switch (hcamcorder->extra_preview.mode) {
+       case MM_CAMCORDER_EXTRA_PREVIEW_MODE_CAMERA_CONTROL:
+               return __mmcamcorder_extra_preview_mode_deinit_camera_control(handle);
+       case MM_CAMCORDER_EXTRA_PREVIEW_MODE_PIPELINE_SRCPAD:
+       case MM_CAMCORDER_EXTRA_PREVIEW_MODE_PIPELINE_ELEMENT:
+               return __mmcamcorder_extra_preview_mode_deinit_pipeline(handle, hcamcorder->extra_preview.mode);
+       default:
+               MMCAM_LOG_ERROR("unknown extra preview mode[%d]", hcamcorder->extra_preview.mode);
+               return MM_ERROR_CAMCORDER_INTERNAL;
+       }
+}
+
+
+static int __mmcamcorder_capture_mode_deinit_encodebin(MMHandleType handle)
 {
        int ret = MM_ERROR_NONE;
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
@@ -336,10 +683,9 @@ _REUSE_CHECK_DONE:
 }
 
 
-int _mmcamcorder_image_cmd_capture(MMHandleType handle)
+static int __mmcamcorder_image_cmd_capture(MMHandleType handle)
 {
        int ret = MM_ERROR_NONE;
-       int UseCaptureMode = 0;
        int width = 0;
        int height = 0;
        int fps = 0;
@@ -371,11 +717,6 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle)
                return MM_ERROR_CAMCORDER_DEVICE_BUSY;
        }
 
-       _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main,
-               CONFIGURE_CATEGORY_MAIN_CAPTURE,
-               "UseCaptureMode",
-               &UseCaptureMode);
-
        /* get current state */
        mm_camcorder_get_state(handle, &current_state);
 
@@ -424,7 +765,7 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle)
 
        /* check state */
        if (current_state >= MM_CAMCORDER_STATE_RECORDING) {
-               if (sc->bencbin_capture) {
+               if (hcamcorder->capture_mode == MM_CAMCORDER_CAPTURE_MODE_ENCODEBIN) {
                        MMCAM_LOG_ERROR("could not capture in this target while recording");
                        ret = MM_ERROR_CAMCORDER_INVALID_STATE;
                        goto cmd_done;
@@ -458,7 +799,10 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle)
 
        sc->internal_encode = FALSE;
 
-       if (!sc->bencbin_capture) {
+       if (hcamcorder->capture_mode == MM_CAMCORDER_CAPTURE_MODE_IMAGE_PAD) {
+               MMCAM_LOG_INFO("emit signal[capture-image]");
+               g_signal_emit_by_name(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-image");
+       } else if (hcamcorder->capture_mode == MM_CAMCORDER_CAPTURE_MODE_CAMERA_CONTROL) {
                /* Check encoding method */
                if (info->capture_format == MM_PIXEL_FORMAT_ENCODED) {
                        if ((sc->SensorEncodedCapture && info->type == _MMCamcorder_SINGLE_SHOT) ||
@@ -495,20 +839,9 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle)
                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;
                int cap_jpeg_quality = 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) {
+               if (width != info->width || height != info->height) {
                        int rotation = 0;
 
                        MMCAM_LOG_INFO("Need to change resolution");
@@ -533,14 +866,6 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle)
                                goto cmd_done;
                        }
 
-                       if (UseCaptureMode) {
-                               set_width = MMFCAMCORDER_HIGHQUALITY_WIDTH;
-                               set_height = MMFCAMCORDER_HIGHQUALITY_HEIGHT;
-                       } else {
-                               set_width = info->width;
-                               set_height = info->height;
-                       }
-
                        mm_camcorder_get_attributes(handle, &err_name,
                                MMCAM_CAMERA_ROTATION, &rotation,
                                NULL);
@@ -550,7 +875,7 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle)
                        }
 
                        /* set new caps */
-                       ret = _mmcamcorder_set_videosrc_caps(handle, sc->fourcc, set_width, set_height, fps, rotation);
+                       ret = _mmcamcorder_set_videosrc_caps(handle, sc->fourcc, info->width, info->height, fps, rotation);
                        if (!ret) {
                                MMCAM_LOG_ERROR("_mmcamcorder_set_videosrc_caps failed");
                                ret = MM_ERROR_CAMCORDER_INTERNAL;
@@ -569,14 +894,13 @@ int _mmcamcorder_image_cmd_capture(MMHandleType handle)
                                goto cmd_done;
                        }
 
-                       MMCAM_LOG_INFO("Change to target resolution(%d, %d)", set_width, set_height);
+                       MMCAM_LOG_INFO("Change to target resolution(%d, %d)", info->width, info->height);
                } else {
                        MMCAM_LOG_INFO("No need to change resolution. Open toggle now.");
                        info->resolution_change = FALSE;
                }
 
-               /* add encodesinkbin */
-               ret = _mmcamcorder_create_stillshot_pipeline((MMHandleType)hcamcorder);
+               ret = __mmcamcorder_capture_mode_init_encodebin((MMHandleType)hcamcorder);
                if (ret != MM_ERROR_NONE) {
                        MMCAM_LOG_ERROR("failed to create encodesinkbin %x", ret);
                        goto cmd_done;
@@ -659,7 +983,7 @@ cmd_done:
 }
 
 
-int _mmcamcorder_image_cmd_preview_start(MMHandleType handle)
+static int __mmcamcorder_image_cmd_preview_start(MMHandleType handle)
 {
        int ret = MM_ERROR_NONE;
        int width = 0;
@@ -702,7 +1026,7 @@ int _mmcamcorder_image_cmd_preview_start(MMHandleType handle)
        current_state = _mmcamcorder_get_state(handle);
        MMCAM_LOG_INFO("current state [%d]", current_state);
 
-       if (!sc->bencbin_capture) {
+       if (hcamcorder->capture_mode == MM_CAMCORDER_CAPTURE_MODE_CAMERA_CONTROL) {
                MMCAM_LOG_INFO("Preview start");
 
                /* just set capture stop command if current state is CAPTURING */
@@ -765,7 +1089,7 @@ int _mmcamcorder_image_cmd_preview_start(MMHandleType handle)
        gst_element_get_state(pipeline, &state, NULL, -1);
 
        if (state == GST_STATE_PLAYING) {
-               if (!sc->bencbin_capture) {
+               if (hcamcorder->capture_mode == MM_CAMCORDER_CAPTURE_MODE_CAMERA_CONTROL) {
                        int try_count = 0;
 
                        if (hcamcorder->support_zsl_capture == FALSE) {
@@ -791,8 +1115,8 @@ int _mmcamcorder_image_cmd_preview_start(MMHandleType handle)
 
                        MMCAM_LOG_INFO("Wait Frame Done. count before[%d],after[%d], try_count[%d]",
                                current_framecount, sc->kpi.video_framecount, try_count);
-               } else {
-                       ret = _mmcamcorder_remove_stillshot_pipeline(handle);
+               } else if (hcamcorder->capture_mode == MM_CAMCORDER_CAPTURE_MODE_ENCODEBIN) {
+                       ret = __mmcamcorder_capture_mode_deinit_encodebin(handle);
                        if (ret != MM_ERROR_NONE)
                                goto cmd_error;
 
@@ -848,19 +1172,13 @@ int _mmcamcorder_image_cmd_preview_start(MMHandleType handle)
                        _mmcamcorder_sound_finalize(handle);
        } else {
                if (_mmcamcorder_is_encoded_preview_pixel_format(info->preview_format)) {
-                       ret = mm_camcorder_get_attributes(handle, NULL,
+                       mm_camcorder_get_attributes(handle, NULL,
                                MMCAM_ENCODED_PREVIEW_BITRATE, &bitrate,
+                               MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval,
                                NULL);
-                       if (ret == MM_ERROR_NONE)
-                               _mmcamcorder_set_encoded_preview_bitrate(handle, bitrate);
 
-                       if (info->preview_format == MM_PIXEL_FORMAT_ENCODED_H264) {
-                               ret = mm_camcorder_get_attributes(handle, NULL,
-                                       MMCAM_ENCODED_PREVIEW_GOP_INTERVAL, &gop_interval,
-                                       NULL);
-                               if (ret == MM_ERROR_NONE)
-                                       _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
-                       }
+                       _mmcamcorder_set_encoded_preview_bitrate(handle, bitrate);
+                       _mmcamcorder_set_encoded_preview_gop_interval(handle, gop_interval);
                }
 
                MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_QUE].gst, "empty-buffers", FALSE);
@@ -884,13 +1202,17 @@ int _mmcamcorder_image_cmd_preview_start(MMHandleType handle)
                        MMCAM_LOG_INFO("register vconf changed_cb and get sound status");
 
                        /* register changed_cb */
-                       vconf_notify_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, __sound_status_changed_cb, hcamcorder);
+                       vconf_notify_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, __mmcamcorder_sound_status_changed_cb, hcamcorder);
 
                        /* get sound status */
                        vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &(info->sound_status));
 
                        MMCAM_LOG_INFO("sound status %d", info->sound_status);
                }
+
+#ifdef _MMCAMCORDER_CAMERA_BOOST_SUPPORT
+               _mmcamcorder_start_boosting();
+#endif /* _MMCAMCORDER_CAMERA_BOOST_SUPPORT */
        }
 
 cmd_error:
@@ -898,7 +1220,7 @@ cmd_error:
 }
 
 
-int _mmcamcorder_image_cmd_preview_stop(MMHandleType handle)
+static int __mmcamcorder_image_cmd_preview_stop(MMHandleType handle)
 {
        int ret = MM_ERROR_NONE;
        int strobe_mode = MM_CAMCORDER_STROBE_MODE_OFF;
@@ -976,7 +1298,7 @@ int _mmcamcorder_image_cmd_preview_stop(MMHandleType handle)
        if (sc->info_image->sound_status != _SOUND_STATUS_INIT) {
                MMCAM_LOG_INFO("deregister sound status callback");
 
-               vconf_ignore_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, __sound_status_changed_cb);
+               vconf_ignore_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, __mmcamcorder_sound_status_changed_cb);
 
                sc->info_image->sound_status = _SOUND_STATUS_INIT;
        }
@@ -1001,16 +1323,21 @@ int _mmcamcorder_video_capture_command(MMHandleType handle, int command)
 
        switch (command) {
        case _MMCamcorder_CMD_CAPTURE:
-               ret = _mmcamcorder_image_cmd_capture(handle);
+               ret = __mmcamcorder_image_cmd_capture(handle);
                break;
        case _MMCamcorder_CMD_PREVIEW_START:
-               ret = _mmcamcorder_image_cmd_preview_start(handle);
+               ret = __mmcamcorder_image_cmd_preview_start(handle);
 
                /* I place this function last because it miscalculates a buffer that sents in GST_STATE_PAUSED */
                _mmcamcorder_video_current_framerate_init(handle);
                break;
        case _MMCamcorder_CMD_PREVIEW_STOP:
-               ret = _mmcamcorder_image_cmd_preview_stop(handle);
+               ret = __mmcamcorder_image_cmd_preview_stop(handle);
+
+#ifdef _MMCAMCORDER_CAMERA_BOOST_SUPPORT
+               _mmcamcorder_stop_boosting();
+#endif /*_MMCAMCORDER_CAMERA_BOOST_SUPPORT */
+
                break;
        case _MMCamcorder_CMD_RECORD:
        case _MMCamcorder_CMD_PAUSE:
@@ -1028,7 +1355,7 @@ int _mmcamcorder_video_capture_command(MMHandleType handle, int command)
 }
 
 
-void __mmcamcorder_init_stillshot_info(MMHandleType handle)
+static void __mmcamcorder_init_stillshot_info(MMHandleType handle)
 {
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
        _MMCamcorderSubContext *sc = NULL;
@@ -1057,7 +1384,7 @@ void __mmcamcorder_init_stillshot_info(MMHandleType handle)
 }
 
 
-int __mmcamcorder_capture_save_exifinfo(MMHandleType handle, MMCamcorderCaptureDataType *original, MMCamcorderCaptureDataType *thumbnail, int provide_exif)
+static int __mmcamcorder_capture_save_exifinfo(MMHandleType handle, MMCamcorderCaptureDataType *original, MMCamcorderCaptureDataType *thumbnail, int provide_exif)
 {
        int ret = MM_ERROR_NONE;
        unsigned char *data = NULL;
@@ -1120,7 +1447,7 @@ int __mmcamcorder_capture_save_exifinfo(MMHandleType handle, MMCamcorderCaptureD
 }
 
 
-void __mmcamcorder_get_capture_data_from_buffer(MMCamcorderCaptureDataType *capture_data, int pixtype, GstSample *sample)
+static void __mmcamcorder_get_capture_data_from_buffer(MMCamcorderCaptureDataType *capture_data, int pixtype, GstSample *sample)
 {
        GstCaps *caps = NULL;
        GstMapInfo mapinfo;
@@ -1142,11 +1469,17 @@ void __mmcamcorder_get_capture_data_from_buffer(MMCamcorderCaptureDataType *capt
 
        memset(&mapinfo, 0x0, sizeof(GstMapInfo));
 
-       gst_buffer_map(gst_sample_get_buffer(sample), &mapinfo, GST_MAP_READ);
+       if (!gst_buffer_map(gst_sample_get_buffer(sample), &mapinfo, GST_MAP_READ)) {
+               MMCAM_LOG_ERROR("map failed : buffer[%p]", gst_sample_get_buffer(sample));
+               goto GET_FAILED;
+       }
+
        capture_data->data = mapinfo.data;
        capture_data->format = pixtype;
-       gst_structure_get_int(structure, "width", &capture_data->width);
-       gst_structure_get_int(structure, "height", &capture_data->height);
+       gst_structure_get(structure,
+               "width", G_TYPE_INT, &capture_data->width,
+               "height", G_TYPE_INT, &capture_data->height,
+               NULL);
        capture_data->length = mapinfo.size;
        gst_buffer_unmap(gst_sample_get_buffer(sample), &mapinfo);
 
@@ -1164,7 +1497,7 @@ GET_FAILED:
 }
 
 
-int __mmcamcorder_set_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType *dest, MMCamcorderCaptureDataType *thumbnail, int provide_exif)
+static int __mmcamcorder_set_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType *dest, MMCamcorderCaptureDataType *thumbnail, int provide_exif)
 {
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
        _MMCamcorderSubContext *sc = NULL;
@@ -1185,7 +1518,7 @@ int __mmcamcorder_set_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType
 }
 
 
-void __mmcamcorder_release_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType *dest, int tag_enable, int provide_exif)
+static void __mmcamcorder_release_jpeg_data(MMHandleType handle, MMCamcorderCaptureDataType *dest, int tag_enable, int provide_exif)
 {
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
        _MMCamcorderSubContext *sc = NULL;
@@ -1333,7 +1666,7 @@ static void __mmcamcorder_image_capture_cb(GstElement *element, GstSample *sampl
        memset((void *)&scrnail, 0x0, sizeof(MMCamcorderCaptureDataType));
 
        /* Prepare main, thumbnail buffer */
-       pixtype_main = _mmcamcorder_get_pixel_format(gst_sample_get_caps(sample1));
+       pixtype_main = _mmcamcorder_get_pixel_format(gst_sample_get_caps(sample1), FALSE);
        if (pixtype_main == MM_PIXEL_FORMAT_INVALID) {
                MMCAM_LOG_ERROR("Unsupported pixel type");
                MMCAM_SEND_MESSAGE(hcamcorder, MM_MESSAGE_CAMCORDER_ERROR, MM_ERROR_CAMCORDER_INTERNAL);
@@ -1369,7 +1702,7 @@ static void __mmcamcorder_image_capture_cb(GstElement *element, GstSample *sampl
        if (sample3 && mapinfo3.data && mapinfo3.size != 0) {
                MMCAM_LOG_INFO("Screennail (sample3=%p,size=%zu)", sample3, mapinfo3.size);
 
-               pixtype_scrnl = _mmcamcorder_get_pixel_format(gst_sample_get_caps(sample3));
+               pixtype_scrnl = _mmcamcorder_get_pixel_format(gst_sample_get_caps(sample3), FALSE);
                __mmcamcorder_get_capture_data_from_buffer(&scrnail, pixtype_scrnl, sample3);
 
                /* Set screennail attribute for application */
@@ -1392,7 +1725,7 @@ static void __mmcamcorder_image_capture_cb(GstElement *element, GstSample *sampl
        /* Thumbnail image buffer */
        if (sample2 && mapinfo2.data && (mapinfo2.size != 0)) {
                MMCAM_LOG_INFO("Thumbnail (buffer2=%p)", gst_sample_get_buffer(sample2));
-               pixtype_thumb = _mmcamcorder_get_pixel_format(gst_sample_get_caps(sample2));
+               pixtype_thumb = _mmcamcorder_get_pixel_format(gst_sample_get_caps(sample2), FALSE);
                __mmcamcorder_get_capture_data_from_buffer(&thumb, pixtype_thumb, sample2);
        } else {
                MMCAM_LOG_INFO("Sample2 has wrong pointer. Not Error. (sample2 %p)", sample2);
@@ -1593,10 +1926,8 @@ static void __mmcamcorder_image_capture_cb(GstElement *element, GstSample *sampl
                        ret = __mmcamcorder_update_exif_info((MMHandleType)hcamcorder, dest.data, dest.length);
                }
 
-               if (ret != MM_ERROR_NONE) {
+               if (ret != MM_ERROR_NONE)
                        MMCAM_LOG_WARNING("Failed set_exif_basic_info [%x], but keep going...", ret);
-                       ret = MM_ERROR_NONE;
-               }
        }
 
        /* get attribute item for EXIF data */
@@ -1671,6 +2002,7 @@ _CAPTURE_CB_EXIF_DONE:
 
        /* Set capture count */
        count = ++(info->capture_send_count);
+       info->next_shot_time = GST_BUFFER_PTS(gst_sample_get_buffer(sample1)) + (GST_MSECOND * info->interval);
        send_captured_message = TRUE;
 
 err_release_exif:
@@ -1795,22 +2127,62 @@ static void __mmcamcorder_extra_preview_stream_cb(GstElement *element, int strea
 }
 
 
-gboolean __mmcamcorder_handoff_callback(GstElement *fakesink, GstBuffer *buffer, GstPad *pad, gpointer u_data)
+static gboolean __mmcamcorder_handoff_callback_extra_preview(GstElement *fakesink, GstBuffer *buffer, GstPad *pad, gpointer u_data)
 {
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
        _MMCamcorderSubContext *sc = NULL;
 
+       GstCaps *caps = NULL;
+       GstSample *sample = NULL;
+
        mmf_return_val_if_fail(hcamcorder, FALSE);
 
        sc = MMF_CAMCORDER_SUBCONTEXT(hcamcorder);
        mmf_return_val_if_fail(sc && sc->element, FALSE);
 
+       /* make sample with buffer and caps */
+       caps = gst_pad_get_allowed_caps(pad);
+       mmf_return_val_if_fail(caps, TRUE);
+
+       sample = gst_sample_new(buffer, caps, NULL, NULL);
+       gst_caps_unref(caps);
+       mmf_return_val_if_fail(sample, TRUE);
+
+       _mmcamcorder_invoke_video_stream_cb((MMHandleType)u_data, sample, TRUE, 0);
+
+       gst_sample_unref(sample);
+
+       return TRUE;
+}
+
+
+static gboolean __mmcamcorder_handoff_callback_capture(GstElement *fakesink, GstBuffer *buffer, GstPad *pad, gpointer u_data)
+{
+       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
+       _MMCamcorderSubContext *sc = NULL;
+       _MMCamcorderImageInfo *info = NULL;
+
+       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->element, FALSE);
+
        MMCAM_LOG_INFO("");
 
+       info = sc->info_image;
+
+       if (info->capture_send_count > 0 && info->next_shot_time > GST_BUFFER_PTS(buffer)) {
+               MMCAM_LOG_INFO("next capture time[%"GST_TIME_FORMAT"], but buffer[%"GST_TIME_FORMAT"]",
+                       GST_TIME_ARGS(info->next_shot_time), GST_TIME_ARGS(GST_BUFFER_PTS(buffer)));
+               return TRUE;
+       }
+
        /* FIXME. How could you get a thumbnail? */
        __mmcamcorder_image_capture_cb(fakesink, gst_sample_new(buffer, gst_pad_get_current_caps(pad), NULL, NULL), NULL, NULL, u_data);
 
-       if (sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst) {
+       if ((info->capture_send_count == info->count || info->capturing == FALSE) &&
+               sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst) {
                MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_SINK].gst, "signal-handoffs", FALSE);
                MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_ENCBIN].gst, "block", TRUE);
                sc->info_video->push_encoding_buffer = PUSH_ENCODING_BUFFER_STOP;
@@ -2151,7 +2523,7 @@ exit:
 }
 
 
-int __mmcamcorder_update_exif_info(MMHandleType handle, void* imagedata, int imgln)
+static int __mmcamcorder_update_exif_info(MMHandleType handle, void* imagedata, int imgln)
 {
        int ret = MM_ERROR_NONE;
        mmf_camcorder_t *hcamcorder = NULL;
@@ -2185,7 +2557,7 @@ int __mmcamcorder_update_exif_info(MMHandleType handle, void* imagedata, int img
        return ret;
 }
 
-int __mmcamcorder_set_exif_basic_info(MMHandleType handle, int image_width, int image_height)
+static int __mmcamcorder_set_exif_basic_info(MMHandleType handle, int image_width, int image_height)
 {
        int ret = MM_ERROR_NONE;
        int value;
@@ -2921,7 +3293,7 @@ exit:
 }
 
 
-static void __sound_status_changed_cb(keynode_t* node, void *data)
+static void __mmcamcorder_sound_status_changed_cb(keynode_t* node, void *data)
 {
        mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)data;
        _MMCamcorderImageInfo *info = NULL;
@@ -2940,28 +3312,63 @@ static void __sound_status_changed_cb(keynode_t* node, void *data)
 }
 
 
-int _mmcamcorder_set_extra_preview_stream_format(MMHandleType camcorder, int stream_id, int pixel_format, int width, int height, int fps)
+int _mmcamcorder_set_extra_preview_device_type(MMHandleType handle, int stream_id, int device_type)
 {
-       mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)camcorder;
+       int ret = MM_ERROR_NONE;
+       int camera_id = 0;
+       mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)handle;
+       MMCamcorderStateType current_state = MM_CAMCORDER_STATE_NONE;
+
+       mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
+       mmf_return_val_if_fail(hcamcorder->extra_preview.is_supported, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
+       mmf_return_val_if_fail(hcamcorder->extra_preview.mode == MM_CAMCORDER_EXTRA_PREVIEW_MODE_PIPELINE_ELEMENT,
+               MM_ERROR_CAMCORDER_NOT_SUPPORTED);
+       mmf_return_val_if_fail(stream_id >= 0 && stream_id < MM_CAMCORDER_EXTRA_PREVIEW_STREAM_MAX,
+               MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
+       mmf_return_val_if_fail(device_type > MM_VIDEO_DEVICE_NONE && device_type < MM_VIDEO_DEVICE_NUM
+               , MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
+
+       mm_camcorder_get_state(handle, &current_state);
+
+       MMCAM_LOG_INFO("stream_id[%d], device type[%d]", stream_id, device_type);
+
+       if (current_state > MM_CAMCORDER_STATE_NULL) {
+               MMCAM_LOG_ERROR("The device type can not be set after pipeline created");
+               return MM_ERROR_CAMCORDER_INVALID_STATE;
+       }
+
+       ret = _mmcamcorder_get_camera_id(device_type, &camera_id);
+       if (ret != MM_ERROR_NONE)
+               return ret;
+
+       hcamcorder->extra_preview.camera_id[stream_id] = camera_id;
+
+       return MM_ERROR_NONE;
+}
+
+
+int _mmcamcorder_set_extra_preview_stream_format(MMHandleType handle, int stream_id, int pixel_format, int width, int height, int fps)
+{
+       mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)handle;
        MMCamcorderStateType current_state = MM_CAMCORDER_STATE_NONE;
        GstCameraControl *control = NULL;
        _MMCamcorderSubContext *sc = NULL;
 
        mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
-       mmf_return_val_if_fail(hcamcorder->support_extra_preview, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
-       mmf_return_val_if_fail(stream_id >= 0 && stream_id < MM_CAMCORDER_EXTRA_PREVIEW_STREAM_NUM,
+       mmf_return_val_if_fail(hcamcorder->extra_preview.is_supported, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
+       mmf_return_val_if_fail(stream_id >= 0 && stream_id < MM_CAMCORDER_EXTRA_PREVIEW_STREAM_MAX,
                MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
        mmf_return_val_if_fail(pixel_format > MM_PIXEL_FORMAT_INVALID && pixel_format < MM_PIXEL_FORMAT_NUM,
                MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
        mmf_return_val_if_fail(width > 0 && height > 0 && fps >= 0, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
 
-       mm_camcorder_get_state(camcorder, &current_state);
+       mm_camcorder_get_state(handle, &current_state);
 
        MMCAM_LOG_INFO("state[%d] stream_id[%d],fmt[%d],res[%dx%d],fps[%d]",
                current_state, stream_id, pixel_format, width, height, fps);
 
        if (current_state >= MM_CAMCORDER_STATE_READY) {
-               sc = MMF_CAMCORDER_SUBCONTEXT(camcorder);
+               sc = MMF_CAMCORDER_SUBCONTEXT(handle);
                mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
 
                control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
@@ -2972,37 +3379,37 @@ int _mmcamcorder_set_extra_preview_stream_format(MMHandleType camcorder, int str
                }
        } else {
                MMCAM_LOG_INFO("It will be set when start preview");
-               hcamcorder->extra_preview_format[stream_id].need_to_set = TRUE;
+               hcamcorder->extra_preview.format[stream_id].need_to_set_format = TRUE;
        }
 
-       hcamcorder->extra_preview_format[stream_id].pixel_format = pixel_format;
-       hcamcorder->extra_preview_format[stream_id].width = width;
-       hcamcorder->extra_preview_format[stream_id].height = height;
-       hcamcorder->extra_preview_format[stream_id].fps = fps;
+       hcamcorder->extra_preview.format[stream_id].pixel_format = pixel_format;
+       hcamcorder->extra_preview.format[stream_id].width = width;
+       hcamcorder->extra_preview.format[stream_id].height = height;
+       hcamcorder->extra_preview.format[stream_id].fps = fps;
 
        return MM_ERROR_NONE;
 }
 
 
-int _mmcamcorder_get_extra_preview_stream_format(MMHandleType camcorder, int stream_id, int *pixel_format, int *width, int *height, int *fps)
+int _mmcamcorder_get_extra_preview_stream_format(MMHandleType handle, int stream_id, int *pixel_format, int *width, int *height, int *fps)
 {
        int _width = 0;
        int _height = 0;
        int _fps = 0;
        GstCameraControlImageFormat _img_fmt = GST_CAMERA_CONTROL_IMAGE_FORMAT_NV12;
        GstCameraControl *control = NULL;
-       mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)camcorder;
+       mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)handle;
        MMCamcorderStateType current_state = MM_CAMCORDER_STATE_NONE;
        _MMCamcorderSubContext *sc = NULL;
 
        mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
-       mmf_return_val_if_fail(hcamcorder->support_extra_preview, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
+       mmf_return_val_if_fail(hcamcorder->extra_preview.is_supported, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
        mmf_return_val_if_fail(pixel_format && width && height && fps, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
 
-       mm_camcorder_get_state(camcorder, &current_state);
+       mm_camcorder_get_state(handle, &current_state);
 
        if (current_state >= MM_CAMCORDER_STATE_READY) {
-               sc = MMF_CAMCORDER_SUBCONTEXT(camcorder);
+               sc = MMF_CAMCORDER_SUBCONTEXT(handle);
                mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
 
                control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
@@ -3017,10 +3424,10 @@ int _mmcamcorder_get_extra_preview_stream_format(MMHandleType camcorder, int str
                *height = _height;
                *fps = _fps;
        } else {
-               *pixel_format = hcamcorder->extra_preview_format[stream_id].pixel_format;
-               *width = hcamcorder->extra_preview_format[stream_id].width;
-               *height = hcamcorder->extra_preview_format[stream_id].height;
-               *fps = hcamcorder->extra_preview_format[stream_id].fps;
+               *pixel_format = hcamcorder->extra_preview.format[stream_id].pixel_format;
+               *width = hcamcorder->extra_preview.format[stream_id].width;
+               *height = hcamcorder->extra_preview.format[stream_id].height;
+               *fps = hcamcorder->extra_preview.format[stream_id].fps;
        }
 
        MMCAM_LOG_INFO("get result[fmt:%d(%d),res:%dx%d,fps:%d][state:%d]",
@@ -3030,25 +3437,25 @@ int _mmcamcorder_get_extra_preview_stream_format(MMHandleType camcorder, int str
 }
 
 
-int _mmcamcorder_set_extra_preview_bitrate(MMHandleType camcorder, int stream_id, int bitrate)
+int _mmcamcorder_set_extra_preview_bitrate(MMHandleType handle, int stream_id, int bitrate)
 {
-       mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)camcorder;
+       mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)handle;
        MMCamcorderStateType current_state = MM_CAMCORDER_STATE_NONE;
        GstCameraControl *control = NULL;
        _MMCamcorderSubContext *sc = NULL;
 
        mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
-       mmf_return_val_if_fail(hcamcorder->support_extra_preview, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
-       mmf_return_val_if_fail(stream_id >= 0 && stream_id < MM_CAMCORDER_EXTRA_PREVIEW_STREAM_NUM,
+       mmf_return_val_if_fail(hcamcorder->extra_preview.is_supported, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
+       mmf_return_val_if_fail(stream_id >= 0 && stream_id < MM_CAMCORDER_EXTRA_PREVIEW_STREAM_MAX,
                MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
        mmf_return_val_if_fail(bitrate > 0, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
 
-       mm_camcorder_get_state(camcorder, &current_state);
+       mm_camcorder_get_state(handle, &current_state);
 
-       MMCAM_LOG_INFO("state[%d] stream_id[%d], bitrate[%d]", current_state, stream_id, bitrate);
+       MMCAM_LOG_INFO("state[%d] stream[%d], bitrate[%d]", current_state, stream_id, bitrate);
 
        if (current_state >= MM_CAMCORDER_STATE_READY) {
-               sc = MMF_CAMCORDER_SUBCONTEXT(camcorder);
+               sc = MMF_CAMCORDER_SUBCONTEXT(handle);
                mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
 
                control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
@@ -3058,33 +3465,33 @@ int _mmcamcorder_set_extra_preview_bitrate(MMHandleType camcorder, int stream_id
                }
        } else {
                MMCAM_LOG_INFO("It will be set when start preview");
-               hcamcorder->extra_preview_format[stream_id].need_to_set = TRUE;
+               hcamcorder->extra_preview.format[stream_id].need_to_set_bitrate = TRUE;
        }
 
-       hcamcorder->extra_preview_format[stream_id].bitrate = bitrate;
+       hcamcorder->extra_preview.format[stream_id].bitrate = bitrate;
 
        return MM_ERROR_NONE;
 }
 
 
-int _mmcamcorder_get_extra_preview_bitrate(MMHandleType camcorder, int stream_id, int *bitrate)
+int _mmcamcorder_get_extra_preview_bitrate(MMHandleType handle, int stream_id, int *bitrate)
 {
        int _bitrate = 0;
        GstCameraControl *control = NULL;
-       mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)camcorder;
+       mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)handle;
        MMCamcorderStateType current_state = MM_CAMCORDER_STATE_NONE;
        _MMCamcorderSubContext *sc = NULL;
 
        mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
-       mmf_return_val_if_fail(hcamcorder->support_extra_preview, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
-       mmf_return_val_if_fail(stream_id >= 0 && stream_id < MM_CAMCORDER_EXTRA_PREVIEW_STREAM_NUM,
+       mmf_return_val_if_fail(hcamcorder->extra_preview.is_supported, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
+       mmf_return_val_if_fail(stream_id >= 0 && stream_id < MM_CAMCORDER_EXTRA_PREVIEW_STREAM_MAX,
                MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
        mmf_return_val_if_fail(bitrate, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
 
-       mm_camcorder_get_state(camcorder, &current_state);
+       mm_camcorder_get_state(handle, &current_state);
 
        if (current_state >= MM_CAMCORDER_STATE_READY) {
-               sc = MMF_CAMCORDER_SUBCONTEXT(camcorder);
+               sc = MMF_CAMCORDER_SUBCONTEXT(handle);
                mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
 
                control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
@@ -3095,10 +3502,85 @@ int _mmcamcorder_get_extra_preview_bitrate(MMHandleType camcorder, int stream_id
 
                *bitrate = _bitrate;
        } else {
-               *bitrate = hcamcorder->extra_preview_format[stream_id].bitrate;
+               *bitrate = hcamcorder->extra_preview.format[stream_id].bitrate;
+       }
+
+       MMCAM_LOG_INFO("get bitrate[%d] for stream[%d][state:%d]",
+               *bitrate, stream_id, current_state);
+
+       return MM_ERROR_NONE;
+}
+
+
+int _mmcamcorder_set_extra_preview_gop_interval(MMHandleType handle, int stream_id, int interval)
+{
+       mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)handle;
+       MMCamcorderStateType current_state = MM_CAMCORDER_STATE_NONE;
+       GstCameraControl *control = NULL;
+       _MMCamcorderSubContext *sc = NULL;
+
+       mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
+       mmf_return_val_if_fail(hcamcorder->extra_preview.is_supported, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
+       mmf_return_val_if_fail(stream_id >= 0 && stream_id < MM_CAMCORDER_EXTRA_PREVIEW_STREAM_MAX,
+               MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
+
+       mm_camcorder_get_state(handle, &current_state);
+
+       MMCAM_LOG_INFO("state[%d] stream[%d], interval[%d]", current_state, stream_id, interval);
+
+       if (current_state >= MM_CAMCORDER_STATE_READY) {
+               sc = MMF_CAMCORDER_SUBCONTEXT(handle);
+               mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
+
+               control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
+               if (!gst_camera_control_set_extra_preview_gop_interval(control, stream_id, interval)) {
+                       MMCAM_LOG_ERROR("set GOP interval[%d] for stream[%d] failed", interval, stream_id);
+                       return MM_ERROR_CAMCORDER_INTERNAL;
+               }
+       } else {
+               MMCAM_LOG_INFO("It will be set when start preview");
+               hcamcorder->extra_preview.format[stream_id].need_to_set_gop_interval = TRUE;
+       }
+
+       hcamcorder->extra_preview.format[stream_id].gop_interval = interval;
+
+       return MM_ERROR_NONE;
+}
+
+
+int _mmcamcorder_get_extra_preview_gop_interval(MMHandleType handle, int stream_id, int *interval)
+{
+       int _interval = 0;
+       GstCameraControl *control = NULL;
+       mmf_camcorder_t *hcamcorder = (mmf_camcorder_t *)handle;
+       MMCamcorderStateType current_state = MM_CAMCORDER_STATE_NONE;
+       _MMCamcorderSubContext *sc = NULL;
+
+       mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
+       mmf_return_val_if_fail(hcamcorder->extra_preview.is_supported, MM_ERROR_CAMCORDER_NOT_SUPPORTED);
+       mmf_return_val_if_fail(stream_id >= 0 && stream_id < MM_CAMCORDER_EXTRA_PREVIEW_STREAM_MAX,
+               MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
+       mmf_return_val_if_fail(interval, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
+
+       mm_camcorder_get_state(handle, &current_state);
+
+       if (current_state >= MM_CAMCORDER_STATE_READY) {
+               sc = MMF_CAMCORDER_SUBCONTEXT(handle);
+               mmf_return_val_if_fail(sc, MM_ERROR_CAMCORDER_INVALID_ARGUMENT);
+
+               control = GST_CAMERA_CONTROL(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst);
+               if (!gst_camera_control_get_extra_preview_gop_interval(control, stream_id, &_interval)) {
+                       MMCAM_LOG_ERROR("get GOP interval for stream[%d] failed", stream_id);
+                       return MM_ERROR_CAMCORDER_INTERNAL;
+               }
+
+               *interval = _interval;
+       } else {
+               *interval = hcamcorder->extra_preview.format[stream_id].gop_interval;
        }
 
-       MMCAM_LOG_INFO("get bitrate[%d] for stream[%d][state:%d]", *bitrate, stream_id, current_state);
+       MMCAM_LOG_INFO("get GOP interval[%d] for stream[%d][state:%d]",
+               *interval, stream_id, current_state);
 
        return MM_ERROR_NONE;
 }