From: jiyong.min Date: Thu, 11 Mar 2021 22:42:31 +0000 (+0900) Subject: Add heif image decoder X-Git-Tag: submit/tizen/20210316.062438^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=461e7304ebdc66e96b46592061f45664446cc5af;p=platform%2Fcore%2Fmultimedia%2Flibmm-utility.git Add heif image decoder Change-Id: I767494f893f5aa4c53de0a442137d2d9304d465f --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 7dba1fb..aef68f6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,7 @@ ADD_SUBDIRECTORY(jpeg) ADD_SUBDIRECTORY(magick) ADD_SUBDIRECTORY(webp) ADD_SUBDIRECTORY(anim) +ADD_SUBDIRECTORY(heif) IF(UNIX) diff --git a/heif/CMakeLists.txt b/heif/CMakeLists.txt new file mode 100644 index 0000000..7c26123 --- /dev/null +++ b/heif/CMakeLists.txt @@ -0,0 +1,73 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_name "mmutil_heif") + +PROJECT(${fw_name}) + +SET(VERSION_MAJOR 0) +SET(VERSION "${VERSION_MAJOR}.0.0") +SET(CMAKE_INSTALL_PREFIX /usr) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +SET(INC_DIR + include +) +INCLUDE_DIRECTORIES(${INC_DIR} + ../common/include + ../jpeg/include +) + +SET(dependents "dlog glib-2.0 heif") + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_name} REQUIRED ${dependents}) +FOREACH(flag ${${fw_name}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Werror") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") + +IF("${ARCH}" STREQUAL "arm") + ADD_DEFINITIONS("-DTARGET") +ENDIF("${ARCH}" STREQUAL "arm") + +ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") +ADD_DEFINITIONS("-DLIBPREFIX=\"${LIB_INSTALL_DIR}\"") +ADD_DEFINITIONS("-DTIZEN_DEBUG") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}") + +aux_source_directory(. SOURCES) +ADD_LIBRARY(${fw_name} SHARED ${SOURCES}) +TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS} mmutil_common heif) +SET_TARGET_PROPERTIES(${fw_name} + PROPERTIES + VERSION ${VERSION} + SOVERSION ${VERSION_MAJOR} + CLEAN_DIRECT_OUTPUT 1 +) + +INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR}) +INSTALL( + DIRECTORY ${INC_DIR}/ DESTINATION include/mmf + FILES_MATCHING + PATTERN "*_internal.h" EXCLUDE + PATTERN "*_private.h" EXCLUDE + PATTERN "${INC_DIR}/*.h" +) + +SET(PC_NAME mmutil-heif) +SET(PC_LDFLAGS -l${fw_name}) +SET(PC_FILE_NAME ${PC_NAME}.pc.in) + +CONFIGURE_FILE( + ${PC_FILE_NAME} + ${CMAKE_CURRENT_SOURCE_DIR}/${PC_NAME}.pc + @ONLY +) +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PC_NAME}.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) + +ADD_SUBDIRECTORY(test) +#IF(BUILD_GTESTS) +# ADD_SUBDIRECTORY(unittest) +#ENDIF(BUILD_GTESTS) diff --git a/heif/include/mm_util_heif.h b/heif/include/mm_util_heif.h new file mode 100644 index 0000000..f4d01be --- /dev/null +++ b/heif/include/mm_util_heif.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef __MM_UTIL_HEIF_H__ +#define __MM_UTIL_HEIF_H__ + +#include "mm_util_type.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +int mm_util_decode_heif_from_file(const char *path, mm_util_color_format_e format, mm_util_image_h *decoded_image); +int mm_util_decode_heif_from_buffer(const void *buf, size_t buf_size, mm_util_color_format_e format, mm_util_image_h *decoded_image); + + +#ifdef __cplusplus +} +#endif + +#endif /*__MM_UTIL_HEIF_H__*/ diff --git a/heif/mm_util_heif.c b/heif/mm_util_heif.c new file mode 100644 index 0000000..8ff2397 --- /dev/null +++ b/heif/mm_util_heif.c @@ -0,0 +1,135 @@ +/* +* Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include + +#include +#include + +#include "mm_util_heif.h" +#include "mm_util_private.h" +#include "mm_util_image.h" + + +static int __mm_util_error(int error_code) +{ + switch (error_code) { + case LIBHEIF_ERROR_NONE: + return MM_UTIL_ERROR_NONE; + + case LIBHEIF_ERROR_INVALID_PARAMETER: + return MM_UTIL_ERROR_INVALID_PARAMETER; + + case LIBHEIF_ERROR_NOT_SUPPORTED: + return MM_UTIL_ERROR_NOT_SUPPORTED_FORMAT; + + case LIBHEIF_ERROR_PERMISSION_DENIED: + // fall through + case LIBHEIF_ERROR_INVALID_OPERATION: + // fall through + default: + return MM_UTIL_ERROR_INVALID_OPERATION; + } + +} + +static heif_color_format_e __get_heif_color_format(mm_util_color_format_e color_format) +{ + switch(color_format) { + case MM_UTIL_COLOR_YUV420: + return HEIF_COLOR_FORMAT_YUV420P; + case MM_UTIL_COLOR_RGB24: + return HEIF_COLOR_FORMAT_RGB24; + case MM_UTIL_COLOR_ARGB: + return HEIF_COLOR_FORMAT_ARGB; + case MM_UTIL_COLOR_BGRA: + return HEIF_COLOR_FORMAT_BGRA; + case MM_UTIL_COLOR_RGBA: + return HEIF_COLOR_FORMAT_RGBA; + default: + return HEIF_COLOR_FORMAT_NONE; + } +} + +static mm_util_color_format_e __get_mm_color_format(heif_color_format_e color_format) +{ + switch(color_format) { + case HEIF_COLOR_FORMAT_YUV420P: + return MM_UTIL_COLOR_YUV420; + case HEIF_COLOR_FORMAT_RGB24: + return MM_UTIL_COLOR_RGB24; + case HEIF_COLOR_FORMAT_ARGB: + return MM_UTIL_COLOR_ARGB; + case HEIF_COLOR_FORMAT_BGRA: + return MM_UTIL_COLOR_BGRA; + case HEIF_COLOR_FORMAT_RGBA: + return MM_UTIL_COLOR_RGBA; + default: + return MM_UTIL_COLOR_NUM; + } +} + +static mm_util_image_h __get_mm_image(heif_image_h image) +{ + int ret = LIBHEIF_ERROR_NONE; + mm_util_image_h mm_image = NULL; + unsigned int width = 0, height = 0; + heif_color_format_e color = HEIF_COLOR_FORMAT_NONE; + unsigned char *data = NULL; + size_t size = 0; + + ret = heif_image_get_image(image, &width, &height, &color, &data, &size); + mm_util_retvm_if(ret != LIBHEIF_ERROR_NONE, NULL, "heif_decode_image_from_file is failed (%d)", ret); + + ret = mm_image_create_image(width, height, __get_mm_color_format(color), (void *)data, size, &mm_image); + mm_util_retvm_if(ret != LIBHEIF_ERROR_NONE, NULL, "mm_image_create_image is failed (%d)", ret); + + return mm_image; +} + +int mm_util_decode_heif_from_file(const char *path, mm_util_color_format_e format, mm_util_image_h *decoded_image) +{ + int ret = LIBHEIF_ERROR_NONE; + heif_image_h image = NULL; + + mm_util_retvm_if(!decoded_image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid decoded_image"); + + ret = heif_decode_image_from_file(path, __get_heif_color_format(format), &image); + mm_util_retvm_if(ret != LIBHEIF_ERROR_NONE, __mm_util_error(ret), "heif_decode_image_from_file is failed (%d)", ret); + + *decoded_image = __get_mm_image(image); + + heif_image_free(image); + + return MM_UTIL_ERROR_NONE; +} + +int mm_util_decode_heif_from_buffer(const void *buf, size_t buf_size, mm_util_color_format_e format, mm_util_image_h *decoded_image) +{ + int ret = LIBHEIF_ERROR_NONE; + heif_image_h image = NULL; + + mm_util_retvm_if(!decoded_image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid decoded_image"); + + ret = heif_decode_image_from_buffer((unsigned char *)buf, buf_size, __get_heif_color_format(format), &image); + mm_util_retvm_if(ret != LIBHEIF_ERROR_NONE, __mm_util_error(ret), "heif_decode_image_from_buffer is failed (%d)", ret); + + *decoded_image = __get_mm_image(image); + + heif_image_free(image); + + return MM_UTIL_ERROR_NONE; +} diff --git a/heif/mmutil-heif.pc.in b/heif/mmutil-heif.pc.in new file mode 100644 index 0000000..91f801d --- /dev/null +++ b/heif/mmutil-heif.pc.in @@ -0,0 +1,11 @@ +prefix=@PREFIX@ +exec_prefix=/usr +libdir=@LIB_INSTALL_DIR@ +includedir=/usr/include/mmf + +Name : @PC_NAME@ +Description : Multimedia Framework Utility Library +Requires : +Version : @VERSION@ +Libs : -L${libdir} @PC_LDFLAGS@ +Cflags : -I${includedir} diff --git a/heif/test/CMakeLists.txt b/heif/test/CMakeLists.txt new file mode 100644 index 0000000..5451360 --- /dev/null +++ b/heif/test/CMakeLists.txt @@ -0,0 +1,18 @@ +SET(fw_name "mmutil_heif") +SET(fw_test "${fw_name}-test") + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_test} REQUIRED glib-2.0 dlog libtzplatform-config) +FOREACH(flag ${${fw_test}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -Wall -fPIE -Werror") + +aux_source_directory(. sources) +FOREACH(src ${sources}) + GET_FILENAME_COMPONENT(src_name ${src} NAME_WE) + MESSAGE("${src_name}") + ADD_EXECUTABLE(${src_name} ${src}) + TARGET_LINK_LIBRARIES(${src_name} ${fw_name} ${${fw_test}_LDFLAGS} mmutil_common mmutil_jpeg) +ENDFOREACH() diff --git a/heif/test/mm_util_heif_testsuite.c b/heif/test/mm_util_heif_testsuite.c new file mode 100644 index 0000000..a776f93 --- /dev/null +++ b/heif/test/mm_util_heif_testsuite.c @@ -0,0 +1,248 @@ +/* +* Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include +#include +#include +#include + +#include +#include +#include + +#define SAFE_FREE(x) { g_free(x); x = NULL; } +#define SAFE_IMAGE_FREE(x) { if (x != NULL) { mm_image_destroy_image(x); x = NULL; } } + +typedef enum { + TEST_AUTO, + TEST_DECODE_FILE, + TEST_DECODE_BUFFER, + TEST_NUM, +} heif_test_mode_e; + +static char *MODE_TO_STR[] = { + "AUTO", + "DECODE_FILE", + "DECODE_BUFFER", + "", +}; + +/* for arguments */ +static int g_test_mode = 0; +static char *g_path = NULL; +static int g_color = MM_UTIL_COLOR_RGB24; + +/* for reading file */ +static gchar *g_readed_data = NULL; +static gsize g_readed_size = 0; + +/* for saving result */ +static const char *g_test_filename[TEST_NUM][MM_UTIL_COLOR_NUM] = { + [TEST_AUTO] = { + NULL, + }, + [TEST_DECODE_FILE] = { + [MM_UTIL_COLOR_YUV420] = "/opt/usr/home/owner/media/test_heif_file_yuv420p.jpg", + [MM_UTIL_COLOR_YUV422] = NULL, + [MM_UTIL_COLOR_I420] = NULL, + [MM_UTIL_COLOR_NV12] = NULL, + [MM_UTIL_COLOR_UYVY] = NULL, + [MM_UTIL_COLOR_YUYV] = NULL, + [MM_UTIL_COLOR_RGB16] = NULL, + [MM_UTIL_COLOR_RGB24] = "/opt/usr/home/owner/media/test_heif_file_rgb24.jpg", + [MM_UTIL_COLOR_ARGB] = "/opt/usr/home/owner/media/test_heif_file_argb.jpg", + [MM_UTIL_COLOR_BGRA] = "/opt/usr/home/owner/media/test_heif_file_bgra.jpg", + [MM_UTIL_COLOR_RGBA] = "/opt/usr/home/owner/media/test_heif_file_rgba.jpg", + [MM_UTIL_COLOR_BGRX] = NULL, + [MM_UTIL_COLOR_NV12_TILED] = NULL, + [MM_UTIL_COLOR_NV16] = NULL, + [MM_UTIL_COLOR_NV61] = NULL, + [MM_UTIL_COLOR_NV21] = NULL, + [MM_UTIL_COLOR_GRAYSCALE] = NULL, + }, + [TEST_DECODE_BUFFER] = { + [MM_UTIL_COLOR_YUV420] = "/opt/usr/home/owner/media/test_heif_buff_yuv420p.jpg", + [MM_UTIL_COLOR_YUV422] = NULL, + [MM_UTIL_COLOR_I420] = NULL, + [MM_UTIL_COLOR_NV12] = NULL, + [MM_UTIL_COLOR_UYVY] = NULL, + [MM_UTIL_COLOR_YUYV] = NULL, + [MM_UTIL_COLOR_RGB16] = NULL, + [MM_UTIL_COLOR_RGB24] = "/opt/usr/home/owner/media/test_heif_buff_rgb24.jpg", + [MM_UTIL_COLOR_ARGB] = "/opt/usr/home/owner/media/test_heif_buff_argb.jpg", + [MM_UTIL_COLOR_BGRA] = "/opt/usr/home/owner/media/test_heif_buff_bgra.jpg", + [MM_UTIL_COLOR_RGBA] = "/opt/usr/home/owner/media/test_heif_buff_rgba.jpg", + [MM_UTIL_COLOR_BGRX] = NULL, + [MM_UTIL_COLOR_NV12_TILED] = NULL, + [MM_UTIL_COLOR_NV16] = NULL, + [MM_UTIL_COLOR_NV61] = NULL, + [MM_UTIL_COLOR_NV21] = NULL, + [MM_UTIL_COLOR_GRAYSCALE] = NULL, + }, +}; + +static mm_util_image_h g_decoded_data = NULL; + +static gboolean __get_input_data(const char *argv, const long min, const long max, int *data) +{ + if (!argv || strlen(argv) == 0) + return FALSE; + + if (!data) + return FALSE; + + long temp = g_ascii_strtoll(argv, NULL, 10); + if (temp < min || temp > max) + return FALSE; + + *data = (int)temp; + + return TRUE; +} + +static void __print_help(const char *argv0) +{ + g_print("\t[usage]\n"); + g_print("\t\t1. decode : %s mode path color_format(opt.)\n", argv0); + g_print("\t\t2. mode : 0 - auto, 1 - decode from file, 2 - decode from memory\n"); + g_print("\t\t\t e.g. %s 0 test.heif\n", argv0); + g_print("\t\t\t e.g. %s 1 test.heif 7\n", argv0); +} + +static gboolean __get_arguments(int argc, char *argv[]) +{ + if (!__get_input_data(argv[1], TEST_AUTO, TEST_NUM - 1, &g_test_mode)) { + g_print("\t[HEIF_testsuite] wrong mode(%s) for test\n", argv[1]); + __print_help(argv[0]); + return FALSE; + } + + g_path = g_strdup(argv[2]); + + if (g_test_mode == TEST_AUTO) { + // do nothing + } else if (g_test_mode == TEST_DECODE_FILE) { + if (!__get_input_data(argv[3], MM_UTIL_COLOR_YUV420, MM_UTIL_COLOR_NUM - 1, &g_color)) + g_print("\t[HEIF_testsuite] color is default(%d)\n", g_color); + } else if (g_test_mode == TEST_DECODE_BUFFER) { + if (!__get_input_data(argv[3], MM_UTIL_COLOR_YUV420, MM_UTIL_COLOR_NUM - 1, &g_color)) + g_print("\t[HEIF_testsuite] color is default(%d)\n", g_color); + } else { + g_print("\t[HEIF_testsuite] wrong mode for test %s\n", argv[1]); + return FALSE; + } + + return TRUE; +} + +static gboolean __test_decode(const heif_test_mode_e mode, mm_util_color_format_e color, const char *path) +{ + int ret = 0; + GError *error = NULL; + + if (!path) { + g_print("\t[HEIF_testsuite] No-Error\n"); + return TRUE; + } + + /* test decoding heif */ + if (mode == TEST_DECODE_FILE) { + ret = mm_util_decode_heif_from_file(g_path, color, &g_decoded_data); + if (ret != MM_UTIL_ERROR_NONE) { + g_print("\t[HEIF_testsuite] mm_util_decode_heif_from_file failed %d\n", ret); + return FALSE; + } + } else if (mode == TEST_DECODE_BUFFER) { + if (!g_file_get_contents(g_path, &g_readed_data, &g_readed_size, &error)) { + g_print("\t[HEIF_testsuite] reading file error(%s)\n", (error ? error->message : "none")); + if (error) + g_error_free(error); + return FALSE; + } + + ret = mm_util_decode_heif_from_buffer(g_readed_data, g_readed_size, color, &g_decoded_data); + if (ret != MM_UTIL_ERROR_NONE) { + g_print("\t[HEIF_testsuite] mm_util_decode_heif_from_buffer failed %d\n", ret); + return FALSE; + } + } + + ret = mm_util_jpeg_encode_to_file(g_decoded_data, 100, path); + if (ret != MM_UTIL_ERROR_NONE) { + g_print("\t[HEIF_testsuite] mm_util_jpeg_encode_to_file failed %d : %s\n", ret, path); + return FALSE; + } + + return TRUE; +} + +static gboolean __test_auto() +{ + heif_test_mode_e test_mode = TEST_DECODE_FILE; + mm_util_color_format_e color = MM_UTIL_COLOR_YUV420; + gboolean result = FALSE; + + while (test_mode < TEST_NUM) { + g_print("\t[HEIF_testsuite] >>>>>>>>>>>>>>>>>>>>>> \'%s\' TEST START\n", MODE_TO_STR[test_mode]); + /* test decoding heif */ + if ((test_mode == TEST_DECODE_FILE) || (test_mode == TEST_DECODE_BUFFER)) { + for (color = MM_UTIL_COLOR_YUV420; color < MM_UTIL_COLOR_NUM; color++) { + result |= __test_decode(test_mode, color, g_test_filename[test_mode][color]); + SAFE_FREE(g_readed_data); + SAFE_IMAGE_FREE(g_decoded_data); + } + } + + g_print("\t[HEIF_testsuite] >>>>>>>>>>>>>>>>>>>>>> \'%s\' TEST %s\n", + MODE_TO_STR[test_mode], (result) ? "SUCCESS" : "FAIL"); + test_mode++; + } + + return TRUE; +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + __print_help(argv[0]); + return 0; + } + + if (!__get_arguments(argc, argv)) { + g_print("\t[HEIF_testsuite] _get_arguments failed\n"); + goto out; + } + + /* test all functions automatically */ + if (g_test_mode == TEST_AUTO) { + if (!__test_auto()) + g_print("\t[HEIF_testsuite] _test_auto failed\n"); + goto out; + } + + /* test decoding heif */ + if ((g_test_mode == TEST_DECODE_FILE) || (g_test_mode == TEST_DECODE_BUFFER)) { + if (!__test_decode(g_test_mode, g_color, g_test_filename[g_test_mode][g_color])) + g_print("\t[HEIF_testsuite] _test_decode(%s) failed\n", MODE_TO_STR[g_test_mode]); + } + +out: + g_free(g_path); + SAFE_FREE(g_readed_data); + SAFE_IMAGE_FREE(g_decoded_data); + + return 0; +} diff --git a/packaging/libmm-utility.spec b/packaging/libmm-utility.spec index 7aba819..85e6c93 100644 --- a/packaging/libmm-utility.spec +++ b/packaging/libmm-utility.spec @@ -1,6 +1,6 @@ Name: libmm-utility Summary: Multimedia Framework Utility Library -Version: 0.2.5 +Version: 0.3.0 Release: 0 Group: System/Libraries License: Apache-2.0 @@ -22,6 +22,7 @@ BuildRequires: pkgconfig(libwebp) BuildRequires: pkgconfig(libwebpmux) BuildRequires: giflib-devel BuildRequires: pkgconfig(GraphicsMagick) +BuildRequires: pkgconfig(heif) %if 0%{?gtests:1} BuildRequires: pkgconfig(gmock) %endif