Support extra preview stream 10/256810/8
authorJeongmo Yang <jm80.yang@samsung.com>
Tue, 13 Apr 2021 09:44:09 +0000 (18:44 +0900)
committerJeongmo Yang <jm80.yang@samsung.com>
Wed, 28 Apr 2021 09:32:18 +0000 (18:32 +0900)
- Additional minor changes
 : Add sub function to measure preview FPS
 : Fix memory leak in video stream callback

[Version] 0.10.232
[Issue Type] New feature

Change-Id: I135e0ba9018333ced35646973893c580e6d1e596
Signed-off-by: Jeongmo Yang <jm80.yang@samsung.com>
15 files changed:
packaging/libmm-camcorder.spec
src/include/mm_camcorder.h
src/include/mm_camcorder_attribute.h
src/include/mm_camcorder_gstcommon.h
src/include/mm_camcorder_internal.h [changed mode: 0755->0644]
src/include/mm_camcorder_stillshot.h
src/include/mm_camcorder_util.h
src/include/mm_camcorder_videorec.h
src/mm_camcorder_attribute.c
src/mm_camcorder_configure.c
src/mm_camcorder_gstcommon.c
src/mm_camcorder_internal.c
src/mm_camcorder_stillshot.c
src/mm_camcorder_util.c
src/mm_camcorder_videorec.c

index dedd179..5a33f3f 100755 (executable)
@@ -1,6 +1,6 @@
 Name:       libmm-camcorder
 Summary:    Camera and recorder library
-Version:    0.10.231
+Version:    0.10.232
 Release:    0
 Group:      Multimedia/Libraries
 License:    Apache-2.0
index 0bebbaf..f2026f8 100644 (file)
@@ -1339,6 +1339,11 @@ extern "C" {
  */
 #define MMCAM_AUDIOSRC_ELEMENT_NAME             "audiosrc-element-name"
 
+/**
+ * Extra preview enable
+ */
+#define MMCAM_EXTRA_PREVIEW_ENABLE              "extra-preview-enable"
+
 
 
 /*=======================================================================================
@@ -1844,6 +1849,7 @@ typedef struct {
        void *internal_buffer;          /**< Internal buffer pointer */
        int stride[BUFFER_MAX_PLANE_NUM];    /**< Stride of each plane */
        int elevation[BUFFER_MAX_PLANE_NUM]; /**< Elevation of each plane */
+       int extra_stream_id;            /**< ID of extra preview stream */
 } MMCamcorderVideoStreamDataType;
 
 
index caef1ba..9721e92 100644 (file)
@@ -194,6 +194,7 @@ typedef enum {
        MM_CAM_STROBE_BRIGHTNESS,
        MM_CAM_VIDEOSRC_ELEMENT_NAME,
        MM_CAM_AUDIOSRC_ELEMENT_NAME,
+       MM_CAM_EXTRA_PREVIEW_ENABLE,
        MM_CAM_ATTRIBUTE_NUM
 } MMCamcorderAttrsID;
 
@@ -396,6 +397,7 @@ bool _mmcamcorder_commit_encoded_preview_gop_interval(MMHandleType handle, int a
 bool _mmcamcorder_commit_sound_stream_info(MMHandleType handle, int attr_idx, const MMAttrsValue *value);
 bool _mmcamcorder_commit_tag(MMHandleType handle, int attr_idx, const MMAttrsValue *value);
 bool _mmcamcorder_commit_audio_replay_gain(MMHandleType handle, int attr_idx, const MMAttrsValue *value);
+bool _mmcamcorder_commit_extra_preview(MMHandleType handle, int attr_idx, const MMAttrsValue *value);
 
 
 /**
index 4cd71bf..f2d296b 100644 (file)
@@ -181,7 +181,7 @@ bool _mmcamcorder_set_encoded_preview_bitrate(MMHandleType handle, int bitrate);
 bool _mmcamcorder_set_encoded_preview_gop_interval(MMHandleType handle, int gop_interval);
 bool _mmcamcorder_set_sound_stream_info(GstElement *element, char *stream_type, int stream_index);
 void _mmcamcorder_set_encoder_bitrate(MMCamcorderEncoderType type, int codec, int bitrate, GstElement *element);
-gboolean _mmcamcorder_invoke_video_stream_cb(MMHandleType handle, GstBuffer *buffer, gboolean is_preview);
+gboolean _mmcamcorder_invoke_video_stream_cb(MMHandleType handle, GstSample *sample, gboolean is_preview, int stream_id);
 GstPadProbeReturn __mmcamcorder_muxed_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
 GstPadProbeReturn __mmcamcorder_eventprobe_monitor(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
 #ifdef __cplusplus
old mode 100755 (executable)
new mode 100644 (file)
index 429968d..cd957d8
@@ -777,6 +777,7 @@ typedef struct mmf_camcorder {
        int use_videoconvert;                                   /**< Whether use videoconvert element for display */
        int support_media_packet_preview_cb;                    /**< Whether support zero copy format for camera input */
        int support_user_buffer;                                /**< Whether support user allocated buffer for zero copy */
+       int support_extra_preview;                              /**< Whether support extra preview stream */
        int shutter_sound_policy;                               /**< shutter sound policy */
        int brightness_default;                                 /**< default value of brightness */
        int brightness_step_denominator;                        /**< denominator of brightness bias step */
@@ -833,6 +834,10 @@ typedef struct mmf_camcorder {
 #ifdef _MMCAMCORDER_CAMERA_CONF_MGR_SUPPORT
        camera_conf_device_info_s conf_device_info;
 #endif /*_MMCAMCORDER_CAMERA_CONF_MGR_SUPPORT */
+
+       /* Profiling */
+       int measure_preview_fps;                                /**< Flag for measuring fps of preview frames */
+
        int reserved[4];                                        /**< reserved */
 } mmf_camcorder_t;
 
index 6de5688..22c19c9 100644 (file)
@@ -122,6 +122,15 @@ int _mmcamcorder_remove_stillshot_pipeline(MMHandleType handle);
 int _mmcamcorder_connect_capture_signal(MMHandleType handle);
 
 /**
+ * This function connects extra preview stream signal.
+ *
+ * @param[in]  handle          Handle of camcorder context.
+ * @return     This function returns MM_ERROR_NONE on success, or the other values on error.
+ * @remarks
+ */
+int _mmcamcorder_connect_extra_preview_stream(MMHandleType handle);
+
+/**
  * This function destroy image pipeline.
  *
  * @param[in]  handle          Handle of camcorder context.
index fb8f09d..d93ff2c 100644 (file)
@@ -223,6 +223,7 @@ typedef enum {
        _MMCAMCORDER_HANDLER_VIDEOREC = (1 << 1),
        _MMCAMCORDER_HANDLER_STILLSHOT = (1 << 2),
        _MMCAMCORDER_HANDLER_AUDIOREC = (1 << 3),
+       _MMCAMCORDER_HANDLER_EXTRA_PREVIEW = (1 << 4),
 } _MMCamcorderHandlerCategory;
 
 /*=======================================================================================
@@ -272,7 +273,11 @@ typedef struct {
 #define G_DBUS_TIMEOUT                          3000
 #define FAT32_FILE_SYSTEM_MAX_SIZE              (4294967295UL)     /* 4 GigaByte - 1 byte */
 #define _MMCAMCORDER_HANDLER_CATEGORY_ALL \
-       (_MMCAMCORDER_HANDLER_PREVIEW | _MMCAMCORDER_HANDLER_VIDEOREC |_MMCAMCORDER_HANDLER_STILLSHOT | _MMCAMCORDER_HANDLER_AUDIOREC)
+       (_MMCAMCORDER_HANDLER_PREVIEW |\
+       _MMCAMCORDER_HANDLER_VIDEOREC |\
+       _MMCAMCORDER_HANDLER_STILLSHOT |\
+       _MMCAMCORDER_HANDLER_AUDIOREC |\
+       _MMCAMCORDER_HANDLER_EXTRA_PREVIEW)
 
 
 /*=======================================================================================
@@ -359,6 +364,9 @@ gboolean _mmcamcorder_is_encoded_preview_pixel_format(int pixel_format);
 void _mmcamcorder_set_log_level(int level);
 int _mmcamcorder_get_log_level(void);
 
+/* profiling */
+void _mmcamcorder_measure_fps(void *data);
+
 
 #ifdef __cplusplus
 }
index 87ae32c..fd5e8cf 100644 (file)
@@ -163,11 +163,11 @@ int _mmcamcorder_video_prepare_record(MMHandleType handle);
  * This function pushes video buffer to encoding pipeline
  *
  * @param[in]  handle          Handle of camcorder context.
- * @param[in]  buffer          Buffer to push.
+ * @param[in]  sample          Sample including buffer to push.
  * @return     This function returns TRUE on success, or FALSE on failure.
  * @remarks
  */
-gboolean _mmcamcorder_video_push_buffer(void *handle, GstBuffer *buffer);
+gboolean _mmcamcorder_video_push_buffer(void *handle, GstSample *sample);
 
 
 #ifdef __cplusplus
index 2cc4e4d..60b40ec 100644 (file)
@@ -1678,6 +1678,17 @@ _mmcamcorder_alloc_attribute(MMHandleType handle)
                        {0},
                        {0},
                        NULL,
+               },
+               {
+                       MM_CAM_EXTRA_PREVIEW_ENABLE,
+                       "extra-preview-enable",
+                       MM_ATTRS_TYPE_INT,
+                       MM_ATTRS_FLAG_RW,
+                       {(void*)FALSE},
+                       MM_ATTRS_VALID_TYPE_INT_RANGE,
+                       {.int_min = 0},
+                       {.int_max = 1},
+                       _mmcamcorder_commit_extra_preview,
                }
        };
 
@@ -4737,6 +4748,36 @@ bool _mmcamcorder_commit_audio_replay_gain(MMHandleType handle, int attr_idx, co
 }
 
 
+bool _mmcamcorder_commit_extra_preview(MMHandleType handle, int attr_idx, const MMAttrsValue *value)
+{
+       int current_state = MM_CAMCORDER_STATE_NONE;
+       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
+       _MMCamcorderSubContext *sc = NULL;
+
+       mmf_return_val_if_fail(hcamcorder && value, FALSE);
+
+       if (hcamcorder->type != MM_CAMCORDER_MODE_VIDEO_CAPTURE) {
+               MMCAM_LOG_ERROR("invalid mode %d", hcamcorder->type);
+               return FALSE;
+       }
+
+       MMCAM_LOG_INFO("Enable extra preview(%d)", value->value.i_val);
+
+       current_state = _mmcamcorder_get_state(handle);
+       if (current_state < MM_CAMCORDER_STATE_READY) {
+               MMCAM_LOG_INFO("will be set when preview is started");
+               return TRUE;
+       }
+
+       sc = MMF_CAMCORDER_SUBCONTEXT(handle);
+       mmf_return_val_if_fail(sc, FALSE);
+
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "extra-preview", value->value.i_val);
+
+       return TRUE;
+}
+
+
 bool _mmcamcorder_set_attribute_to_camsensor(MMHandleType handle)
 {
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
index 7580875..c93509a 100644 (file)
@@ -641,6 +641,8 @@ int _mmcamcorder_conf_init(MMHandleType handle, int type, camera_conf *configure
                { "DeviceCount",        CONFIGURE_VALUE_INT,            {.value_int = MM_VIDEO_DEVICE_NUM} },
                { "SupportMediaPacketPreviewCb",  CONFIGURE_VALUE_INT,  {.value_int = 0} },
                { "SupportUserBuffer",  CONFIGURE_VALUE_INT,            {.value_int = 0} },
+               { "MeasurePreviewFPS",  CONFIGURE_VALUE_INT,            {.value_int = 0} },
+               { "SupportExtraPreview", CONFIGURE_VALUE_INT,           {.value_int = 0} },
        };
 
        /* [AudioInput] matching table */
index 47243a3..85bb8c8 100755 (executable)
@@ -298,7 +298,7 @@ static gboolean __mmcamcorder_set_stream_data_tbm(MMCamcorderVideoStreamDataType
 }
 
 
-gboolean _mmcamcorder_invoke_video_stream_cb(MMHandleType handle, GstBuffer *buffer, gboolean is_preview)
+gboolean _mmcamcorder_invoke_video_stream_cb(MMHandleType handle, GstSample *sample, gboolean is_preview, int stream_id)
 {
        int i = 0;
        int num_bos = 0;
@@ -310,13 +310,15 @@ gboolean _mmcamcorder_invoke_video_stream_cb(MMHandleType handle, GstBuffer *buf
        tbm_surface_h t_surface = NULL;
        tbm_surface_info_s ts_info;
 
+       GstBuffer *buffer = NULL;
        GstMemory *memory = NULL;
        GstMapInfo map_info;
        GstCaps *caps = NULL;
-       GstPad *pad = NULL;
        GstStructure *structure = NULL;
 
        mmf_return_val_if_fail(hcamcorder, FALSE);
+
+       buffer = gst_sample_get_buffer(sample);
        mmf_return_val_if_fail(buffer, FALSE);
        mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
 
@@ -327,41 +329,17 @@ gboolean _mmcamcorder_invoke_video_stream_cb(MMHandleType handle, GstBuffer *buf
        memset(&map_info, 0x0, sizeof(GstMapInfo));
        memset(&stream, 0x0, sizeof(MMCamcorderVideoStreamDataType));
 
-       stream.format = sc->info_image->preview_format;
-       if (is_preview) {
-               /* preview buffer - get resolution from caps */
-               pad = gst_element_get_static_pad(sc->element[_MMCAMCORDER_VIDEOSRC_FILT].gst, "src");
-               mmf_return_val_if_fail(pad, FALSE);
-
-               caps = gst_pad_get_allowed_caps(pad);
-               if (!caps) {
-                       MMCAM_LOG_ERROR("failed to get caps from pad %p", pad);
-                       gst_object_unref(pad);
-                       return FALSE;
-               }
-
-               structure = gst_caps_get_structure(caps, 0);
-               if (!structure) {
-                       MMCAM_LOG_ERROR("failed to get structure from caps %p", caps);
-                       gst_caps_unref(caps);
-                       gst_object_unref(pad);
-                       return FALSE;
-               }
+       caps = gst_sample_get_caps(sample);
+       mmf_return_val_if_fail(caps, FALSE);
 
-               gst_structure_get_int(structure, "width", &stream.width);
-               gst_structure_get_int(structure, "height", &stream.height);
+       structure = gst_caps_get_structure(caps, 0);
+       mmf_return_val_if_fail(structure, FALSE);
 
-               gst_caps_unref(caps);
-               caps = NULL;
-               gst_object_unref(pad);
-               pad = NULL;
-       } else {
-               /* video recording buffer */
-               stream.width = sc->info_video->video_width;
-               stream.height = sc->info_video->video_height;
-       }
+       /* set format and resolution */
+       gst_structure_get_int(structure, "width", &stream.width);
+       gst_structure_get_int(structure, "height", &stream.height);
+       stream.format = _mmcamcorder_get_pixel_format(caps);
 
-       /* set size and timestamp */
        if (_mmcamcorder_is_encoded_preview_pixel_format(stream.format)) {
                memory = gst_buffer_get_all_memory(buffer);
                stream.internal_buffer = buffer;
@@ -406,10 +384,11 @@ gboolean _mmcamcorder_invoke_video_stream_cb(MMHandleType handle, GstBuffer *buf
                        goto _INVOKE_VIDEO_STREAM_CB_DONE;
        }
 
-       MMCAM_LOG_DEBUG("VideoStreamData : resolution[%dx%d], format[%d]",
-               stream.width, stream.height, stream.format);
+       MMCAM_LOG_DEBUG("VideoStreamData : format[%d], resolution[%dx%d], stream_id[%d]",
+               stream.format, stream.width, stream.height, stream_id);
 
        stream.timestamp = (unsigned int)(GST_BUFFER_PTS(buffer) / 1000000); /* nano sec -> milli sec */
+       stream.extra_stream_id = stream_id;
 
        /* invoke application callback */
        if (is_preview) {
@@ -469,6 +448,7 @@ int _mmcamcorder_create_preview_elements(MMHandleType handle)
        int sink_element_size = 0;
        int *fds = NULL;
        int fd_number = 0;
+       int extra_preview_enable = 0;
 
        GList *element_list = NULL;
 
@@ -519,6 +499,7 @@ int _mmcamcorder_create_preview_elements(MMHandleType handle)
                MMCAM_IMAGE_ENCODER_QUALITY, &capture_jpg_quality,
                MMCAM_DISPLAY_SOCKET_PATH, &socket_path, &socket_path_len,
                MMCAM_DISPLAY_SURFACE, &display_surface_type,
+               MMCAM_EXTRA_PREVIEW_ENABLE, &extra_preview_enable,
                NULL);
        if (err != MM_ERROR_NONE) {
                MMCAM_LOG_WARNING("Get attrs fail. (%s:%x)", err_name, err);
@@ -558,13 +539,6 @@ int _mmcamcorder_create_preview_elements(MMHandleType handle)
 
        _MMCAMCORDER_ELEMENT_MAKE(sc, sc->element, _MMCAMCORDER_VIDEOSRC_FILT, "capsfilter", "videosrc_filter", element_list, err);
 
-       /* set camera properties */
-       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);
-       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-jpg-quality", capture_jpg_quality);
-       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hdr-capture", sc->info_image->hdr_capture_mode);
-
        /**
         * This is for "tizencamerasrc" element only.
         * The camera HAL library will be loaded when "hal-name" property is set.
@@ -572,6 +546,14 @@ int _mmcamcorder_create_preview_elements(MMHandleType handle)
         */
        MMCAMCORDER_G_OBJECT_SET_POINTER(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hal-name", hcamcorder->network_hal_name);
 
+       /* set camera properties */
+       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);
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "capture-jpg-quality", capture_jpg_quality);
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "hdr-capture", sc->info_image->hdr_capture_mode);
+       MMCAMCORDER_G_OBJECT_SET(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, "extra-preview", extra_preview_enable);
+
        _MMCAMCORDER_ELEMENT_MAKE(sc, sc->element, _MMCAMCORDER_VIDEOSRC_QUE, "queue", "videosrc_queue", element_list, err);
 
        /* set camera flip */
@@ -2009,10 +1991,12 @@ static guint32 _mmcamcorder_convert_fourcc_string_to_value(const gchar* format_n
 
 static GstPadProbeReturn __mmcamcorder_video_dataprobe_preview(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
 {
+       gboolean ret = TRUE;
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
        _MMCamcorderSubContext *sc = NULL;
-       _MMCamcorderKPIMeasure *kpi = NULL;
        GstBuffer *buffer = GST_PAD_PROBE_INFO_BUFFER(info);
+       GstSample *sample = NULL;
+       GstCaps *caps = NULL;
 
        mmf_return_val_if_fail(buffer, GST_PAD_PROBE_DROP);
        mmf_return_val_if_fail(gst_buffer_n_memory(buffer), GST_PAD_PROBE_DROP);
@@ -2036,41 +2020,8 @@ static GstPadProbeReturn __mmcamcorder_video_dataprobe_preview(GstPad *pad, GstP
                return GST_PAD_PROBE_DROP;
        }
 
-       if (hcamcorder->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_LOG_INFO("START to measure FPS");
-                       */
-                       gettimeofday(&(kpi->init_video_time), NULL);
-               }
-
-               frame_count = ++(kpi->video_framecount);
-
-               gettimeofday(&current_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_LOG_INFO("current fps(%d), average(%d)", kpi->current_fps, kpi->average_fps);
-                       */
-               }
-       }
+       if (hcamcorder->measure_preview_fps && hcamcorder->state >= MM_CAMCORDER_STATE_PREPARE)
+               _mmcamcorder_measure_fps(&sc->kpi);
 
        /* The first H.264 frame should not be skipped for vstream cb. */
        if (hcamcorder->state < MM_CAMCORDER_STATE_PREPARE &&
@@ -2079,7 +2030,19 @@ static GstPadProbeReturn __mmcamcorder_video_dataprobe_preview(GstPad *pad, GstP
                return GST_PAD_PROBE_OK;
        }
 
-       if (_mmcamcorder_invoke_video_stream_cb((MMHandleType)hcamcorder, buffer, TRUE))
+       /* make sample with buffer and caps */
+       caps = gst_pad_get_allowed_caps(pad);
+       mmf_return_val_if_fail(caps, GST_PAD_PROBE_OK);
+
+       sample = gst_sample_new(buffer, caps, NULL, NULL);
+       gst_caps_unref(caps);
+       mmf_return_val_if_fail(sample, GST_PAD_PROBE_OK);
+
+       ret = _mmcamcorder_invoke_video_stream_cb((MMHandleType)hcamcorder, sample, TRUE, -1);
+
+       gst_sample_unref(sample);
+
+       if (ret)
                return GST_PAD_PROBE_OK;
        else
                return GST_PAD_PROBE_DROP;
@@ -2088,10 +2051,22 @@ static GstPadProbeReturn __mmcamcorder_video_dataprobe_preview(GstPad *pad, GstP
 
 static GstPadProbeReturn __mmcamcorder_video_dataprobe_record(GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
 {
-       if (_mmcamcorder_video_push_buffer(u_data, GST_PAD_PROBE_INFO_BUFFER(info)))
-               return GST_PAD_PROBE_OK;
+       gboolean ret = TRUE;
+       GstSample *sample = NULL;
+       GstCaps *caps = NULL;
+
+       caps = gst_pad_get_allowed_caps(pad);
+       mmf_return_val_if_fail(caps, GST_PAD_PROBE_OK);
+
+       sample = gst_sample_new(GST_PAD_PROBE_INFO_BUFFER(info), caps, NULL, NULL);
+       gst_caps_unref(caps);
+       mmf_return_val_if_fail(sample, GST_PAD_PROBE_OK);
+
+       ret = _mmcamcorder_video_push_buffer(u_data, sample);
+
+       gst_sample_unref(sample);
 
-       return GST_PAD_PROBE_DROP;
+       return (ret ? GST_PAD_PROBE_OK : GST_PAD_PROBE_DROP);
 }
 
 
index 7742c4d..3920cbc 100644 (file)
@@ -455,10 +455,20 @@ static gint __mmcamcorder_init_configure_video_capture(mmf_camcorder_t *hcamcord
                &hcamcorder->support_media_packet_preview_cb);
 
        _mmcamcorder_conf_get_value_int((MMHandleType)hcamcorder, hcamcorder->conf_main,
+               CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT,
+               "SupportExtraPreview",
+               &hcamcorder->support_extra_preview);
+
+       _mmcamcorder_conf_get_value_int((MMHandleType)hcamcorder, hcamcorder->conf_main,
                CONFIGURE_CATEGORY_MAIN_VIDEO_OUTPUT,
                "UseVideoconvert",
                &hcamcorder->use_videoconvert);
 
+       _mmcamcorder_conf_get_value_int((MMHandleType)hcamcorder, hcamcorder->conf_main,
+               CONFIGURE_CATEGORY_MAIN_VIDEO_INPUT,
+               "MeasurePreviewFPS",
+               &hcamcorder->measure_preview_fps);
+
        ret = mm_camcorder_get_attributes((MMHandleType)hcamcorder, NULL,
                MMCAM_CAMERA_WIDTH, &resolution_width,
                MMCAM_CAMERA_HEIGHT, &resolution_height,
@@ -474,9 +484,10 @@ static gint __mmcamcorder_init_configure_video_capture(mmf_camcorder_t *hcamcord
                return MM_ERROR_CAMCORDER_INTERNAL;
        }
 
-       MMCAM_LOG_INFO("ZeroCopy %d, UserBuffer %d, Videoconvert %d, MPPreviewCb %d",
+       MMCAM_LOG_INFO("ZC %d, UB %d, VC %d, MPPC %d, EP %d, MPFPS %d",
                hcamcorder->use_zero_copy_format, hcamcorder->support_user_buffer,
-               hcamcorder->use_videoconvert, hcamcorder->support_media_packet_preview_cb);
+               hcamcorder->use_videoconvert, hcamcorder->support_media_packet_preview_cb,
+               hcamcorder->support_extra_preview, hcamcorder->measure_preview_fps);
 
        MMCAM_LOG_INFO("res : %d X %d, Default FPS by resolution : %d",
                resolution_width, resolution_height, fps_info.int_array.def);
@@ -3071,17 +3082,21 @@ int _mmcamcorder_create_pipeline(MMHandleType handle, int type)
 
                break;
        case MM_CAMCORDER_MODE_VIDEO_CAPTURE:
+               /* fall through */
        default:
                ret = _mmcamcorder_create_preview_pipeline(handle);
                if (ret != MM_ERROR_NONE)
                        return ret;
 
-               /* connect capture signal */
                if (!sc->bencbin_capture) {
                        ret = _mmcamcorder_connect_capture_signal(handle);
                        if (ret != MM_ERROR_NONE)
                                return ret;
                }
+
+               if (hcamcorder->support_extra_preview &&
+                       _mmcamcorder_connect_extra_preview_stream(handle) != MM_ERROR_NONE)
+                       MMCAM_LOG_WARNING("connect extra preview stream signal failed");
                break;
        }
 
index a7853d1..6c48752 100644 (file)
@@ -65,6 +65,7 @@ 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, 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);
@@ -144,19 +145,39 @@ int _mmcamcorder_connect_capture_signal(MMHandleType handle)
        sc = MMF_CAMCORDER_SUBCONTEXT(handle);
        mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
 
-       /* check video source element */
-       if (sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst) {
-               MMCAM_LOG_WARNING("connect capture signal to _MMCAMCORDER_VIDEOSRC_SRC");
-               MMCAMCORDER_SIGNAL_CONNECT(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst,
-                       _MMCAMCORDER_HANDLER_STILLSHOT, "still-capture",
-                       G_CALLBACK(__mmcamcorder_image_capture_cb),
-                       hcamcorder);
+       mmf_return_val_if_fail(sc->element[_MMCAMCORDER_VIDEOSRC_SRC].gst, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
 
-               return MM_ERROR_NONE;
-       } else {
-               MMCAM_LOG_ERROR("videosrc element is not created yet");
-               return MM_ERROR_CAMCORDER_NOT_INITIALIZED;
-       }
+       MMCAM_LOG_INFO("connect capture signal to _MMCAMCORDER_VIDEOSRC_SRC");
+
+       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;
+}
+
+
+int _mmcamcorder_connect_extra_preview_stream(MMHandleType handle)
+{
+       mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
+       _MMCamcorderSubContext *sc = NULL;
+
+       mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
+
+       sc = MMF_CAMCORDER_SUBCONTEXT(handle);
+       mmf_return_val_if_fail(sc && sc->element, MM_ERROR_CAMCORDER_NOT_INITIALIZED);
+
+       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");
+
+       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);
+
+       return MM_ERROR_NONE;
 }
 
 
@@ -1728,6 +1749,20 @@ error:
 }
 
 
+static void __mmcamcorder_extra_preview_stream_cb(GstElement *element, int stream_id, GstSample *sample, gpointer u_data)
+{
+       if (!sample) {
+               MMCAM_LOG_ERROR("NULL sample for extra preview[id:%d]", stream_id);
+               return;
+       }
+
+       /* no need to check return value here */
+       _mmcamcorder_invoke_video_stream_cb((MMHandleType)u_data, sample, TRUE, stream_id);
+
+       gst_sample_unref(sample);
+}
+
+
 gboolean __mmcamcorder_handoff_callback(GstElement *fakesink, GstBuffer *buffer, GstPad *pad, gpointer u_data)
 {
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(u_data);
index e884259..24a1230 100644 (file)
@@ -2407,3 +2407,37 @@ int _mmcamcorder_get_log_level(void)
 {
        return mmcam_log_level;
 }
+
+void _mmcamcorder_measure_fps(void *data)
+{
+       int diff_sec;
+       int frame_count = 0;
+       struct timeval current_video_time;
+       _MMCamcorderKPIMeasure *kpi = (_MMCamcorderKPIMeasure *)data;
+
+       mmf_return_if_fail(kpi);
+
+       if (!timerisset(&kpi->init_video_time) && !timerisset(&kpi->last_video_time)) {
+               MMCAM_LOG_INFO("START to measure FPS");
+               gettimeofday(&(kpi->init_video_time), NULL);
+       }
+
+       frame_count = ++(kpi->video_framecount);
+
+       gettimeofday(&current_video_time, NULL);
+
+       diff_sec = current_video_time.tv_sec - kpi->last_video_time.tv_sec;
+       if (diff_sec == 0)
+               return;
+
+       kpi->current_fps = (frame_count - kpi->last_framecount) / diff_sec;
+
+       if ((current_video_time.tv_sec - kpi->init_video_time.tv_sec) != 0)
+               kpi->average_fps = kpi->video_framecount / (current_video_time.tv_sec - kpi->init_video_time.tv_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_LOG_INFO("current fps[%d], average[%d]", kpi->current_fps, kpi->average_fps);
+}
index b90fa91..0f68c16 100644 (file)
@@ -44,7 +44,7 @@
 |    LOCAL FUNCTION PROTOTYPES:                                                                                                                        |
 ---------------------------------------------------------------------------------------*/
 /* STATIC INTERNAL FUNCTION */
-static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
+static void __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data);
 static GstPadProbeReturn __mmcamcorder_audio_dataprobe_check(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
 static GstPadProbeReturn __mmcamcorder_video_dataprobe_encoded(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
 static GstPadProbeReturn __mmcamcorder_audioque_dataprobe(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
@@ -59,7 +59,7 @@ static gboolean __mmcamcorder_add_metadata_mp4(MMHandleType handle);
 /*---------------------------------------------------------------------------------------
 |    GLOBAL FUNCTION DEFINITIONS:                                                      |
 ---------------------------------------------------------------------------------------*/
-gboolean _mmcamcorder_video_push_buffer(void *handle, GstBuffer *buffer)
+gboolean _mmcamcorder_video_push_buffer(void *handle, GstSample *sample)
 {
        mmf_camcorder_t *hcamcorder = MMF_CAMCORDER(handle);
        _MMCamcorderSubContext *sc = NULL;
@@ -67,10 +67,13 @@ gboolean _mmcamcorder_video_push_buffer(void *handle, GstBuffer *buffer)
        _MMCamcorderVideoInfo *info_video = NULL;
        _MMCamcorderGstElement *element = NULL;
        GstClockTime current_ts = 0; /* nsec */
+       GstBuffer *buffer = NULL;
 
        mmf_return_val_if_fail(hcamcorder, FALSE);
        mmf_return_val_if_fail(MMF_CAMCORDER_SUBCONTEXT(hcamcorder), FALSE);
 
+       buffer = gst_sample_get_buffer(sample);
+
        mmf_return_val_if_fail(buffer, FALSE);
        mmf_return_val_if_fail(gst_buffer_n_memory(buffer), FALSE);
 
@@ -126,7 +129,7 @@ gboolean _mmcamcorder_video_push_buffer(void *handle, GstBuffer *buffer)
                                info_video->base_video_ts = current_ts;
                        }
                } else {
-                       if (_mmcamcorder_invoke_video_stream_cb(handle, buffer, FALSE) == FALSE) {
+                       if (_mmcamcorder_invoke_video_stream_cb(handle, sample, FALSE, -1) == FALSE) {
                                /* increase base video timestamp by frame duration,
                                   it will remove delay of dropped buffer when play recorded file. */
                                info_video->base_video_ts += current_ts - info_video->last_video_ts;
@@ -183,9 +186,14 @@ _VIDEO_PUSH_BUFFER_DONE:
 }
 
 
-static gboolean __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
+static void __mmcamcorder_video_stream_cb(GstElement *element, GstSample *sample, gpointer u_data)
 {
-       return _mmcamcorder_video_push_buffer(u_data, gst_sample_get_buffer(sample));
+       mmf_return_if_fail(sample);
+
+       /* no need to check return value here */
+       _mmcamcorder_video_push_buffer(u_data, sample);
+
+       gst_sample_unref(sample);
 }