webrtc_sink_snapshot: Support PNG format 26/285226/5
authorSangchul Lee <sc11.lee@samsung.com>
Thu, 8 Dec 2022 01:51:10 +0000 (10:51 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Fri, 9 Dec 2022 00:27:36 +0000 (09:27 +0900)
[Version] 0.3.271
[Issue Type] Add

Change-Id: I663ea2cf682492929745e3b9022ec86c9e5c4051
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
CMakeLists.txt
include/webrtc_private.h
packaging/capi-media-webrtc.spec
src/webrtc_sink.c
src/webrtc_sink_snapshot.c

index 9bb8d7f954ba25170f33ddd936a1b165498630d6..dc637db6d17589b25039f05fa5e37e4a68fb909d 100644 (file)
@@ -13,7 +13,7 @@ INCLUDE_DIRECTORIES(${INC_DIR})
 SET(dependents "dlog glib-2.0 gstreamer-1.0 gstreamer-webrtc-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 \
                 gstreamer-allocators-1.0 libpulse json-glib-1.0 iniparser mm-common mm-display-interface capi-media-tool \
                 libtbm libwebsockets cynara-client libsmack capi-system-info libsoup-2.4 bundle capi-media-sound-manager \
-                mm-fileinfo mmutil-common mmutil-imgp mmutil-jpeg")
+                mm-fileinfo mmutil-common mmutil-imgp mmutil-jpeg mmutil-magick")
 IF(NOT TIZEN_PROFILE_TV)
     SET(dependents "${dependents} mm-resource-manager")
     IF(TIZEN_FEATURE_UI)
index 56099f09879192e0bd78ef0616d2f637108b3259..88c2ad9900afe65f2691183af529127990396993 100644 (file)
@@ -541,6 +541,7 @@ typedef struct _webrtc_s {
 typedef enum snapshot_format_e {
        SNAPSHOT_FORMAT_RGB24,
        SNAPSHOT_FORMAT_JPEG,
+       SNAPSHOT_FORMAT_PNG,
 } snapshot_format_e;
 
 /* FIXME: divide into two slot types or use union */
@@ -611,7 +612,7 @@ typedef struct _webrtc_gst_slot_s {
                gulong sink_pad_probe_id;
                GMutex mutex;
                snapshot_format_e target_format;
-               int quality;
+               int option; /* quality for JPEG, compression level for PNG */
        } snapshot;
 
        struct {
@@ -793,7 +794,7 @@ void _remove_probe_from_pad_for_dump(webrtc_gst_slot_s *sink);
 /* sink capture video frame */
 int _init_convert_thread(webrtc_s *webrtc);
 void _deinit_convert_thread(webrtc_s *webrtc);
-int _capture_video_frame_from_sink(webrtc_s *webrtc, unsigned int track_id, snapshot_format_e format, int quality);
+int _capture_video_frame_from_sink(webrtc_s *webrtc, unsigned int track_id, snapshot_format_e format, int option);
 int _capture_video_frame(webrtc_gst_slot_s *sink);
 
 /* display */
index 5c33dab3cf1feb159de9c0e7112fd7bfd89f027c..568cc16b7b8075e881bec26ad8a402bc1a0f1470 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.3.270
+Version:    0.3.271
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
@@ -38,6 +38,7 @@ BuildRequires:  pkgconfig(mm-fileinfo)
 BuildRequires:  pkgconfig(mmutil-common)
 BuildRequires:  pkgconfig(mmutil-imgp)
 BuildRequires:  pkgconfig(mmutil-jpeg)
+BuildRequires:  pkgconfig(mmutil-magick)
 %if "%{tizen_profile_name}" != "tv"
 BuildRequires:  pkgconfig(mm-resource-manager)
 BuildRequires:  pkgconfig(capi-system-sensor)
index fa3cce4d39a580d56d4e96af56f0f06001295f8f..b2481ccc661e035733fedc883bc430d84234e1db 100644 (file)
@@ -1308,7 +1308,7 @@ int _get_video_resolution_from_sink(webrtc_s *webrtc, unsigned int track_id, int
        return WEBRTC_ERROR_NONE;
 }
 
-int _capture_video_frame_from_sink(webrtc_s *webrtc, unsigned int track_id, snapshot_format_e format, int quality)
+int _capture_video_frame_from_sink(webrtc_s *webrtc, unsigned int track_id, snapshot_format_e format, int option)
 {
        webrtc_gst_slot_s *sink;
 
@@ -1320,13 +1320,15 @@ int _capture_video_frame_from_sink(webrtc_s *webrtc, unsigned int track_id, snap
        RET_VAL_IF(sink->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL");
        RET_VAL_IF(sink->encoded_frame_cb != NULL, WEBRTC_ERROR_INVALID_OPERATION, "it may be a forwarding sink for encoded frame callback");
        RET_VAL_IF((sink->media_types & MEDIA_TYPE_VIDEO) == 0x0, WEBRTC_ERROR_INVALID_OPERATION, "it's not a video track");
+       RET_VAL_IF(format == SNAPSHOT_FORMAT_JPEG && (option < 1 || option > 100), WEBRTC_ERROR_INVALID_PARAMETER, "invalid JPEG option value");
+       RET_VAL_IF(format == SNAPSHOT_FORMAT_PNG && (option < 0 || option > 9), WEBRTC_ERROR_INVALID_PARAMETER, "invalid PNG option value");
 
        g_mutex_lock(&sink->snapshot.mutex); /* unlock in __remove_probe_from_pad_for_snapshot() */
 
        sink->snapshot.target_format = format;
-       sink->snapshot.quality = quality;
+       sink->snapshot.option = option;
 
-       LOG_INFO("webrtc[%p] track_id[%u] format[%d] quality[%d]", webrtc, track_id, format, quality);
+       LOG_INFO("webrtc[%p] track_id[%u] format[%d] option[%d]", webrtc, track_id, format, option);
 
        return _capture_video_frame(sink);
 }
index 8bd794da96ad14cdb09b7099c6322b709712905f..99649af8e80454a4fca21051b31a4ffb9dee467a 100644 (file)
@@ -22,6 +22,7 @@
 #include <mm_util_image.h>
 #include <mm_util_imgp.h>
 #include <mm_util_jpeg.h>
+#include <mm_util_magick.h>
 
 typedef struct {
        unsigned char *data;
@@ -35,12 +36,13 @@ typedef struct {
        MMVideoBuffer *vbuffer;
        bool exit;
        snapshot_format_e target_format;
-       int quality;
+       int option;
 } queue_data_s;
 
 static const char * __format_str[] = {
        [SNAPSHOT_FORMAT_RGB24] = "RGB24",
        [SNAPSHOT_FORMAT_JPEG] = "JPEG",
+       [SNAPSHOT_FORMAT_PNG] = "PNG",
 };
 
 //LCOV_EXCL_START
@@ -157,7 +159,8 @@ static MMVideoBuffer* __get_video_frame_raw_data(GstBuffer *buffer, GstPad *pad,
        return vbuffer;
 }
 
-static int __mm_image_convert_colorspace(unsigned char *src_data, size_t src_size, int src_w, int src_h, mm_util_color_format_e src_fmt, mm_util_color_format_e dst_fmt, webrtc_video_frame_s *result)
+static int __mm_image_convert_colorspace(unsigned char *src_data, size_t src_size, int src_w, int src_h, mm_util_color_format_e src_fmt,
+       mm_util_color_format_e dst_fmt, webrtc_video_frame_s *result)
 {
        int ret;
        mm_util_image_h src_image;
@@ -188,38 +191,76 @@ static int __mm_image_convert_colorspace(unsigned char *src_data, size_t src_siz
        return WEBRTC_ERROR_NONE;
 }
 
-static int __mm_image_encode(unsigned char *src_data, size_t src_size, int src_w, int src_h, mm_util_color_format_e src_fmt, mm_util_img_codec_type codec, int quality, webrtc_video_frame_s *result)
+static int __mm_image_encode(unsigned char *src_data, size_t src_size, int src_w, int src_h, mm_util_color_format_e src_fmt,
+       mm_util_img_codec_type codec, int option, webrtc_video_frame_s *result)
 {
-       int ret;
+       int mm_ret;
+       int ret = WEBRTC_ERROR_INVALID_OPERATION;
        mm_util_image_h src_image;
+       mm_util_enc_opt_h enc_opt = NULL;
 
        RET_VAL_IF(src_data == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "src_data is NULL");
        RET_VAL_IF(result == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "result is NULL");
 
        LOG_DEBUG_ENTER();
 
-       ret = mm_image_create_image(src_w, src_h, src_fmt, src_data, src_size, &src_image);
-       RET_VAL_IF(ret != MM_UTIL_ERROR_NONE, WEBRTC_ERROR_INVALID_OPERATION, "failed to mm_image_create_image()");
-
-       result->width = src_w;
-       result->height = src_h;
+       mm_ret = mm_image_create_image(src_w, src_h, src_fmt, src_data, src_size, &src_image);
+       RET_VAL_IF(mm_ret != MM_UTIL_ERROR_NONE, WEBRTC_ERROR_INVALID_OPERATION, "failed to mm_image_create_image()");
 
        switch (codec) {
        case IMG_CODEC_JPEG:
-               ret = mm_util_encode_to_jpeg_memory(src_image, quality, (void **)&result->data, &result->size);
-               mm_image_destroy_image(src_image);
-               RET_VAL_IF(ret != MM_UTIL_ERROR_NONE, WEBRTC_ERROR_INVALID_OPERATION, "failed to mm_util_encode_to_jpeg_memory()");
+               /* option value is for quality (1 ~ 100) */
+               mm_ret = mm_util_encode_to_jpeg_memory(src_image, option, (void **)&result->data, &result->size);
+               if (mm_ret != MM_UTIL_ERROR_NONE) {
+                       LOG_ERROR("failed to mm_util_encode_to_jpeg_memory()");
+                       goto error;
+               }
+               break;
+       case IMG_CODEC_PNG: {
+               mm_ret = mm_util_enc_opt_create(&enc_opt);
+               if (mm_ret != MM_UTIL_ERROR_NONE) {
+                       LOG_ERROR("failed to mm_util_enc_opt_create()");
+                       goto error;
+               }
 
-               LOG_INFO("src[data:%p, size:%zu, %dx%d, fmt:%d] -> dst[data:%p, size:%zu, %ux%u, codec:JPEG, quality:%d]",
-                       src_data, src_size, src_w, src_h, src_fmt,
-                       result->data, result->size, result->width, result->height, quality);
-               return WEBRTC_ERROR_NONE;
+               mm_ret = mm_util_enc_opt_set_codec(enc_opt, IMG_CODEC_PNG);
+               if (mm_ret != MM_UTIL_ERROR_NONE) {
+                       LOG_ERROR("failed to mm_util_enc_opt_set_codec()");
+                       goto error;
+               }
+
+               /* option value is for compression level (0 ~ 9) */
+               mm_ret = mm_util_enc_opt_set_png_compression(enc_opt, (unsigned int)option);
+               if (mm_ret != MM_UTIL_ERROR_NONE) {
+                       LOG_ERROR("failed to mm_util_enc_opt_set_png_compression()");
+                       goto error;
+               }
 
+               mm_ret = mm_util_encode_image_to_buffer(src_image, enc_opt, (void **)&result->data, &result->size);
+               if (mm_ret != MM_UTIL_ERROR_NONE) {
+                       LOG_ERROR("failed to mm_util_encode_image_to_buffer()");
+                       goto error;
+               }
+               break;
+       }
        default:
                LOG_ERROR_IF_REACHED("codec(%d)", codec);
-               mm_image_destroy_image(src_image);
-               return WEBRTC_ERROR_INVALID_PARAMETER;
+               ret = WEBRTC_ERROR_INVALID_PARAMETER;
+               goto error;
        }
+
+       result->width = src_w;
+       result->height = src_h;
+       ret = WEBRTC_ERROR_NONE;
+
+       LOG_INFO("src[data:%p, size:%zu, %dx%d, fmt:%d] -> dst[data:%p, size:%zu, %ux%u, codec:%d, option:%d]",
+               src_data, src_size, src_w, src_h, src_fmt,
+               result->data, result->size, result->width, result->height, codec, option);
+error:
+       if (enc_opt)
+               mm_util_enc_opt_destroy(enc_opt);
+       mm_image_destroy_image(src_image);
+       return ret;
 }
 
 static int __get_src_size(MMVideoBuffer *vbuffer, mm_util_color_format_e color_format)
@@ -333,7 +374,7 @@ static void __dump_rgb24_result(webrtc_video_frame_s *result, unsigned int idx)
        LOG_WARNING("converted rgb24 frame is dumped to [%s]", file_path);
 }
 
-static void __dump_encoded_result(webrtc_video_frame_s *result, snapshot_format_e target_format, unsigned int idx)
+static void __dump_encoded_result(webrtc_video_frame_s *result, snapshot_format_e target_format, int option, unsigned int idx)
 {
        g_autofree gchar *file_path = NULL;
        g_autoptr(GError) error = NULL;
@@ -343,7 +384,7 @@ static void __dump_encoded_result(webrtc_video_frame_s *result, snapshot_format_
        if (!result->data)
                return;
 
-       file_path = g_strdup_printf("/tmp/snapshot_%03u_%ux%u_%s.dump", idx, result->width, result->height, __format_str[target_format]);
+       file_path = g_strdup_printf("/tmp/snapshot_%03u_%ux%u_%s_opt%d.dump", idx, result->width, result->height, __format_str[target_format], option);
 
        if (!g_file_set_contents(file_path, (char *)result->data, result->size, &error)) {
                LOG_ERROR("failed to g_file_set_contents() for %s, error:%s", file_path, error->message);
@@ -384,7 +425,7 @@ static GstPadProbeReturn __snapshot_probe_cb(GstPad *pad, GstPadProbeInfo *info,
        qd->color_format = color_format;
        qd->vbuffer = vbuffer;
        qd->target_format = probe_data->slot->snapshot.target_format;
-       qd->quality = probe_data->slot->snapshot.quality;
+       qd->option = probe_data->slot->snapshot.option;
        g_async_queue_push(probe_data->slot->webrtc->snapshot.queue, qd);
 
 out:
@@ -422,18 +463,20 @@ static gpointer __convert_thread(gpointer data)
                        case SNAPSHOT_FORMAT_RGB24:
                                break; /* skip encoding */
                        case SNAPSHOT_FORMAT_JPEG:
+                       case SNAPSHOT_FORMAT_PNG:
                                ret = __mm_image_encode(rgb24_frame.data, rgb24_frame.size, rgb24_frame.width, rgb24_frame.height, MM_UTIL_COLOR_RGB24,
-                                       IMG_CODEC_JPEG, qd->quality, &encoded_frame);
-                               if (ret != WEBRTC_ERROR_NONE)
-                                       LOG_ERROR("failed to __mm_image_encode() for %s", __format_str[qd->target_format]);
+                                       (qd->target_format == SNAPSHOT_FORMAT_JPEG) ? IMG_CODEC_JPEG : IMG_CODEC_PNG, qd->option, &encoded_frame);
                                break;
                        default:
                                LOG_ERROR_IF_REACHED("target_format(%d)", qd->target_format);
+                               ret = WEBRTC_ERROR_INVALID_PARAMETER;
                                break;
                        }
+                       if (ret != WEBRTC_ERROR_NONE)
+                               LOG_ERROR("failed to encode image(), ret[0x%x]", ret);
 #ifdef DUMP_CONVERTED_RESULT
                        __dump_rgb24_result(&rgb24_frame, ++idx);
-                       __dump_encoded_result(&encoded_frame, qd->target_format, idx);
+                       __dump_encoded_result(&encoded_frame, qd->target_format, qd->option, idx);
 #endif
                        /* TODO: Append data to user callback */
                }
@@ -484,7 +527,8 @@ int _capture_video_frame(webrtc_gst_slot_s *sink)
 
        RET_VAL_IF(sink == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "sink is NULL");
        RET_VAL_IF(sink->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL");
-       RET_VAL_IF(!(videosink = gst_bin_get_by_name(sink->bin, ELEMENT_NAME_VIDEO_SINK)), WEBRTC_ERROR_INVALID_OPERATION, "could not find video sink element");
+       RET_VAL_IF(!(videosink = gst_bin_get_by_name(sink->bin, ELEMENT_NAME_VIDEO_SINK)), WEBRTC_ERROR_INVALID_OPERATION,
+               "could not find video sink element");
 
        __add_probe_to_pad_for_snapshot(sink, videosink, __snapshot_probe_cb);