Support video scaling for video recording 84/242584/2 accepted/tizen/unified/20200902.011917 submit/tizen/20200901.061448
authorJeongmo Yang <jm80.yang@samsung.com>
Fri, 28 Aug 2020 05:29:07 +0000 (14:29 +0900)
committerJeongmo Yang <jm80.yang@samsung.com>
Fri, 28 Aug 2020 09:52:49 +0000 (18:52 +0900)
- 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 <jm80.yang@samsung.com>
packaging/libmm-camcorder.spec
src/include/mm_camcorder_internal.h
src/include/mm_camcorder_videorec.h
src/mm_camcorder_configure.c
src/mm_camcorder_gstcommon.c
src/mm_camcorder_internal.c
src/mm_camcorder_videorec.c

index 96bfce7..aa29705 100644 (file)
@@ -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
index 7edc812..8ac7edb 100644 (file)
@@ -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,
index c148c64..b6d845e 100644 (file)
@@ -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;
 
index 98c64e1..2f77582 100644 (file)
@@ -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 */
index 1c75930..d508c3f 100644 (file)
@@ -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;
 }
index fd26f73..5bb47d4 100644 (file)
@@ -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) {
index 79aeab4..b7be551 100644 (file)
@@ -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 */