From 1125f77a18d575f37b5959651b5020a707fa9d7d Mon Sep 17 00:00:00 2001 From: Jeongmo Yang Date: Fri, 28 Aug 2020 14:29:07 +0900 Subject: [PATCH] Support video scaling for video recording - This feature is just for the target which does not support dual stream recording. - Add "UseVideoscale" and "VideoscaleElement" like below in mmfw_camcorder.ini file to enable this feature. [Record] ... UseVideoscale = 1 VideoscaleElement = videoscale | 1,0 | method,1 - It will be disabled when video resolution is bigger than preview resolution although "UseVideoscale" is 1. [Version] 0.10.211 [Issue Type] New feature Change-Id: Ia7ea1740da8dbf934c9e574261e26fa460f33e61 Signed-off-by: Jeongmo Yang --- packaging/libmm-camcorder.spec | 2 +- src/include/mm_camcorder_internal.h | 2 + src/include/mm_camcorder_videorec.h | 1 + src/mm_camcorder_configure.c | 4 +- src/mm_camcorder_gstcommon.c | 106 +++++++++++++++++++++------- src/mm_camcorder_internal.c | 9 ++- src/mm_camcorder_videorec.c | 39 ++++++++-- 7 files changed, 128 insertions(+), 35 deletions(-) diff --git a/packaging/libmm-camcorder.spec b/packaging/libmm-camcorder.spec index 96bfce7..aa29705 100644 --- 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.210 +Version: 0.10.211 Release: 0 Group: Multimedia/Libraries License: Apache-2.0 diff --git a/src/include/mm_camcorder_internal.h b/src/include/mm_camcorder_internal.h index 7edc812..8ac7edb 100644 --- a/src/include/mm_camcorder_internal.h +++ b/src/include/mm_camcorder_internal.h @@ -587,6 +587,8 @@ typedef enum { _MMCAMCORDER_ENCSINK_AENC, _MMCAMCORDER_ENCSINK_AENC_QUE, _MMCAMCORDER_ENCSINK_VQUE, + _MMCAMCORDER_ENCSINK_VSCALE, + _MMCAMCORDER_ENCSINK_VSCALE_FILT, _MMCAMCORDER_ENCSINK_VCONV, _MMCAMCORDER_ENCSINK_VENC, _MMCAMCORDER_ENCSINK_VENC_QUE, diff --git a/src/include/mm_camcorder_videorec.h b/src/include/mm_camcorder_videorec.h index c148c64..b6d845e 100644 --- a/src/include/mm_camcorder_videorec.h +++ b/src/include/mm_camcorder_videorec.h @@ -79,6 +79,7 @@ typedef struct { gboolean support_dual_stream; /**< support dual stream flag */ gboolean record_dual_stream; /**< record with dual stream flag */ gboolean restart_preview; /**< flag for whether restart preview or not when start recording */ + gboolean use_videoscale; /**< use video scale element in encoding pipeline */ GMutex size_check_lock; /**< mutex for checking recording size */ } _MMCamcorderVideoInfo; diff --git a/src/mm_camcorder_configure.c b/src/mm_camcorder_configure.c index 98c64e1..2f77582 100644 --- a/src/mm_camcorder_configure.c +++ b/src/mm_camcorder_configure.c @@ -693,7 +693,9 @@ int _mmcamcorder_conf_init(MMHandleType handle, int type, camera_conf *configure { "UseNoiseSuppressor", CONFIGURE_VALUE_INT, {.value_int = 0} }, { "DropVideoFrame", CONFIGURE_VALUE_INT, {.value_int = 0} }, { "PassFirstVideoFrame", CONFIGURE_VALUE_INT, {.value_int = 0} }, - { "SupportDualStream", CONFIGURE_VALUE_INT, {.value_int = FALSE} }, + { "SupportDualStream", CONFIGURE_VALUE_INT, {.value_int = 0} }, + { "UseVideoscale", CONFIGURE_VALUE_INT, {.value_int = 0} }, + { "VideoscaleElement", CONFIGURE_VALUE_ELEMENT, {&_videoscale_element_default} } }; /* [VideoEncoder] matching table */ diff --git a/src/mm_camcorder_gstcommon.c b/src/mm_camcorder_gstcommon.c index 1c75930..d508c3f 100644 --- a/src/mm_camcorder_gstcommon.c +++ b/src/mm_camcorder_gstcommon.c @@ -1077,6 +1077,7 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle, MMCamcorderEncodebin const char *gst_element_ienc_name = NULL; const char *gst_element_mux_name = NULL; const char *gst_element_rsink_name = NULL; + const char *gst_element_vscale_name = NULL; const char *str_profile = NULL; const char *str_aac = NULL; const char *str_aar = NULL; @@ -1085,6 +1086,7 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle, MMCamcorderEncodebin const char *videoconvert_name = NULL; GstCaps *audio_caps = NULL; GstCaps *video_caps = NULL; + GstCaps *videoscale_caps = NULL; GstPad *pad = NULL; GList *element_list = NULL; @@ -1095,6 +1097,7 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle, MMCamcorderEncodebin type_element *ImageencElement = NULL; type_element *MuxElement = NULL; type_element *RecordsinkElement = NULL; + type_element *VideoscaleElement = NULL; mmf_return_val_if_fail(hcamcorder, MM_ERROR_CAMCORDER_NOT_INITIALIZED); @@ -1118,18 +1121,13 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle, MMCamcorderEncodebin /* Create child element */ if (profile != MM_CAMCORDER_ENCBIN_PROFILE_AUDIO) { GstCaps *caps_from_pad = NULL; + char *caps_str = NULL; /* create appsrc and capsfilter */ _MMCAMCORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCSINK_SRC, "appsrc", "encodesink_src", element_list, err); _MMCAMCORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCSINK_FILT, "capsfilter", "encodesink_filter", element_list, err); - /* release element_list, they will be placed out of encodesink bin */ - if (element_list) { - g_list_free(element_list); - element_list = NULL; - } - /* set appsrc as live source */ MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "is-live", TRUE); MMCAMCORDER_G_OBJECT_SET(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "format", 3); /* GST_FORMAT_TIME */ @@ -1164,28 +1162,84 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle, MMCamcorderEncodebin MMCAMCORDER_G_OBJECT_GET(sc->element[_MMCAMCORDER_VIDEOSRC_FILT].gst, "caps", &video_caps); } - if (video_caps) { - char *caps_str = NULL; + if (!video_caps) { + _mmcam_dbg_err("create recording pipeline caps failed"); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } - if (profile == MM_CAMCORDER_ENCBIN_PROFILE_VIDEO) { + if (profile == MM_CAMCORDER_ENCBIN_PROFILE_VIDEO) { + if (sc->info_video->use_videoscale) { + gst_caps_set_simple(video_caps, + "width", G_TYPE_INT, sc->info_video->preview_width, + "height", G_TYPE_INT, sc->info_video->preview_height, + NULL); + videoscale_caps = gst_caps_copy(video_caps); + } else { gst_caps_set_simple(video_caps, "width", G_TYPE_INT, sc->info_video->video_width, "height", G_TYPE_INT, sc->info_video->video_height, NULL); } + } + + caps_str = gst_caps_to_string(video_caps); + + _mmcam_dbg_log("encodebin caps [%s]", caps_str); + + g_free(caps_str); + caps_str = NULL; + + MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "caps", video_caps); + + gst_caps_unref(video_caps); + video_caps = NULL; + + /* video scale */ + if (profile == MM_CAMCORDER_ENCBIN_PROFILE_VIDEO && + sc->info_video->use_videoscale) { + if (!videoscale_caps) { + _mmcam_dbg_err("no videoscale caps"); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + gst_caps_set_simple(videoscale_caps, + "width", G_TYPE_INT, sc->info_video->video_width, + "height", G_TYPE_INT, sc->info_video->video_height, + NULL); + + _mmcamcorder_conf_get_element(handle, hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_RECORD, + "VideoscaleElement", + &VideoscaleElement); + + if (!_mmcamcorder_conf_get_value_element_name(VideoscaleElement, &gst_element_vscale_name)) { + _mmcam_dbg_err("failed to get videoscale element name"); + err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; + goto pipeline_creation_error; + } + + caps_str = gst_caps_to_string(videoscale_caps); + + _mmcam_dbg_log("encodebin videocale [%s][%s]", gst_element_vscale_name, caps_str); - caps_str = gst_caps_to_string(video_caps); - _mmcam_dbg_log("encodebin caps [%s]", caps_str); g_free(caps_str); caps_str = NULL; - MMCAMCORDER_G_OBJECT_SET_POINTER(sc->encode_element[_MMCAMCORDER_ENCSINK_FILT].gst, "caps", video_caps); - gst_caps_unref(video_caps); - video_caps = NULL; - } else { - _mmcam_dbg_err("create recording pipeline caps failed"); - err = MM_ERROR_CAMCORDER_RESOURCE_CREATION; - goto pipeline_creation_error; + _MMCAMCORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCSINK_VSCALE, gst_element_vscale_name, "encodesink_vscale", element_list, err); + _MMCAMCORDER_ELEMENT_MAKE(sc, sc->encode_element, _MMCAMCORDER_ENCSINK_VSCALE_FILT, "capsfilter", "encodesink_vscale_filter", element_list, err); + + MMCAMCORDER_G_OBJECT_SET_POINTER((sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst), "caps", videoscale_caps); + + gst_caps_unref(videoscale_caps); + videoscale_caps = NULL; + } + + /* release element_list, they will be placed out of encodesink bin */ + if (element_list) { + g_list_free(element_list); + element_list = NULL; } /* connect signal for ready to push buffer */ @@ -1515,10 +1569,8 @@ int _mmcamcorder_create_encodesink_bin(MMHandleType handle, MMCamcorderEncodebin goto pipeline_creation_error; } - if (element_list) { + if (element_list) g_list_free(element_list); - element_list = NULL; - } _mmcam_dbg_log("done"); @@ -1530,6 +1582,8 @@ pipeline_creation_error: _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_ENCBIN); _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_SRC); _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_FILT); + _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_VSCALE); + _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_VSCALE_FILT); _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_VENC); _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_AENC); _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_IENC); @@ -1537,10 +1591,14 @@ pipeline_creation_error: _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_SINK); _MMCAMCORDER_ELEMENT_REMOVE(sc->encode_element, _MMCAMCORDER_ENCSINK_BIN); - if (element_list) { + if (element_list) g_list_free(element_list); - element_list = NULL; - } + + if (video_caps) + gst_caps_unref(video_caps); + + if (videoscale_caps) + gst_caps_unref(videoscale_caps); return err; } diff --git a/src/mm_camcorder_internal.c b/src/mm_camcorder_internal.c index fd26f73..5bb47d4 100644 --- a/src/mm_camcorder_internal.c +++ b/src/mm_camcorder_internal.c @@ -898,13 +898,18 @@ int _mmcamcorder_realize(MMHandleType handle) _mmcam_dbg_warn("UseEncodebin [%d]", hcamcorder->sub_context->bencbin_capture); if (hcamcorder->type != MM_CAMCORDER_MODE_AUDIO) { - /* get dual stream support info */ + /* get video recording info */ _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main, CONFIGURE_CATEGORY_MAIN_RECORD, "SupportDualStream", &(hcamcorder->sub_context->info_video->support_dual_stream)); - _mmcam_dbg_warn("SupportDualStream [%d]", hcamcorder->sub_context->info_video->support_dual_stream); + + _mmcamcorder_conf_get_value_int(handle, hcamcorder->conf_main, + CONFIGURE_CATEGORY_MAIN_RECORD, + "UseVideoscale", + &(hcamcorder->sub_context->info_video->use_videoscale)); + _mmcam_dbg_warn("UseVideoscale [%d]", hcamcorder->sub_context->info_video->use_videoscale); } switch (display_surface_type) { diff --git a/src/mm_camcorder_videorec.c b/src/mm_camcorder_videorec.c index 79aeab4..b7be551 100644 --- a/src/mm_camcorder_videorec.c +++ b/src/mm_camcorder_videorec.c @@ -252,12 +252,22 @@ int _mmcamcorder_create_recorder_pipeline(MMHandleType handle) sc->encode_element[_MMCAMCORDER_AUDIOSRC_BIN].gst); } - /* 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_BIN].gst, - NULL); + /* add elements and encodesink bin to encode main pipeline */ + if (sc->info_video->use_videoscale) { + 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_VSCALE].gst, + sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst, + sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, + NULL); + } else { + 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_BIN].gst, + NULL); + } /* Link each element : appsrc - capsfilter - encodesink bin */ srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_SRC].gst, "src"); @@ -265,6 +275,16 @@ int _mmcamcorder_create_recorder_pipeline(MMHandleType handle) _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"); + if (sc->info_video->use_videoscale) { + sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].gst, "sink"); + _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error); + + srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE].gst, "src"); + sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst, "sink"); + _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error); + + srcpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_VSCALE_FILT].gst, "src"); + } sinkpad = gst_element_get_static_pad(sc->encode_element[_MMCAMCORDER_ENCSINK_BIN].gst, "video_sink0"); _MM_GST_PAD_LINK_UNREF(srcpad, sinkpad, err, pipeline_creation_error); @@ -721,9 +741,14 @@ int _mmcamcorder_video_command(MMHandleType handle, int command) /* No need to restart preview */ info->restart_preview = FALSE; + } else if (info->use_videoscale && + info->preview_width >= info->video_width && + info->preview_height >= info->video_height) { + info->restart_preview = FALSE; } else { - /* always need to restart preview */ info->restart_preview = TRUE; + /* reset use_videoscale */ + info->use_videoscale = FALSE; } /* set recording hint */ -- 2.34.1