ADD_SUBDIRECTORY(webp)
ADD_SUBDIRECTORY(anim)
ADD_SUBDIRECTORY(heif)
+ADD_SUBDIRECTORY(jxl)
IF(UNIX)
int mm_util_enc_opt_create(mm_util_enc_opt_h *enc_opt);
int mm_util_enc_opt_set_codec(mm_util_enc_opt_h enc_opt, mm_util_img_codec_type codec);
int mm_util_enc_opt_set_png_compression(mm_util_enc_opt_h enc_opt, unsigned int compression);
-int mm_util_enc_opt_set_webp_lossless(mm_util_enc_opt_h enc_opt, bool lossless);
+int mm_util_enc_opt_set_lossless(mm_util_enc_opt_h enc_opt, bool lossless);
void mm_util_enc_opt_destroy(mm_util_enc_opt_h enc_opt);
#ifdef __cplusplus
IMG_CODEC_GIF,
IMG_CODEC_BMP,
IMG_CODEC_WEBP,
+ IMG_CODEC_JPEGXL,
IMG_CODEC_WBMP = 100, // used by only media-content
IMG_CODEC_UNKNOWN_TYPE,
} mm_util_img_codec_type;
return MM_UTIL_ERROR_NONE;
}
-int mm_util_enc_opt_set_webp_lossless(mm_util_enc_opt_h enc_opt, bool lossless)
+int mm_util_enc_opt_set_lossless(mm_util_enc_opt_h enc_opt, bool lossless)
{
mm_util_enc_opt_t *enc_option = (mm_util_enc_opt_t *)enc_opt;
mm_util_retvm_if(!enc_opt, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid enc_opt");
- mm_util_retvm_if(enc_option->codec != IMG_CODEC_WEBP, MM_UTIL_ERROR_NOT_SUPPORTED_FORMAT, "not supported format [%d]", enc_option->codec);
+ mm_util_retvm_if(enc_option->codec != IMG_CODEC_WEBP && enc_option->codec != IMG_CODEC_JPEGXL, MM_UTIL_ERROR_NOT_SUPPORTED_FORMAT, "not supported format [%d]", enc_option->codec);
enc_option->lossless = lossless;
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(fw_name "mmutil_jxl")
+
+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")
+
+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 jxl jxl_threads)
+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-jxl)
+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)
--- /dev/null
+/*
+ * Copyright (c) 2022 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_JPEGXL_H__
+#define __MM_UTIL_JPEGXL_H__
+
+#include <mm_util_type.h>
+#include <mm_util_image.h>
+#include <mm_util_option.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int mm_util_decode_jxl_from_file(const char *path, mm_util_color_format_e format, mm_util_image_h *decoded_image);
+int mm_util_decode_jxl_from_buffer(const void *encoded_buf, size_t encoded_buf_size, mm_util_color_format_e format, mm_util_image_h *decoded_image);
+int mm_util_encode_jxl_to_file(mm_util_image_h decoded_image, mm_util_enc_opt_h enc_opt, const char *path);
+int mm_util_encode_jxl_to_buffer(mm_util_image_h decoded_image, mm_util_enc_opt_h enc_opt, void **encoded_buf, size_t *encoded_buf_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__MM_UTIL_JPEGXL_H__*/
--- /dev/null
+/*
+* Copyright (c) 2022 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 <stdio.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <jxl/decode.h>
+#include <jxl/encode.h>
+#include <jxl/thread_parallel_runner.h>
+
+#include "mm_util_jxl.h"
+#include "mm_util_private.h"
+
+
+// TODO: it will be moved into .ini of mmfw_config
+#define NUM_OF_THREADS 4
+
+
+static JxlPixelFormat jxl_formats[] = {
+ [MM_UTIL_COLOR_RGB24] = {3, JXL_TYPE_UINT8, JXL_BIG_ENDIAN, 0}, // RGB -> RGB
+ [MM_UTIL_COLOR_RGBA] = {4, JXL_TYPE_UINT8, JXL_BIG_ENDIAN, 0}, // RGBA -> RGBA
+};
+
+static int __convert_dec_error(JxlDecoderStatus status)
+{
+ int err = MM_UTIL_ERROR_NONE;
+
+ switch (status) {
+ case JXL_DEC_SUCCESS:
+ err = MM_UTIL_ERROR_NONE;
+ break;
+ case JXL_DEC_NEED_MORE_INPUT:
+ case JXL_DEC_NEED_PREVIEW_OUT_BUFFER:
+ case JXL_DEC_NEED_DC_OUT_BUFFER:
+ case JXL_DEC_NEED_IMAGE_OUT_BUFFER:
+ err = MM_UTIL_ERROR_INVALID_PARAMETER;
+ break;
+ case JXL_DEC_JPEG_NEED_MORE_OUTPUT:
+ err = MM_UTIL_ERROR_OUT_OF_MEMORY;
+ break;
+ case JXL_DEC_ERROR:
+ default:
+ err = MM_UTIL_ERROR_INVALID_OPERATION;
+ break;
+ }
+
+ mm_util_warn("convert err(%d) from status(%d)", err, status);
+
+ return err;
+}
+
+static int __convert_enc_error(JxlEncoderStatus status)
+{
+ int err = MM_UTIL_ERROR_NONE;
+
+ switch (status) {
+ case JXL_ENC_SUCCESS:
+ err = MM_UTIL_ERROR_NONE;
+ break;
+ case JXL_ENC_NEED_MORE_OUTPUT:
+ err = MM_UTIL_ERROR_OUT_OF_MEMORY;
+ break;
+ case JXL_ENC_NOT_SUPPORTED:
+ err = MM_UTIL_ERROR_NOT_SUPPORTED_FORMAT;
+ break;
+ case JXL_ENC_ERROR:
+ default:
+ err = MM_UTIL_ERROR_INVALID_OPERATION;
+ break;
+ }
+
+ mm_util_warn("convert err(%d) from status(%d)", err, status);
+
+ return err;
+}
+
+static int __get_file_size(const char *path, size_t *size)
+{
+ GStatBuf buf;
+
+ mm_util_retvm_if(!path, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid path");
+ mm_util_retvm_if(!size, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid size");
+
+ mm_util_fenter();
+
+ if (g_stat(path, &buf) < 0) {
+ mm_util_stderror("Fail to open path");
+ return MM_UTIL_ERROR_INVALID_PARAMETER;
+ }
+
+ *size = (size_t)buf.st_size;
+
+ mm_util_info("size: %zu", *size);
+
+ mm_util_fleave();
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+static int __get_decoded_data(mm_util_image_h decoded, uint32_t *width, uint32_t *height, JxlPixelFormat *format, uint8_t **pixels, size_t *pixels_size)
+{
+ mm_image_info_s *_image = (mm_image_info_s *)decoded;
+
+ mm_util_retvm_if(!mm_image_is_valid_image(decoded), MM_UTIL_ERROR_INVALID_PARAMETER, "invalid decoded");
+ mm_util_retvm_if((_image->color != MM_UTIL_COLOR_RGB24) && (_image->color != MM_UTIL_COLOR_RGBA),
+ MM_UTIL_ERROR_INVALID_PARAMETER, "invalid format %d", _image->color);
+ mm_image_debug_image(decoded, "SOURCE");
+
+ *width = (uint32_t)_image->width;
+ *height = (uint32_t)_image->height;
+ *format = jxl_formats[_image->color];
+ *pixels = _image->data;
+ *pixels_size = _image->size;
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+static bool __read_file(const char *path, void **data, size_t size)
+{
+ gsize read_n = 0;
+ gchar *read_data = NULL;
+ GError *error = NULL;
+
+ mm_util_retvm_if(!path, false, "invalid path");
+ mm_util_retvm_if(!data, false, "invalid data");
+ mm_util_retvm_if(size == 0, false, "invalid size");
+
+ mm_util_fenter();
+
+ if (!g_file_get_contents(path, &read_data, &read_n, &error)) {
+ mm_util_error("g_file_get_contents error(%s)", (error ? error->message : "none"));
+ if (error)
+ g_error_free(error);
+ return false;
+ }
+
+ if (read_n != size) {
+ mm_util_stderror("read");
+ mm_util_error("read_n: %zu, size: %zu", read_n, size);
+ g_free(read_data);
+ return false;
+ }
+
+ *data = read_data;
+
+ mm_util_fleave();
+
+ return true;
+}
+
+static bool __write_file(const char *path, void *data, size_t size)
+{
+ GError *error = NULL;
+
+ mm_util_retvm_if(!path, false, "invalid path");
+ mm_util_retvm_if(!data, false, "invalid data");
+ mm_util_retvm_if(size == 0, false, "invalid size");
+
+ mm_util_fenter();
+
+ if (!g_file_set_contents(path, (const gchar *)data, (gssize)size, &error)) {
+ mm_util_error("g_file_set_contents error(%s)", (error ? error->message : "none"));
+ if (error)
+ g_error_free(error);
+ return false;
+ }
+
+ mm_util_fleave();
+
+ return true;
+}
+
+static int __mm_util_decode_jpegxl(const void *buf, size_t buf_size, mm_util_color_format_e format, mm_util_image_h *decoded_image)
+{
+ int ret = MM_UTIL_ERROR_NONE;
+ JxlDecoderStatus status = JXL_DEC_ERROR;
+ JxlDecoder *jxl_dec = NULL;
+ void *jxl_thread = NULL;
+ JxlPixelFormat *jxl_format = &jxl_formats[format];
+ JxlBasicInfo info;
+ uint8_t* pixels = NULL;
+ size_t pixels_size = 0;
+
+ mm_util_retvm_if(!buf, MM_UTIL_ERROR_INVALID_PARAMETER, "buf is null");
+ mm_util_retvm_if(buf_size == 0, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid buf_size %zu", buf_size);
+ mm_util_retvm_if((format != MM_UTIL_COLOR_RGB24) && (format != MM_UTIL_COLOR_RGBA),
+ MM_UTIL_ERROR_INVALID_PARAMETER, "invalid format %d", format);
+ mm_util_retvm_if(!decoded_image, MM_UTIL_ERROR_INVALID_PARAMETER, "decoded_image is null");
+
+ mm_util_fenter();
+
+ jxl_dec = JxlDecoderCreate(NULL);
+ if (!jxl_dec) {
+ mm_util_error("failed to JxlDecoderCreate");
+ goto Exit;
+ }
+
+ jxl_thread = JxlThreadParallelRunnerCreate(NULL, NUM_OF_THREADS);
+ if (!jxl_thread) {
+ mm_util_error("failed to JxlThreadParallelRunnerCreate");
+ goto Exit;
+ }
+
+ status = JxlDecoderSetParallelRunner(jxl_dec, JxlThreadParallelRunner, jxl_thread);
+ if (status != JXL_DEC_SUCCESS) {
+ mm_util_error("failed to JxlDecoderSetParallelRunner(%d)", status);
+ goto Exit;
+ }
+
+ // set the events for process to invoke
+ status = JxlDecoderSubscribeEvents(jxl_dec, JXL_DEC_BASIC_INFO | JXL_DEC_FRAME | JXL_DEC_FULL_IMAGE);
+ if (status != JXL_DEC_SUCCESS) {
+ mm_util_error("failed to JxlDecoderSubscribeEvents(%d)", status);
+ goto Exit;
+ }
+
+ status = JxlDecoderSetInput(jxl_dec, buf, buf_size);
+ if (status != JXL_DEC_SUCCESS) {
+ mm_util_error("failed to JxlDecoderSetInput(%d)", status);
+ goto Exit;
+ }
+
+ // process to start container parsing
+ status = JxlDecoderProcessInput(jxl_dec);
+ if (status != JXL_DEC_BASIC_INFO) {
+ mm_util_error("failed to JxlDecoderProcessInput to start parsing (%d)", status);
+ goto Exit;
+ }
+
+ status = JxlDecoderImageOutBufferSize(jxl_dec, jxl_format, &pixels_size);
+ if (status != JXL_DEC_SUCCESS) {
+ mm_util_error("failed to JxlDecoderImageOutBufferSize(%d)", status);
+ goto Exit;
+ }
+
+ status = JxlDecoderGetBasicInfo(jxl_dec, &info);
+ if (status != JXL_DEC_SUCCESS) {
+ mm_util_error("failed to JxlDecoderGetBasicInfo(%d)", status);
+ goto Exit;
+ }
+
+ // calculate the size of output buffer
+ pixels = g_malloc0(pixels_size);
+
+ // process to get frame
+ status = JxlDecoderProcessInput(jxl_dec);
+ if (status != JXL_DEC_FRAME) {
+ mm_util_error("failed to JxlDecoderProcessInput to get frame (%d)", status);
+ goto Exit;
+ }
+
+ // process to set output buffer
+ status = JxlDecoderProcessInput(jxl_dec);
+ if (status != JXL_DEC_NEED_IMAGE_OUT_BUFFER) {
+ mm_util_error("failed to JxlDecoderProcessInput to set output buffer (%d)", status);
+ goto Exit;
+ }
+
+ status = JxlDecoderSetImageOutBuffer(jxl_dec, jxl_format, pixels, pixels_size);
+ if (status != JXL_DEC_SUCCESS) {
+ mm_util_error("failed to JxlDecoderSetImageOutBuffer(%d)", status);
+ goto Exit;
+ }
+
+ // process to get full image
+ status = JxlDecoderProcessInput(jxl_dec);
+ if (status != JXL_DEC_FULL_IMAGE) {
+ mm_util_error("failed to JxlDecoderProcessInput to get full image (%d)", status);
+ goto Exit;
+ }
+
+ // process to finish decoding
+ status = JxlDecoderProcessInput(jxl_dec);
+ if (status != JXL_DEC_SUCCESS) {
+ mm_util_error("failed to JxlDecoderProcessInput to finish decoding (%d)", status);
+ goto Exit;
+ }
+
+ ret = mm_image_create_image(info.xsize, info.ysize, format, pixels, pixels_size, decoded_image);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ mm_util_error("failed to mm_image_create_image");
+ goto Exit;
+ }
+
+ mm_image_debug_image(decoded_image, "RESULT");
+
+Exit:
+
+ g_free(pixels);
+
+ JxlThreadParallelRunnerDestroy(jxl_thread);
+ JxlDecoderDestroy(jxl_dec);
+
+ mm_util_fleave();
+
+ return __convert_dec_error(status);
+}
+
+static int __mm_util_encode_jpegxl(mm_util_image_h decoded_image, mm_util_enc_opt_t *enc_opt, void **buf, size_t *buf_size)
+{
+ int ret = MM_UTIL_ERROR_NONE;
+ JxlEncoderStatus status = JXL_ENC_ERROR;
+ JxlEncoder *jxl_enc = NULL;
+ void *jxl_thread = NULL;
+ JxlPixelFormat jxl_format;
+ JxlBasicInfo basic_info;
+ JxlColorEncoding color_encoding;
+ JxlEncoderOptions* options = NULL;
+ uint8_t *pixels = NULL;
+ size_t pixels_size = 0;
+ size_t compressed_size = 64;
+ uint8_t *compressed = NULL;
+ uint8_t *next_out = NULL;
+ size_t avail_out = 0;
+
+ mm_util_retvm_if(!buf, MM_UTIL_ERROR_INVALID_PARAMETER, "buf is null");
+ mm_util_retvm_if(!buf_size, MM_UTIL_ERROR_INVALID_PARAMETER, "buf_size is null");
+
+ mm_util_fenter();
+
+ JxlEncoderInitBasicInfo(&basic_info);
+
+ ret = __get_decoded_data(decoded_image, &basic_info.xsize, &basic_info.ysize,
+ &jxl_format, &pixels, &pixels_size);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ mm_util_error("failed to __get_decoded_data");
+ return ret;
+ }
+
+ basic_info.uses_original_profile = (enc_opt && enc_opt->lossless) ? JXL_TRUE : JXL_FALSE;
+ basic_info.num_color_channels = jxl_format.num_channels;
+ if (jxl_format.num_channels == 4)
+ basic_info.alpha_bits = basic_info.bits_per_sample;
+
+ mm_util_info("num_color_channels = %u, alpha_bits = %u",
+ basic_info.num_color_channels, basic_info.alpha_bits);
+
+ jxl_enc = JxlEncoderCreate(NULL);
+ if (!jxl_enc) {
+ mm_util_error("failed to JxlEncoderCreate");
+ goto Exit;
+ }
+
+ jxl_thread = JxlThreadParallelRunnerCreate(NULL, NUM_OF_THREADS);
+ if (!jxl_thread) {
+ mm_util_error("failed to JxlThreadParallelRunnerCreate");
+ goto Exit;
+ }
+
+ status = JxlEncoderSetParallelRunner(jxl_enc, JxlThreadParallelRunner, jxl_thread);
+ if (status != JXL_ENC_SUCCESS) {
+ mm_util_error("failed to JxlDecoderSetParallelRunner(%d)", status);
+ goto Exit;
+ }
+
+ status = JxlEncoderUseContainer(jxl_enc, JXL_TRUE);
+ if (status != JXL_ENC_SUCCESS) {
+ mm_util_error("failed to JxlEncoderUseContainer(%d)", status);
+ goto Exit;
+ }
+
+ status = JxlEncoderSetBasicInfo(jxl_enc, &basic_info);
+ if (status != JXL_ENC_SUCCESS) {
+ mm_util_error("failed to JxlEncoderSetBasicInfo(%d)", status);
+ goto Exit;
+ }
+
+ JxlColorEncodingSetToSRGB(&color_encoding, /*is_gray=*/JXL_FALSE);
+ status = JxlEncoderSetColorEncoding(jxl_enc, &color_encoding);
+ if (status != JXL_ENC_SUCCESS) {
+ mm_util_error("failed to JxlEncoderSetColorEncoding(%d)", status);
+ goto Exit;
+ }
+
+ // set default options
+ // 'options' will be destroyed when 'JxlEncoderDestroy' is called
+ options = JxlEncoderOptionsCreate(jxl_enc, NULL);
+
+ // set lossless into options
+ status = JxlEncoderOptionsSetLossless(options, (enc_opt && enc_opt->lossless) ? JXL_TRUE : JXL_FALSE);
+ if (status != JXL_ENC_SUCCESS) {
+ mm_util_error("failed to JxlEncoderOptionsSetLossless(%d)", status);
+ goto Exit;
+ }
+
+ status = JxlEncoderAddImageFrame(options, &jxl_format, pixels, pixels_size);
+ if (status != JXL_ENC_SUCCESS) {
+ mm_util_error("failed to JxlEncoderAddImageFrame(%d)", status);
+ goto Exit;
+ }
+
+ JxlEncoderCloseInput(jxl_enc);
+
+ compressed = g_malloc0(compressed_size);
+ next_out = compressed;
+ avail_out = compressed_size;
+
+ status = JXL_ENC_NEED_MORE_OUTPUT;
+ while (status == JXL_ENC_NEED_MORE_OUTPUT) {
+ status = JxlEncoderProcessOutput(jxl_enc, &next_out, &avail_out);
+ mm_util_debug("JxlEncoderProcessOutput status(%d)", status);
+ if (status == JXL_ENC_NEED_MORE_OUTPUT) {
+ size_t offset = next_out - compressed;
+ compressed_size *= 2;
+ compressed = g_realloc(compressed, compressed_size);
+ next_out = compressed + offset;
+ avail_out = compressed_size - offset;
+ }
+ }
+
+ mm_util_warn("JxlEncoderProcessOutput was completed");
+
+ if (status != JXL_ENC_SUCCESS) {
+ mm_util_error("failed to JxlEncoderProcessOutput(%d)", status);
+ goto Exit;
+ }
+
+ compressed_size -= (next_out - compressed);
+ *buf = g_memdup2(compressed, next_out - compressed);
+ *buf_size = next_out - compressed;
+
+ mm_util_info("[Success] buffer: %p, size: %zu", *buf, *buf_size);
+
+Exit:
+
+ g_free(compressed);
+ JxlThreadParallelRunnerDestroy(jxl_thread);
+ JxlEncoderDestroy(jxl_enc);
+
+ mm_util_fleave();
+
+ return __convert_enc_error(status);
+}
+
+int mm_util_decode_jxl_from_file(const char *path, mm_util_color_format_e format, mm_util_image_h *decoded_image)
+{
+ int ret = MM_UTIL_ERROR_NONE;
+ void *encoded_buf = NULL;
+ size_t encoded_buf_size = 0;
+
+ mm_util_retvm_if(__get_file_size(path, &encoded_buf_size) != MM_UTIL_ERROR_NONE,
+ MM_UTIL_ERROR_INVALID_PARAMETER, "invalid path %s", path);
+ mm_util_retvm_if(!__read_file(path, &encoded_buf, encoded_buf_size),
+ MM_UTIL_ERROR_INVALID_PARAMETER, "invalid path %s:%zu", path, encoded_buf_size);
+
+ ret =__mm_util_decode_jpegxl(encoded_buf, encoded_buf_size, format, decoded_image);
+
+ g_free(encoded_buf);
+
+ return ret;
+}
+
+int mm_util_decode_jxl_from_buffer(const void *encoded_buf, size_t encoded_buf_size, mm_util_color_format_e format, mm_util_image_h *decoded_image)
+{
+ return __mm_util_decode_jpegxl(encoded_buf, encoded_buf_size, format, decoded_image);
+}
+
+int mm_util_encode_jxl_to_file(mm_util_image_h decoded_image, mm_util_enc_opt_h enc_opt, const char *path)
+{
+ int ret = MM_UTIL_ERROR_NONE;
+ void *encoded_buf = NULL;
+ size_t encoded_buf_size = 0;
+
+ ret = __mm_util_encode_jpegxl(decoded_image, (mm_util_enc_opt_t *)enc_opt, &encoded_buf, &encoded_buf_size);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ mm_util_error("failed to __mm_util_encode_jxl(%d)", ret);
+ return ret;
+ }
+
+ if (!__write_file(path, encoded_buf, encoded_buf_size)) {
+ mm_util_error("failed to __write_file");
+ ret = MM_UTIL_ERROR_INVALID_PARAMETER;
+ }
+
+ g_free(encoded_buf);
+
+ return ret;
+}
+
+int mm_util_encode_jxl_to_buffer(mm_util_image_h decoded_image, mm_util_enc_opt_h enc_opt, void **encoded_buf, size_t *encoded_buf_size)
+{
+ return __mm_util_encode_jpegxl(decoded_image, (mm_util_enc_opt_t *)enc_opt, encoded_buf, encoded_buf_size);
+}
--- /dev/null
+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}
--- /dev/null
+SET(fw_name "mmutil_jxl")
+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()
--- /dev/null
+/*
+* Copyright (c) 2022 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include <mm_util_jxl.h>
+#include <mm_util_jpeg.h>
+
+#define SAFE_FREE(x) { g_free(x); x = NULL; }
+#define SAFE_IMAGE_FREE(x) { if (x != NULL) { mm_image_destroy_image(x); x = NULL; } }
+#define MAX_QUALITY 4
+
+typedef enum {
+ TEST_AUTO,
+ TEST_DECODE_FILE,
+ TEST_DECODE_BUFFER,
+ TEST_ENCODE_FILE,
+ TEST_ENCODE_BUFFER,
+ TEST_NUM,
+} jxl_test_mode_e;
+
+static char *MODE_TO_STR[] = {
+ "AUTO",
+ "DECODE_FILE",
+ "DECODE_BUFFER",
+ "ENCODE_FILE",
+ "ENCODE_BUFFER",
+ "",
+};
+
+/* for arguments */
+static int g_test_mode = 0;
+static char *g_path = NULL;
+static unsigned int g_width = 0;
+static unsigned int g_height = 0;
+static int g_color = MM_UTIL_COLOR_RGB24;
+static bool g_lossless = false;
+
+/* 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_DECODE_FILE] = {
+ [MM_UTIL_COLOR_RGB24] = "/opt/usr/home/owner/media/test_jxl_file_rgb24.jpg",
+ [MM_UTIL_COLOR_RGBA] = "/opt/usr/home/owner/media/test_jxl_file_rgba.jpg",
+ },
+ [TEST_DECODE_BUFFER] = {
+ [MM_UTIL_COLOR_RGB24] = "/opt/usr/home/owner/media/test_jxl_buff_rgb24.jpg",
+ [MM_UTIL_COLOR_RGBA] = "/opt/usr/home/owner/media/test_jxl_buff_rgba.jpg",
+ },
+ [TEST_ENCODE_FILE] = {
+ [MM_UTIL_COLOR_RGB24] = "/opt/usr/home/owner/media/test_jxl_file_rgb24.jxl",
+ [MM_UTIL_COLOR_RGBA] = "/opt/usr/home/owner/media/test_jxl_file_rgba.jxl",
+ },
+ [TEST_ENCODE_BUFFER] = {
+ [MM_UTIL_COLOR_RGB24] = "/opt/usr/home/owner/media/test_jxl_buff_rgb24.jxl",
+ [MM_UTIL_COLOR_RGBA] = "/opt/usr/home/owner/media/test_jxl_buff_rgba.jxl",
+ },
+};
+
+static mm_util_image_h g_decoded_data = NULL;
+static mm_util_enc_opt_h g_enc_opt = 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.) lossless(opt.)\n", argv0);
+ g_print("\t\t2. mode : %d - auto, %d - decode from file, %d - decode from buffer, %d - encode to file, %d - encode to buffer\n",
+ TEST_AUTO, TEST_DECODE_FILE, TEST_DECODE_BUFFER, TEST_ENCODE_FILE, TEST_ENCODE_BUFFER);
+ g_print("\t\t\t e.g. %s %d test.jxl\n", argv0, TEST_AUTO);
+ g_print("\t\t\t e.g. %s %d test.jxl 7\n", argv0, TEST_DECODE_FILE);
+ g_print("\t\t\t e.g. %s %d test.jxl 1920 1280 7\n", argv0, TEST_ENCODE_FILE);
+}
+
+static gboolean __get_arguments(int argc, char *argv[])
+{
+ int width = 0, height = 0;
+ int lossless = 0;
+
+ if (!__get_input_data(argv[1], TEST_AUTO, TEST_NUM - 1, &g_test_mode)) {
+ g_print("\t[JXL_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) {
+ // optional : lossless
+ if (!__get_input_data(argv[3], 0, 1, &lossless))
+ g_print("\t[JXL_testsuite] lossless is default(%d)\n", g_lossless);
+ else
+ g_lossless = (lossless == 1) ? true : false;
+ } else if ((g_test_mode == TEST_DECODE_FILE) || (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[JXL_testsuite] color is default(%d)\n", g_color);
+ } else if (g_test_mode == TEST_ENCODE_FILE || g_test_mode == TEST_ENCODE_BUFFER) {
+ if (argc < 5) {
+ g_print("\t[JPEG_testsuite] not enough args\n");
+ __print_help(argv[0]);
+ return FALSE;
+ }
+
+ if (!__get_input_data(argv[3], 0, INT_MAX, &width)) {
+ g_print("\t[JXL_testsuite] wrong width %s\n", argv[3]);
+ return FALSE;
+ }
+ g_width = (unsigned int)width;
+
+ if (!__get_input_data(argv[4], 0, INT_MAX, &height)) {
+ g_print("\t[JXL_testsuite] wrong height %s\n", argv[4]);
+ return FALSE;
+ }
+ g_height = (unsigned int)height;
+
+ if (!__get_input_data(argv[5], 0, MM_UTIL_COLOR_NUM - 1, &g_color)) {
+ g_print("\t[JXL_testsuite] wrong color %s\n", argv[5]);
+ return FALSE;
+ }
+
+ // optional : lossless
+ if (!__get_input_data(argv[6], 0, 1, &lossless))
+ g_print("\t[JXL_testsuite] lossless is default(%d)\n", g_lossless);
+ else
+ g_lossless = (lossless == 1) ? true : false;
+ } else {
+ g_print("\t[JXL_testsuite] wrong mode for test %s\n", argv[1]);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean __get_decoded_data(void)
+{
+ int ret = 0;
+ GError *error = NULL;
+
+ if (!g_file_get_contents(g_path, &g_readed_data, &g_readed_size, &error)) {
+ g_print("\t[JXL_testsuite] reading file error(%s)\n", (error ? error->message : "none"));
+ if (error)
+ g_error_free(error);
+ return FALSE;
+ }
+ ret = mm_image_create_image(g_width, g_height, g_color,
+ (const unsigned char*)g_readed_data, g_readed_size, &g_decoded_data);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ g_print("\t[JXL_testsuite] mm_image_create_image failed : %d\n", ret);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void __set_enc_opt(bool lossless)
+{
+ int ret = 0;
+
+ if (!g_enc_opt) {
+ ret = mm_util_enc_opt_create(&g_enc_opt);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ g_print("\t[JXL_testsuite] mm_util_enc_opt_create failed : %d\n", ret);
+ return;
+ }
+
+ ret = mm_util_enc_opt_set_codec(g_enc_opt, IMG_CODEC_JPEGXL);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ g_print("\t[JXL_testsuite] mm_util_enc_opt_set_codec failed : %d\n", ret);
+ return;
+ }
+ }
+
+ ret = mm_util_enc_opt_set_lossless(g_enc_opt, lossless);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ g_print("\t[JXL_testsuite] mm_util_enc_opt_set_lossless failed : %d\n", ret);
+ return;
+ }
+ g_print("\t[JXL_testsuite] __set_enc_opt lossless: %s\n", (lossless) ? "lossless" : "lossy");
+}
+
+static gboolean __test_decode(const jxl_test_mode_e mode, mm_util_color_format_e color)
+{
+ int ret = 0;
+ GError *error = NULL;
+
+ SAFE_FREE(g_readed_data);
+ SAFE_IMAGE_FREE(g_decoded_data);
+
+ if ((mode != TEST_DECODE_FILE) && (mode != TEST_DECODE_BUFFER))
+ return TRUE;
+
+ /* test decoding jxl */
+ if (mode == TEST_DECODE_FILE) {
+ ret = mm_util_decode_jxl_from_file(g_path, color, &g_decoded_data);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ g_print("\t[JXL_testsuite] mm_util_decode_jxl_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[JXL_testsuite] reading file error(%s)\n", (error ? error->message : "none"));
+ if (error)
+ g_error_free(error);
+ return FALSE;
+ }
+
+ ret = mm_util_decode_jxl_from_buffer(g_readed_data, g_readed_size, color, &g_decoded_data);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ g_print("\t[JXL_testsuite] mm_util_decode_jxl_from_buffer failed %d\n", ret);
+ return FALSE;
+ }
+ }
+
+ ret = mm_util_jpeg_encode_to_file(g_decoded_data, 100, g_test_filename[mode][color]);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ g_print("\t[JXL_testsuite] mm_util_jpeg_encode_to_file failed %d : %s\n", ret, g_test_filename[mode][color]);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean __test_encode(const jxl_test_mode_e mode, mm_util_color_format_e color)
+{
+ int ret = 0;
+ void *encoded_data = NULL;
+ size_t encoded_size = 0;
+ GError *error = NULL;
+
+ if ((mode != TEST_ENCODE_FILE) && (mode != TEST_ENCODE_BUFFER))
+ return TRUE;
+
+ /* test encoding jxl */
+ if (mode == TEST_ENCODE_FILE) {
+ ret = mm_util_encode_jxl_to_file(g_decoded_data, g_enc_opt, g_test_filename[mode][color]);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ g_print("\t[JXL_testsuite] mm_util_encode_jxl_to_file failed : %d\n", ret);
+ return FALSE;
+ }
+ } else if (mode == TEST_ENCODE_BUFFER) {
+ ret = mm_util_encode_jxl_to_buffer(g_decoded_data, g_enc_opt, &encoded_data, &encoded_size);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ g_print("\t[JXL_testsuite] mm_util_encode_jxl_to_buffer failed : %d\n", ret);
+ SAFE_FREE(encoded_data);
+ return FALSE;
+ }
+ if (FALSE == g_file_set_contents(g_test_filename[mode][color], encoded_data, encoded_size, &error))
+ g_print("\t[JXL_testsuite] g_file_set_contents failed : %s\n", (error ? error->message : "none"));
+
+ SAFE_FREE(encoded_data);
+ }
+
+ return TRUE;
+}
+
+static void __test_auto(void)
+{
+ mm_util_color_format_e color = 0;
+ gboolean result = FALSE;
+
+ /* test for both decoding & encoding */
+ for (color = 0; color < MM_UTIL_COLOR_NUM; color++) {
+ if (g_test_filename[TEST_DECODE_FILE][color]) { // check supported
+ result = __test_decode(TEST_DECODE_FILE, color);
+ g_print("\t[JXL_testsuite] >>>>>>>>>>>>>>>>>>>>>> \'%s(%d)\' TEST %s\n",
+ MODE_TO_STR[TEST_DECODE_FILE], color, (result) ? "SUCCESS" : "FAIL");
+ }
+
+ if (g_test_filename[TEST_ENCODE_FILE][color]) { // check supported
+ result = __test_encode(TEST_ENCODE_FILE, color);
+ g_print("\t[JXL_testsuite] >>>>>>>>>>>>>>>>>>>>>> \'%s(%d)\' TEST %s\n",
+ MODE_TO_STR[TEST_ENCODE_FILE], color, (result) ? "SUCCESS" : "FAIL");
+ }
+
+ if (g_test_filename[TEST_DECODE_BUFFER][color]) { // check supported
+ result = __test_decode(TEST_DECODE_BUFFER, color);
+ g_print("\t[JXL_testsuite] >>>>>>>>>>>>>>>>>>>>>> \'%s(%d)\' TEST %s\n",
+ MODE_TO_STR[TEST_DECODE_BUFFER], color, (result) ? "SUCCESS" : "FAIL");
+ }
+
+ if (g_test_filename[TEST_ENCODE_BUFFER][color]) { // check supported
+ result = __test_encode(TEST_ENCODE_BUFFER, color);
+ g_print("\t[JXL_testsuite] >>>>>>>>>>>>>>>>>>>>>> \'%s(%d)\' TEST %s\n",
+ MODE_TO_STR[TEST_ENCODE_BUFFER], color, (result) ? "SUCCESS" : "FAIL");
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2) {
+ __print_help(argv[0]);
+ return 0;
+ }
+
+ if (!__get_arguments(argc, argv)) {
+ g_print("\t[JXL_testsuite] _get_arguments failed\n");
+ goto out;
+ }
+
+ /* test all functions automatically */
+ switch (g_test_mode) {
+ case TEST_AUTO:
+ __set_enc_opt(g_lossless);
+ __test_auto();
+ break;
+ case TEST_DECODE_FILE:
+ case TEST_DECODE_BUFFER:
+ g_print("\t[JXL_testsuite] >>>>>>>>>>>>>>>>>>>>>> \'%s(%d)\' TEST %s\n", MODE_TO_STR[g_test_mode],
+ g_color, (__test_decode(g_test_mode, g_color)) ? "SUCCESS" : "FAIL");
+ break;
+ case TEST_ENCODE_FILE:
+ case TEST_ENCODE_BUFFER:
+ if (!__get_decoded_data()) {
+ g_print("\t[JXL_testsuite] __get_decoded_data failed\n");
+ goto out;
+ }
+ __set_enc_opt(g_lossless);
+ g_print("\t[JXL_testsuite] >>>>>>>>>>>>>>>>>>>>>> \'%s(%d)\' TEST %s\n", MODE_TO_STR[g_test_mode],
+ g_color, (__test_encode(g_test_mode, g_color)) ? "SUCCESS" : "FAIL");
+ break;
+ default:
+ __print_help(argv[0]);
+ break;
+ }
+
+out:
+ g_free(g_path);
+ SAFE_FREE(g_readed_data);
+ SAFE_IMAGE_FREE(g_decoded_data);
+ mm_util_enc_opt_destroy(g_enc_opt);
+
+ return 0;
+}
goto END;
}
- ret = mm_util_enc_opt_set_webp_lossless(enc_option, lossless);
+ ret = mm_util_enc_opt_set_lossless(enc_option, lossless);
if (ret != MM_UTIL_ERROR_NONE) {
- printf("Fail mm_util_enc_opt_set_webp_lossless [0x%x]\n", ret);
+ printf("Fail mm_util_enc_opt_set_lossless [0x%x]\n", ret);
goto END;
}
goto END;
}
- ret = mm_util_enc_opt_set_webp_lossless(enc_option, lossless);
+ ret = mm_util_enc_opt_set_lossless(enc_option, lossless);
if (ret != MM_UTIL_ERROR_NONE) {
- printf("Fail mm_util_enc_opt_set_webp_lossless [0x%x]\n", ret);
+ printf("Fail mm_util_enc_opt_set_lossless [0x%x]\n", ret);
goto END;
}
Name: libmm-utility
Summary: Multimedia Framework Utility Library
-Version: 0.3.6
+Version: 0.4.0
Release: 0
Group: System/Libraries
License: Apache-2.0
BuildRequires: giflib-devel
BuildRequires: pkgconfig(GraphicsMagick)
BuildRequires: pkgconfig(heif)
+BuildRequires: pkgconfig(libjxl)
+BuildRequires: pkgconfig(libjxl_threads)
%if 0%{?gtests:1}
BuildRequires: pkgconfig(gmock)
%endif