ADD_SUBDIRECTORY(imgp)
ADD_SUBDIRECTORY(jpeg)
ADD_SUBDIRECTORY(magick)
+ADD_SUBDIRECTORY(webp)
IF(UNIX)
BuildRequires: libjpeg-turbo-devel
BuildRequires: pkgconfig(libtzplatform-config)
BuildRequires: pkgconfig(opencv) >= 3.4.1
+BuildRequires: pkgconfig(libwebp)
+BuildRequires: pkgconfig(libwebpmux)
BuildRequires: giflib-devel
BuildRequires: pkgconfig(GraphicsMagick)
%if 0%{?gtests:1}
--- /dev/null
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+SET(fw_name "mmutil_webp")
+
+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
+ ../magick/include
+)
+
+SET(dependents "dlog glib-2.0 libwebp libwebpmux")
+
+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)
+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-webp)
+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) 2020 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_WEBP_H__
+#define __MM_UTIL_WEBP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include "mm_util_type.h"
+
+
+typedef void *mm_util_webp_anim_enc_h;
+
+int mm_util_webp_anim_enc_create(mm_util_webp_anim_enc_h *anim_enc_h);
+int mm_util_webp_anim_enc_set_bgcolor(mm_util_webp_anim_enc_h anim_enc_h, unsigned char alpha, unsigned char red, unsigned char green, unsigned char blue);
+int mm_util_webp_anim_enc_set_loop_count(mm_util_webp_anim_enc_h anim_enc_h, unsigned int loop_count);
+int mm_util_webp_anim_enc_set_lossless(mm_util_webp_anim_enc_h anim_enc_h, bool lossless);
+int mm_util_webp_anim_enc_add_image(mm_util_webp_anim_enc_h anim_enc_h, mm_util_image_h image);
+int mm_util_webp_anim_enc_save_to_file(mm_util_webp_anim_enc_h anim_enc_h, const char *path);
+int mm_util_webp_anim_enc_save_to_buffer(mm_util_webp_anim_enc_h anim_enc_h, void **buf, size_t *buf_size);
+void mm_util_webp_anim_enc_destroy(mm_util_webp_anim_enc_h anim_enc_h);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*__MM_UTIL_WEBP_H__*/
--- /dev/null
+/*
+* Copyright (c) 2020 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 <glib.h>
+#include <webp/encode.h>
+#include <webp/mux.h>
+
+#include "mm_util_webp.h"
+#include "mm_util_private.h"
+
+typedef struct {
+ WebPAnimEncoder *enc;
+ WebPMuxAnimParams anim_params;
+ bool lossless;
+ unsigned int timestamp;
+} mm_util_webp_anim_enc_t;
+
+
+static int __webp_anim_enc_init(mm_util_webp_anim_enc_t *anim_enc, mm_image_info_s *image)
+{
+ WebPAnimEncoderOptions enc_options;
+
+ mm_util_retvm_if(!anim_enc, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid anim_enc");
+ mm_util_retvm_if(!image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image_info");
+
+ mm_util_retvm_if(!WebPAnimEncoderOptionsInit(&enc_options), MM_UTIL_ERROR_INVALID_OPERATION, "Error! WebPAnimEncoderOptionsInit");
+
+ anim_enc->enc = WebPAnimEncoderNew(image->width, image->height, &enc_options);
+ mm_util_retvm_if(!anim_enc->enc, MM_UTIL_ERROR_INVALID_OPERATION, "Error! WebPAnimEncoderNew");
+
+ anim_enc->timestamp = 0;
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+static void __webp_anim_enc_deinit(mm_util_webp_anim_enc_t *anim_enc)
+{
+ if (!anim_enc)
+ return;
+
+ WebPAnimEncoderDelete(anim_enc->enc);
+ anim_enc->enc = NULL;
+}
+
+static int __mm_image_info_to_webp_picture(mm_image_info_s *image, WebPPicture *picture)
+{
+ size_t idx = 0;
+ unsigned char *ptr = NULL, *a = NULL, *r = NULL, *g = NULL, *b = NULL;
+ unsigned int bpp = 4;
+
+ mm_util_retvm_if(!image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image");
+ mm_util_retvm_if(!picture, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid picture");
+
+ picture->width = image->width;
+ picture->height = image->height;
+ // use ARGB because of libwebp recommendation(YUV incurs loss).
+ picture->use_argb = 1;
+
+ mm_util_retvm_if(!WebPPictureAlloc(picture), MM_UTIL_ERROR_INVALID_OPERATION, "Error! WebPPictureAlloc");
+
+ // convert 'unsigned char'(LSB) type to 'uint32_t'(MSB) type
+ // If we did not change the data type, the color of encoded webp was broken.
+ mm_util_debug("image colorspace: %d", image->color);
+
+ // make uint32_t(MSB) 'ARGB' from unsigned char(LSB) 'ARGB/BGRA/RGBA'.
+ ptr = (unsigned char*)(image->data);
+ switch(image->color) {
+ case MM_UTIL_COLOR_ARGB:
+ a = ptr;
+ r = ptr + 1;
+ g = ptr + 2;
+ b = ptr + 3;
+ bpp = 4;
+ break;
+ case MM_UTIL_COLOR_BGRA:
+ a = ptr + 3;
+ r = ptr + 2;
+ g = ptr + 1;
+ b = ptr;
+ bpp = 4;
+ break;
+ case MM_UTIL_COLOR_RGBA:
+ a = ptr + 3;
+ r = ptr;
+ g = ptr + 1;
+ b = ptr + 2;
+ bpp = 4;
+ break;
+ default:
+ mm_util_error("not supported colorspace %d", image->color);
+ WebPPictureFree(picture);
+ return MM_UTIL_ERROR_NOT_SUPPORTED_FORMAT;
+ }
+
+ while(idx < (size_t)(picture->argb_stride * picture->height)) {
+ picture->argb[idx++] = ((*a << 24) | (*r << 16) | (*g << 8) | (*b));
+
+ a += bpp;
+ r += bpp;
+ g += bpp;
+ b += bpp;
+ }
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+static int __mm_util_webp_anim_enc_save(mm_util_webp_anim_enc_t *anim_enc, WebPData *webp_data)
+{
+ WebPMux *mux = NULL;
+ WebPMuxError err = WEBP_MUX_OK;
+
+ mm_util_retvm_if(!anim_enc, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid anim_enc");
+ mm_util_retvm_if(!webp_data, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid webp_data");
+
+ mm_util_fenter();
+
+ // add NULL to end animation
+ if (!WebPAnimEncoderAdd(anim_enc->enc, NULL, anim_enc->timestamp, NULL)) {
+ mm_util_error("Error! WebPAnimEncoderAdd(%s)", WebPAnimEncoderGetError(anim_enc->enc));
+ return MM_UTIL_ERROR_INVALID_OPERATION;
+ }
+ if (!WebPAnimEncoderAssemble(anim_enc->enc, webp_data)) {
+ mm_util_error("Error! WebPAnimEncoderAssemble(%s)", WebPAnimEncoderGetError(anim_enc->enc));
+ return MM_UTIL_ERROR_INVALID_OPERATION;
+ }
+
+ // add animation container into webp
+ mux = WebPMuxCreate(webp_data, 1);
+ if (!mux) {
+ mm_util_error("Error! WebPMuxCreate");
+ return MM_UTIL_ERROR_INVALID_OPERATION;
+ }
+
+ err = WebPMuxSetAnimationParams(mux, &anim_enc->anim_params);
+ if (err != WEBP_MUX_OK) {
+ mm_util_error("Error! WebPMuxSetAnimationParams(%d)", err);
+ WebPMuxDelete(mux);
+ return MM_UTIL_ERROR_INVALID_OPERATION;
+ }
+
+ err = WebPMuxAssemble(mux, webp_data);
+ if (err != WEBP_MUX_OK) {
+ mm_util_error("Error! WebPMuxAssemble(%d)", err);
+ WebPMuxDelete(mux);
+ return MM_UTIL_ERROR_INVALID_OPERATION;
+ }
+
+ WebPMuxDelete(mux);
+
+ mm_util_fleave();
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_webp_anim_enc_create(mm_util_webp_anim_enc_h *anim_enc_h)
+{
+ mm_util_webp_anim_enc_t *anim_enc = NULL;
+
+ mm_util_retvm_if(!anim_enc_h, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid anim_enc_h");
+
+ anim_enc = g_new0(mm_util_webp_anim_enc_t, 1);
+ anim_enc->anim_params.bgcolor = 0xFFFFFFFF; // white
+ anim_enc->anim_params.loop_count = 0; // infinite
+ anim_enc->lossless = false;
+
+ *anim_enc_h = anim_enc;
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_webp_anim_enc_set_bgcolor(mm_util_webp_anim_enc_h anim_enc_h, unsigned char alpha, unsigned char red, unsigned char green, unsigned char blue)
+{
+ mm_util_webp_anim_enc_t *anim_enc = (mm_util_webp_anim_enc_t *)anim_enc_h;
+
+ mm_util_retvm_if(!anim_enc_h, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid anim_enc_h");
+
+ // background color of the animation, default is white
+ anim_enc->anim_params.bgcolor = (uint32_t)((alpha << 24) | (red << 16) | (green << 8) | blue);
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_webp_anim_enc_set_loop_count(mm_util_webp_anim_enc_h anim_enc_h, unsigned int loop_count)
+{
+ mm_util_webp_anim_enc_t *anim_enc = (mm_util_webp_anim_enc_t *)anim_enc_h;
+
+ mm_util_retvm_if(!anim_enc_h, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid anim_enc_h");
+
+ // number of times to repeat the animation, default is 0[infinite]
+ anim_enc->anim_params.loop_count = (int)loop_count;
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_webp_anim_enc_set_lossless(mm_util_webp_anim_enc_h anim_enc_h, bool lossless)
+{
+ mm_util_webp_anim_enc_t *anim_enc = (mm_util_webp_anim_enc_t *)anim_enc_h;
+
+ mm_util_retvm_if(!anim_enc_h, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid anim_enc_h");
+
+ // lossless, default is false due to performance
+ anim_enc->lossless = lossless;
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+int mm_util_webp_anim_enc_add_image(mm_util_webp_anim_enc_h anim_enc_h, mm_util_image_h image)
+{
+ int ret = MM_UTIL_ERROR_NONE;
+ mm_util_webp_anim_enc_t *anim_enc = (mm_util_webp_anim_enc_t *)anim_enc_h;
+ mm_image_info_s *frame = (mm_image_info_s *)image;
+ WebPPicture picture;
+ WebPConfig config;
+
+ mm_util_fenter();
+
+ mm_util_retvm_if(!anim_enc_h, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid anim_enc_h");
+ mm_util_retvm_if(!image, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid image");
+
+ mm_util_retvm_if(!WebPPictureInit(&picture), MM_UTIL_ERROR_INVALID_OPERATION, "Error! WebPPictureInit");
+ mm_util_retvm_if(!WebPConfigInit(&config), MM_UTIL_ERROR_INVALID_OPERATION, "Error! WebPConfigInit");
+
+ config.lossless = anim_enc->lossless;
+
+ ret = __mm_image_info_to_webp_picture(frame, &picture);
+ mm_util_retvm_if(ret != MM_UTIL_ERROR_NONE, ret, "Error! __mm_image_info_to_webp_picture(%d)", ret);
+
+ // if first frame, create animation container of webp
+ if (!anim_enc->enc) {
+ ret = __webp_anim_enc_init(anim_enc, frame);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ mm_util_error("Error! __webp_anim_enc_init(%d)", ret);
+ WebPPictureFree(&picture);
+ return ret;
+ }
+ }
+
+ // add picture into animation container
+ if (!WebPAnimEncoderAdd(anim_enc->enc, &picture, (int)anim_enc->timestamp, &config)) {
+ mm_util_error("Error! WebPAnimEncoderAdd(%s)", WebPAnimEncoderGetError(anim_enc->enc));
+ __webp_anim_enc_deinit(anim_enc);
+ ret = MM_UTIL_ERROR_INVALID_OPERATION;
+ } else {
+ // convert the delay between frames to timestamp of each frame
+ anim_enc->timestamp += frame->delay_time;
+ }
+
+ WebPPictureFree(&picture);
+
+ mm_util_fleave();
+
+ return ret;
+}
+
+int mm_util_webp_anim_enc_save_to_file(mm_util_webp_anim_enc_h anim_enc_h, const char *path)
+{
+ int ret = MM_UTIL_ERROR_NONE;
+ mm_util_webp_anim_enc_t *anim_enc = (mm_util_webp_anim_enc_t *)anim_enc_h;
+ WebPData webp_data;
+ GError *g_error = NULL;
+
+ mm_util_retvm_if(!anim_enc_h, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid anim_enc_h");
+
+ WebPDataInit(&webp_data);
+
+ ret = __mm_util_webp_anim_enc_save(anim_enc, &webp_data);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ mm_util_error("Error! __mm_util_webp_anim_enc_save(%d)", ret);
+ goto END;
+ }
+
+ if (!g_file_set_contents(path, (gchar *)webp_data.bytes, (gssize)webp_data.size, &g_error))
+ mm_util_error("Error! g_file_set_contents(%s)", (g_error ? g_error->message : "none"));
+
+ if (g_error)
+ g_error_free(g_error);
+END:
+
+ WebPDataClear(&webp_data);
+ __webp_anim_enc_deinit(anim_enc);
+
+ return ret;
+}
+
+int mm_util_webp_anim_enc_save_to_buffer(mm_util_webp_anim_enc_h anim_enc_h, void **buf, size_t *buf_size)
+{
+ int ret = MM_UTIL_ERROR_NONE;
+ mm_util_webp_anim_enc_t *anim_enc = (mm_util_webp_anim_enc_t *)anim_enc_h;
+ WebPData webp_data;
+
+ mm_util_retvm_if(!anim_enc_h, MM_UTIL_ERROR_INVALID_PARAMETER, "invalid anim_enc_h");
+
+ WebPDataInit(&webp_data);
+
+ ret = __mm_util_webp_anim_enc_save(anim_enc, &webp_data);
+ if (ret == MM_UTIL_ERROR_NONE) {
+ *buf = g_memdup(webp_data.bytes, webp_data.size);
+ *buf_size = webp_data.size;
+ } else {
+ mm_util_error("Error! __mm_util_webp_anim_enc_save(%d)", ret);
+ }
+
+ WebPDataClear(&webp_data);
+ __webp_anim_enc_deinit(anim_enc);
+
+ return MM_UTIL_ERROR_NONE;
+}
+
+void mm_util_webp_anim_enc_destroy(mm_util_webp_anim_enc_h anim_enc_h)
+{
+ if (!anim_enc_h)
+ return;
+
+ __webp_anim_enc_deinit((mm_util_webp_anim_enc_t *)anim_enc_h);
+ g_free(anim_enc_h);
+}
--- /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_webp")
+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")
+
+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_magick)
+ENDFOREACH()
--- /dev/null
+/*
+* Copyright (c) 2020 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 <errno.h>
+#include <glib.h>
+#include <limits.h>
+
+#include <mm_util_image.h>
+#include <mm_util_magick.h>
+#include <mm_util_webp.h>
+#include <tzplatform_config.h>
+
+#define TEST_STRING_VALID(str) ((str != NULL && strlen(str) > 0) ? TRUE : FALSE)
+
+#define ENCODE_FILE_PATH tzplatform_mkpath(TZ_USER_CONTENT, "webp_test_enc_file.webp")
+#define ENCODE_MEM_PATH tzplatform_mkpath(TZ_USER_CONTENT, "webp_test_enc_mem.webp")
+
+static char *g_path = NULL;
+
+/* for reading files */
+static GQueue *g_queue_files = NULL;
+static GQueue *g_queue_images = NULL;
+
+static const mm_util_color_format_e g_color = MM_UTIL_COLOR_ARGB;
+static const unsigned int g_delay_time = 500; // 500ms
+static const int g_loop_count = 0; // if loop_count is 0, it is infinite loop
+static uint8_t g_bgcolor[] = { 0xFF, 0x00, 0x00, 0x00 }; // black
+
+static void __decode_func(gpointer data, gpointer user_data)
+{
+ int ret = MM_UTIL_ERROR_NONE;
+ char *path = (char *)data;
+ mm_util_image_h image = NULL;
+
+ if (!TEST_STRING_VALID(path)) {
+ g_print("invalid path %s\n", path);
+ return;
+ }
+
+ ret = mm_util_decode_image_from_file(path, g_color, &image);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ g_print("mm_util_decode_image_from_file failed %d\n", ret);
+ return;
+ }
+
+ ret = mm_image_set_delay_time(image, g_delay_time);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ g_print("mm_image_set_delay_time failed %d\n", ret);
+ return;
+ }
+
+ g_queue_push_tail(g_queue_images, image);
+}
+
+static gboolean __decode_files_in_queue()
+{
+ if (g_queue_images)
+ g_queue_free_full(g_queue_images, mm_image_destroy_image);
+
+ g_queue_images = g_queue_new();
+
+ g_queue_foreach(g_queue_files, __decode_func, NULL);
+
+ if (g_queue_images->length == 0) {
+ g_print("No valid image\n");
+ return FALSE;
+ }
+
+ g_print("%u valid image have been decoded.\n", g_queue_images->length);
+
+ return TRUE;
+}
+
+static int __sort_compare(gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ const char *_a = (const char *)a;
+ const char *_b = (const char *)b;
+ if (strlen(_a) < strlen(_b))
+ return -1;
+
+ if (strlen(_a) > strlen(_b))
+ return 1;
+
+ return g_ascii_strcasecmp(_a, _b);
+}
+
+static gboolean __set_input_dir(const char *path)
+{
+ GDir *dir = NULL;
+ const gchar *filename = NULL;
+ GError *g_error = NULL;
+
+ dir = g_dir_open(path, 0, &g_error);
+ if (!dir) {
+ g_print("invalid dir %s (%s)\n", path, g_error ? g_error->message : "none");
+ g_error_free(g_error);
+ return FALSE;
+ }
+
+ if (g_queue_files)
+ g_queue_free_full(g_queue_files, g_free);
+
+ g_queue_files = g_queue_new();
+
+ /* push files of dir into queue */
+ while ((filename = g_dir_read_name(dir)) != NULL)
+ g_queue_insert_sorted(g_queue_files, g_strdup_printf("%s/%s", path, filename), __sort_compare, NULL);
+
+ g_dir_close(dir);
+
+ if (g_queue_files->length == 0) {
+ g_print("\tNo test file in directory(%s)!\n", path);
+ return FALSE;
+ }
+
+ /* decode files of dir */
+ if (!__decode_files_in_queue()) {
+ g_print("Fail to decode files from dir! %s\n", path);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void __print_help(const char *argv0)
+{
+ fprintf(stderr, "\t[usage] Encode animation webp with images\n");
+ fprintf(stderr, "\t\t1. encode : %s directory(has numeric named files)\n", argv0);
+ fprintf(stderr, "\t\t2. support jpeg/png/gif/bmp/webp files to animation webp\n");
+}
+
+static gboolean __get_arguments(int argc, char *argv[])
+{
+ g_path = g_strdup(argv[1]);
+
+ if (!TEST_STRING_VALID(g_path)) {
+ fprintf(stderr, "\t[WEBP_testsuite] invalid path %s\n", argv[1]);
+ return FALSE;
+ }
+
+ if (!__set_input_dir(g_path)) {
+ fprintf(stderr, "\t[WEBP_testsuite] __set_input_dir failed\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void __add_image(gpointer data, gpointer user_data)
+{
+ int ret = 0;
+
+ ret = mm_util_webp_anim_enc_add_image((mm_util_webp_anim_enc_h)user_data, (mm_util_image_h)data);
+ if (ret != MM_UTIL_ERROR_NONE)
+ fprintf(stderr, "\t[WEBP_testsuite] mm_util_webp_anim_enc_add_image failed : %d\n", ret);
+}
+
+static gboolean __test_encode_to_file()
+{
+ int ret = 0;
+ mm_util_webp_anim_enc_h anim_enc = NULL;
+
+ ret = mm_util_webp_anim_enc_create(&anim_enc);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ fprintf(stderr, "\t[WEBP_testsuite] mm_util_webp_anim_enc_create failed : %d\n", ret);
+ return FALSE;
+ }
+
+ ret = mm_util_webp_anim_enc_set_bgcolor(anim_enc, g_bgcolor[0], g_bgcolor[1], g_bgcolor[2], g_bgcolor[3]);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ fprintf(stderr, "\t[WEBP_testsuite] mm_util_webp_anim_enc_set_bgcolor failed : %d\n", ret);
+ goto END;
+ }
+
+ ret = mm_util_webp_anim_enc_set_loop_count(anim_enc, g_loop_count);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ fprintf(stderr, "\t[WEBP_testsuite] mm_util_webp_anim_enc_set_loop_count failed : %d\n", ret);
+ goto END;
+ }
+
+ g_queue_foreach(g_queue_images, __add_image, anim_enc);
+
+ ret = mm_util_webp_anim_enc_save_to_file(anim_enc, ENCODE_FILE_PATH);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ fprintf(stderr, "\t[WEBP_testsuite] mm_util_encode_webp_to_file failed : %d\n", ret);
+ goto END;
+ }
+
+END:
+ mm_util_webp_anim_enc_destroy(anim_enc);
+
+ if (ret != MM_UTIL_ERROR_NONE)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean __test_encode_to_buffer()
+{
+ int ret = 0;
+ mm_util_webp_anim_enc_h anim_enc = NULL;
+ /* for encoding webp to memory */
+ void *encoded_data = NULL;
+ size_t encoded_size = 0;
+ GError *g_error = NULL;
+
+ ret = mm_util_webp_anim_enc_create(&anim_enc);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ fprintf(stderr, "\t[WEBP_testsuite] mm_util_webp_anim_enc_create failed : %d\n", ret);
+ return FALSE;
+ }
+
+ ret = mm_util_webp_anim_enc_set_bgcolor(anim_enc, g_bgcolor[0], g_bgcolor[1], g_bgcolor[2], g_bgcolor[3]);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ fprintf(stderr, "\t[WEBP_testsuite] mm_util_webp_anim_enc_set_bgcolor failed : %d\n", ret);
+ goto END;
+ }
+
+ ret = mm_util_webp_anim_enc_set_loop_count(anim_enc, g_loop_count);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ fprintf(stderr, "\t[WEBP_testsuite] mm_util_webp_anim_enc_set_loop_count failed : %d\n", ret);
+ goto END;
+ }
+
+ g_queue_foreach(g_queue_images, __add_image, anim_enc);
+
+ ret = mm_util_webp_anim_enc_save_to_buffer(anim_enc, &encoded_data, &encoded_size);
+ if (ret != MM_UTIL_ERROR_NONE) {
+ fprintf(stderr, "\t[WEBP_testsuite] mm_util_webp_anim_enc_save_to_buffer failed : %d\n", ret);
+ goto END;
+ }
+ if (!g_file_set_contents(ENCODE_MEM_PATH, (gchar *)encoded_data, (gssize)encoded_size, &g_error)) {
+ fprintf(stderr, "\t[WEBP_testsuite] g_file_set_contents failed : %s\n", ENCODE_MEM_PATH);
+ if (g_error)
+ g_error_free(g_error);
+ goto END;
+ }
+
+END:
+ mm_util_webp_anim_enc_destroy(anim_enc);
+
+ g_free(encoded_data);
+
+ if (ret != MM_UTIL_ERROR_NONE)
+ return FALSE;
+
+ return TRUE;
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2) {
+ __print_help(argv[0]);
+ return 0;
+ }
+
+ if (FALSE == __get_arguments(argc, argv)) {
+ fprintf(stderr, "\t[WEBP_testsuite] _get_arguments failed\n");
+ goto out;
+ }
+
+ /* test encoding animation webp to file */
+ if (FALSE == __test_encode_to_file()) {
+ fprintf(stderr, "\t[WEBP_testsuite] __test_encode_to_file failed\n");
+ goto out;
+ }
+
+ /* test encoding animation webp to buffer */
+ if (FALSE == __test_encode_to_buffer()) {
+ fprintf(stderr, "\t[WEBP_testsuite] __test_encode_to_buffer failed\n");
+ goto out;
+ }
+
+out:
+ g_free(g_path);
+ g_queue_free_full(g_queue_images, mm_image_destroy_image);
+ g_queue_free_full(g_queue_files, g_free);
+
+ return 0;
+}
+