From 9a0ce7320cf407bcfa3e6b8102c62fbcafb84a10 Mon Sep 17 00:00:00 2001 From: Jeongmo Yang Date: Tue, 13 Apr 2021 18:44:09 +0900 Subject: [PATCH] Support extra preview stream - 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 --- packaging/libmm-camcorder.spec | 2 +- src/include/mm_camcorder.h | 6 ++ src/include/mm_camcorder_attribute.h | 2 + src/include/mm_camcorder_gstcommon.h | 2 +- src/include/mm_camcorder_internal.h | 5 + src/include/mm_camcorder_stillshot.h | 9 ++ src/include/mm_camcorder_util.h | 10 +- src/include/mm_camcorder_videorec.h | 4 +- src/mm_camcorder_attribute.c | 41 ++++++++ src/mm_camcorder_configure.c | 2 + src/mm_camcorder_gstcommon.c | 141 +++++++++++---------------- src/mm_camcorder_internal.c | 21 +++- src/mm_camcorder_stillshot.c | 59 ++++++++--- src/mm_camcorder_util.c | 34 +++++++ src/mm_camcorder_videorec.c | 18 +++- 15 files changed, 248 insertions(+), 108 deletions(-) mode change 100755 => 100644 src/include/mm_camcorder_internal.h diff --git a/packaging/libmm-camcorder.spec b/packaging/libmm-camcorder.spec index dedd179..5a33f3f 100755 --- a/packaging/libmm-camcorder.spec +++ b/packaging/libmm-camcorder.spec @@ -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 diff --git a/src/include/mm_camcorder.h b/src/include/mm_camcorder.h index 0bebbaf..f2026f8 100644 --- a/src/include/mm_camcorder.h +++ b/src/include/mm_camcorder.h @@ -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; diff --git a/src/include/mm_camcorder_attribute.h b/src/include/mm_camcorder_attribute.h index caef1ba..9721e92 100644 --- a/src/include/mm_camcorder_attribute.h +++ b/src/include/mm_camcorder_attribute.h @@ -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); /** diff --git a/src/include/mm_camcorder_gstcommon.h b/src/include/mm_camcorder_gstcommon.h index 4cd71bf..f2d296b 100644 --- a/src/include/mm_camcorder_gstcommon.h +++ b/src/include/mm_camcorder_gstcommon.h @@ -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 diff --git a/src/include/mm_camcorder_internal.h b/src/include/mm_camcorder_internal.h old mode 100755 new mode 100644 index 429968d..cd957d8 --- a/src/include/mm_camcorder_internal.h +++ b/src/include/mm_camcorder_internal.h @@ -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; diff --git a/src/include/mm_camcorder_stillshot.h b/src/include/mm_camcorder_stillshot.h index 6de5688..22c19c9 100644 --- a/src/include/mm_camcorder_stillshot.h +++ b/src/include/mm_camcorder_stillshot.h @@ -121,6 +121,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. * diff --git a/src/include/mm_camcorder_util.h b/src/include/mm_camcorder_util.h index fb8f09d..d93ff2c 100644 --- a/src/include/mm_camcorder_util.h +++ b/src/include/mm_camcorder_util.h @@ -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 } diff --git a/src/include/mm_camcorder_videorec.h b/src/include/mm_camcorder_videorec.h index 87ae32c..fd5e8cf 100644 --- a/src/include/mm_camcorder_videorec.h +++ b/src/include/mm_camcorder_videorec.h @@ -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 diff --git a/src/mm_camcorder_attribute.c b/src/mm_camcorder_attribute.c index 2cc4e4d..60b40ec 100644 --- a/src/mm_camcorder_attribute.c +++ b/src/mm_camcorder_attribute.c @@ -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); diff --git a/src/mm_camcorder_configure.c b/src/mm_camcorder_configure.c index 7580875..c93509a 100644 --- a/src/mm_camcorder_configure.c +++ b/src/mm_camcorder_configure.c @@ -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 */ diff --git a/src/mm_camcorder_gstcommon.c b/src/mm_camcorder_gstcommon.c index 47243a3..85bb8c8 100755 --- a/src/mm_camcorder_gstcommon.c +++ b/src/mm_camcorder_gstcommon.c @@ -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(¤t_video_time, NULL); - diff_sec = current_video_time.tv_sec - kpi->last_video_time.tv_sec; - if (diff_sec != 0) { - kpi->current_fps = (frame_count - kpi->last_framecount) / diff_sec; - if ((current_video_time.tv_sec - kpi->init_video_time.tv_sec) != 0) { - int framecount = kpi->video_framecount; - int elased_sec = current_video_time.tv_sec - kpi->init_video_time.tv_sec; - kpi->average_fps = framecount / elased_sec; - } - - kpi->last_framecount = frame_count; - kpi->last_video_time.tv_sec = current_video_time.tv_sec; - kpi->last_video_time.tv_usec = current_video_time.tv_usec; - /* - MMCAM_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); } diff --git a/src/mm_camcorder_internal.c b/src/mm_camcorder_internal.c index 7742c4d..3920cbc 100644 --- a/src/mm_camcorder_internal.c +++ b/src/mm_camcorder_internal.c @@ -454,11 +454,21 @@ static gint __mmcamcorder_init_configure_video_capture(mmf_camcorder_t *hcamcord "SupportMediaPacketPreviewCb", &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; } diff --git a/src/mm_camcorder_stillshot.c b/src/mm_camcorder_stillshot.c index a7853d1..6c48752 100644 --- a/src/mm_camcorder_stillshot.c +++ b/src/mm_camcorder_stillshot.c @@ -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); diff --git a/src/mm_camcorder_util.c b/src/mm_camcorder_util.c index e884259..24a1230 100644 --- a/src/mm_camcorder_util.c +++ b/src/mm_camcorder_util.c @@ -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(¤t_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); +} diff --git a/src/mm_camcorder_videorec.c b/src/mm_camcorder_videorec.c index b90fa91..0f68c16 100644 --- a/src/mm_camcorder_videorec.c +++ b/src/mm_camcorder_videorec.c @@ -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); } -- 2.34.1