From: Jeongmo Yang Date: Mon, 23 Sep 2024 10:12:37 +0000 (+0900) Subject: [HALACR-16] Add HAL interface for Codec X-Git-Tag: accepted/tizen/unified/20250121.155638^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fa9456edd6e39188ce7d75083612e8f9b18f5455;p=platform%2Fhal%2Fapi%2Fcodec.git [HALACR-16] Add HAL interface for Codec - Add "doc" directory for documentation. - Replace HAL test for new codec HAL interface. [Version] 1.0.0 [Issue Type] New feature Change-Id: I6ab283d173a7ec7008a3fa70ebc3c01a7c4698a6 Signed-off-by: Jeongmo Yang --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 95b7275..38e87ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,51 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +PROJECT(hal-api-codec) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(EXEC_PREFIX "${CMAKE_INSTALL_PREFIX}/bin") +SET(INCLUDEDIR "${CMAKE_INSTALL_PREFIX}/include") +SET(LIBDIR ${CMAKE_LIBDIR_PREFIX}) +SET(VERSION_MAJOR 1) +SET(VERSION "${VERSION_MAJOR}.0.0") + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) + +SET(PKG_MODULES + dlog + glib-2.0 + hal-api-common +) + +INCLUDE(FindPkgConfig) +pkg_check_modules(pkgs REQUIRED ${PKG_MODULES}) + +FOREACH(flag ${pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -g -fno-omit-frame-pointer -finstrument-functions") +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fPIC -Wall -Wextra -Wno-array-bounds -Wno-empty-body -Wno-ignored-qualifiers -Wno-unused-parameter -Wshadow -Wwrite-strings -Wswitch-default -Wno-unused-but-set-parameter -Wno-unused-but-set-variable") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -lrt") + +SET(SRCS src/hal-api-codec.c) + +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} -Wl,--as-needed -Wl,--rpath=${LIBDIR}/hal) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION}) + +CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION ${LIBDIR}/hal) + +INSTALL(DIRECTORY include/ DESTINATION include/hal + FILES_MATCHING + PATTERN "include/*.h") + +INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.pc DESTINATION ${LIBDIR}/pkgconfig) + +IF(ENABLE_TESTS) ADD_SUBDIRECTORY(tests) +ENDIF(ENABLE_TESTS) diff --git a/doc/hal_codec_doc.h b/doc/hal_codec_doc.h new file mode 100644 index 0000000..d343df2 --- /dev/null +++ b/doc/hal_codec_doc.h @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2025 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 __TIZEN_HAL_CODEC_DOC_H__ +#define __TIZEN_HAL_CODEC_DOC_H__ + + +/** + * @file hal_codec_doc.h + * @brief This file contains high level documentation of the HAL Codec. + */ + +/** + * @defgroup HALAPI_HAL_CODEC_MODULE Codec + * @brief The @ref HALAPI_HAL_CODEC_MODULE provides functions for codec devices. + * + * @section HALAPI_HAL_CODEC_MODULE_HEADER Required Header + * \#include + * + * @section HALAPI_HAL_CODEC_MODULE_OVERVIEW Overview + * The codec devices have various specifications and backend interfaces, so it's hard to control them using single code. + * The codec HAL provides common abstraction interfaces to control codec devices which are different. + * + * Key functionalities include: + * - Configure and release codec devices + * - Decode or encode image + * + * @subsection HALAPI_HAL_CODEC_MODULE_STATE_DIAGRAM State Diagram + * @image html hal_codec_state_diagram.png + * + * @subsection HALAPI_HAL_CODEC_MODULE_STATE_TRANSITIONS State Transitions + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
FUNCTIONPRE-STATEPOST-STATESYNC TYPE
hal_codec_init() N/A INITIALIZED SYNC
hal_codec_deinit() INITIALIZED N/A SYNC
hal_codec_configure() INITIALIZED CONFIGURED SYNC
hal_codec_release() CONFIGURED INITIALIZED SYNC
hal_codec_start() CONFIGURED STARTED SYNC
hal_codec_stop() STARTED CONFIGURED SYNC
+ * + * For more information on the Codec features and the macros, see HAL Codec programming guides and tutorials. + */ + +#endif /* __TIZEN_HAL_CODEC_DOC_H__ */ diff --git a/doc/images/hal_codec_state_diagram.png b/doc/images/hal_codec_state_diagram.png new file mode 100644 index 0000000..419ec78 Binary files /dev/null and b/doc/images/hal_codec_state_diagram.png differ diff --git a/hal-api-codec.manifest b/hal-api-codec.manifest new file mode 100644 index 0000000..81ace0c --- /dev/null +++ b/hal-api-codec.manifest @@ -0,0 +1,6 @@ + + + + + + diff --git a/hal-api-codec.pc.in b/hal-api-codec.pc.in new file mode 100644 index 0000000..484072c --- /dev/null +++ b/hal-api-codec.pc.in @@ -0,0 +1,13 @@ +# Package Information for pkg-config +prefix=@PREFIX@ +exec_prefix=@EXEC_PREFIX@/hal +libdir=@LIBDIR@/hal +includedir=@INCLUDEDIR@/hal + +Name: @PROJECT_NAME@ +Description: @PROJECT_NAME@ interface +Version: @VERSION@ +Requires: +Libs: -L${libdir} -l@PROJECT_NAME@ +Cflags: -I${includedir} +CXXflags: -I${includedir} diff --git a/include/hal-codec-interface-1.h b/include/hal-codec-interface-1.h new file mode 100644 index 0000000..a07adc0 --- /dev/null +++ b/include/hal-codec-interface-1.h @@ -0,0 +1,324 @@ +/* + * HAL (Hardware Abstract Layer) interface API for Codec + * + * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * + * 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 __HAL_CODEC_INTERFACE_1__ +#define __HAL_CODEC_INTERFACE_1__ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file hal-codec-interface-1.h + * @brief This file contains the Tizen codec HAL interface API, related structures and enumerations. + * @since HAL_MODULE_CODEC 1.0 + */ + +/** + * @addtogroup HALAPI_HAL_CODEC_MODULE + * @{ + */ + +/** + * @brief The maximum number of planes in buffer + * @since HAL_MODULE_CODEC 1.0 + */ +#define HAL_CODEC_BUFFER_PLANE_MAX 4 + +/** + * @brief Enumeration for the codec HAL error. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef enum { + HAL_CODEC_ERROR_NONE = (int32_t)0x00000000, /**< Error none */ + HAL_CODEC_ERROR_NOT_SUPPORTED = (int32_t)0x80003001, /**< Not supported */ + HAL_CODEC_ERROR_PERMISSION_DENIED = (int32_t)0x80003002, /**< Permission denied */ + HAL_CODEC_ERROR_INVALID_PARAMETER = (int32_t)0x80003003, /**< Invalid parameter */ + HAL_CODEC_ERROR_INVALID_STATE = (int32_t)0x80003004, /**< Invalid state */ + HAL_CODEC_ERROR_OUT_OF_MEMORY = (int32_t)0x80003005, /**< Out of memory */ + HAL_CODEC_ERROR_DEVICE_OPEN = (int32_t)0x80003006, /**< Device open */ + HAL_CODEC_ERROR_DEVICE_NOT_FOUND = (int32_t)0x80003007, /**< Device not found */ + HAL_CODEC_ERROR_DEVICE_UNAVAILABLE = (int32_t)0x80003008, /**< Device unavailable */ + HAL_CODEC_ERROR_DEVICE_READ = (int32_t)0x80003009, /**< Device read */ + HAL_CODEC_ERROR_DEVICE_WRITE = (int32_t)0x8000300a, /**< Device write */ + HAL_CODEC_ERROR_DEVICE_BUSY = (int32_t)0x8000300b, /**< Device busy */ + HAL_CODEC_ERROR_DEVICE_TIME_OUT = (int32_t)0x8000300c, /**< Device time out */ + + HAL_CODEC_ERROR_INTERNAL = (int32_t)0x80003ffd, /**< Internal */ + HAL_CODEC_ERROR_NOT_IMPLEMENTED = (int32_t)0x80003ffe, /**< Not implemented */ + HAL_CODEC_ERROR_UNKNOWN = (int32_t)0x80003fff /**< Unknown */ +} hal_codec_error_e; + +/** + * @brief Enumeration for the codec HAL type. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef enum { + HAL_CODEC_TYPE_DECODER = 0, /**< Decoder type */ + HAL_CODEC_TYPE_ENCODER /**< Encoder type */ +} hal_codec_type_e; + +/** + * @brief Enumeration for the codec HAL state. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef enum { + HAL_CODEC_STATE_INITIALIZED = 0, /**< Initialized state */ + HAL_CODEC_STATE_CONFIGURED, /**< Configured state */ + HAL_CODEC_STATE_STARTED /**< Started state */ +} hal_codec_state_e; + +/** + * @brief Enumeration for codec HAL format type. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef enum { + HAL_CODEC_FORMAT_TYPE_ENCODED = 0x10000000, /**< Encoded format type */ + HAL_CODEC_FORMAT_TYPE_RAW = 0x20000000 /**< RAW format type */ +} hal_codec_format_type_e; + +/** + * @brief Enumeration for the codec HAL format. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef enum { + /* ENCODED */ + HAL_CODEC_FORMAT_H264 = (HAL_CODEC_FORMAT_TYPE_ENCODED | 0x1002), /**< Encoded - H.264 */ + HAL_CODEC_FORMAT_H265 = (HAL_CODEC_FORMAT_TYPE_ENCODED | 0x1003), /**< Encoded - H.265 */ + HAL_CODEC_FORMAT_H266 = (HAL_CODEC_FORMAT_TYPE_ENCODED | 0x1004), /**< Encoded - H.266 */ + HAL_CODEC_FORMAT_VP8 = (HAL_CODEC_FORMAT_TYPE_ENCODED | 0x2001), /**< Encoded - VP8 */ + HAL_CODEC_FORMAT_VP9 = (HAL_CODEC_FORMAT_TYPE_ENCODED | 0x2002), /**< Encoded - VP9 */ + HAL_CODEC_FORMAT_AV1 = (HAL_CODEC_FORMAT_TYPE_ENCODED | 0x3001), /**< Encoded - AV1 */ + + /* YUV */ + HAL_CODEC_FORMAT_NV12 = (HAL_CODEC_FORMAT_TYPE_RAW | 0x1001), /**< RAW - NV12 */ + HAL_CODEC_FORMAT_NV12T = (HAL_CODEC_FORMAT_TYPE_RAW | 0x1002), /**< RAW - NV12 Tiled */ + HAL_CODEC_FORMAT_NV21 = (HAL_CODEC_FORMAT_TYPE_RAW | 0x1003), /**< RAW - NV21 */ + HAL_CODEC_FORMAT_I420 = (HAL_CODEC_FORMAT_TYPE_RAW | 0x1004), /**< RAW - I420(YU12) */ + HAL_CODEC_FORMAT_YV12 = (HAL_CODEC_FORMAT_TYPE_RAW | 0x1005), /**< RAW - YV12 */ + HAL_CODEC_FORMAT_YUYV = (HAL_CODEC_FORMAT_TYPE_RAW | 0x1006), /**< RAW - YUYV */ + HAL_CODEC_FORMAT_UYVY = (HAL_CODEC_FORMAT_TYPE_RAW | 0x1007), /**< RAW - UYVY */ + + /* RGB */ + HAL_CODEC_FORMAT_BGRA8888 = (HAL_CODEC_FORMAT_TYPE_RAW | 0x2001), /**< RAW - BGRA8888 */ + HAL_CODEC_FORMAT_ARGB8888 = (HAL_CODEC_FORMAT_TYPE_RAW | 0x2002) /**< RAW - ARGB8888 */ +} hal_codec_format_e; + +/** + * @brief Enumeration for the buffer flag. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef enum { + HAL_CODEC_BUFFER_FLAG_NONE = 0x0000, /**< None flag */ + HAL_CODEC_BUFFER_FLAG_CODECCONFIG = 0x0001, /**< Codec config flag */ + HAL_CODEC_BUFFER_FLAG_SYNCFRAME = 0x0002, /**< Sync frame flag */ + HAL_CODEC_BUFFER_FLAG_EOS = 0x0004, /**< EOS(End of stream) flag */ + HAL_CODEC_BUFFER_FLAG_ROTATED = 0x0008, /**< Rotated flag */ + HAL_CODEC_BUFFER_FLAG_SECURE = 0xf000 /**< Secure flag */ +} hal_codec_buffer_flag_e; + +/** + * @brief Enumeration for the buffer rotation. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef enum { + HAL_CODEC_ROTATION_NONE = 0, /**< None rotation */ + HAL_CODEC_ROTATION_90, /**< 90 degree rotation */ + HAL_CODEC_ROTATION_180, /**< 180 degree rotation */ + HAL_CODEC_ROTATION_270 /**< 270 degree rotation */ +} hal_codec_rotation_e; + +/** + * @brief The structure type of the resolution. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef struct { + int width; /**< The width of resolution */ + int height; /**< The height of resolution */ +} hal_codec_resolution_s; + +/** + * @brief The structure type of the buffer plane. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef struct { + unsigned char *data; /**< The data pointer of plane, it could be NULL when it's secure buffer */ + uint32_t stride; /**< The stride of plane */ + uint32_t size; /**< The size of plane */ + uint32_t bytesused; /**< The actual data size of plane */ +} hal_codec_plane_s; + +/** + * @brief The structure type of the buffer planes. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef struct { + uint32_t num_planes; /**< The number of planes */ + hal_codec_plane_s plane[HAL_CODEC_BUFFER_PLANE_MAX]; /**< The array of planes */ +} hal_codec_planes_s; + +/** + * @brief The structure type of the buffer memory. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef struct { + uint32_t num_fd; /**< The number of fd */ + int fd[HAL_CODEC_BUFFER_PLANE_MAX]; /**< The fd */ +} hal_codec_memory_s; + +/** + * @brief The structure type of the buffer meta. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef struct { + hal_codec_format_e format; /**< The format */ + hal_codec_resolution_s resolution; /**< The resolution of frame */ + hal_codec_rotation_e rotation; /**< The rotation of frame */ + uint64_t timestamp; /**< The timestamp */ + uint32_t duration; /**< The duration */ + uint32_t flags; /**< The flags */ +} hal_codec_meta_s; + +/** + * @brief The structure type of the buffer. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef struct { + int index; /**< The index of buffer */ + uint32_t size; /**< The size of buffer */ + hal_codec_planes_s planes; /**< The planes of buffer - logical plane data */ + hal_codec_memory_s memory; /**< The memory of buffer for zero copy */ + hal_codec_meta_s meta; /**< The meta data of buffer */ +} hal_codec_buffer_s; + + +/** + * @brief Enumeration for the codec HAL command. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef enum { + HAL_CODEC_COMMAND_BASE = (uint64_t)0x0000000000000001, /**< Base of command */ + HAL_CODEC_COMMAND_BITRATE = (uint64_t)0x0000000000000002, /**< Bitrate */ + HAL_CODEC_COMMAND_REQUEST_CODECDATA = (uint64_t)0x0000000000000004, /**< Request codec data */ + HAL_CODEC_COMMAND_REQUEST_SYNCFRAME = (uint64_t)0x0000000000000008, /**< Request syncframe */ + HAL_CODEC_COMMAND_CUSTOM = (uint64_t)0xf000000000000000 /**< Custom */ +} hal_codec_command_e; + +/** + * @brief The structure type of the codec HAL custom command. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef struct { + const char *name; /**< The name of custom command */ + void *value; /**< The value of custom command */ +} hal_codec_custom_command_s; + +/** + * @brief The structure type of the codec HAL batch command. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef struct { + /* flag for modified command */ + uint64_t command_set_flag; /**< The flag for updating commands */ + + /* value list */ + uint64_t bitrate; /**< The value for bitrate command */ + hal_codec_custom_command_s custom; /**< The value for custom command */ +} hal_codec_batch_command_control_s; + +/** + * @brief Enumeration for the codec HAL message type. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef enum { + HAL_CODEC_MESSAGE_TYPE_INPUT_BUFFER_USED = 0x0001, /**< Input buffer is used */ + HAL_CODEC_MESSAGE_TYPE_OUTPUT_BUFFER, /**< Output buffer is delivered */ + HAL_CODEC_MESSAGE_TYPE_RESOLUTION_CHANGED, /**< Resolution is changed */ + + HAL_CODEC_MESSAGE_TYPE_ERROR = 0xffff /**< Error is occurred */ +} hal_codec_message_type_e; + +/** + * @brief The structure type of the codec HAL message. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef struct { + hal_codec_message_type_e type; /**< The type of message */ + union { + hal_codec_error_e error_code; /**< The error code */ + hal_codec_buffer_s *buffer; /**< The buffer for #HAL_CODEC_MESSAGE_TYPE_INPUT_BUFFER_USED or #HAL_CODEC_MESSAGE_TYPE_OUTPUT_BUFFER */ + hal_codec_resolution_s resolution; /**< The changed resolution */ + }; +} hal_codec_message_s; + +/** + * @brief Callback function for notification from codec HAL. + * @since HAL_MODULE_CODEC 1.0 + * @param[in] message The message from codec HAL + * @param[in] user_data The user data for callback + * @see hal_codec_add_message_callback() + * @see hal_codec_remove_message_callback() + */ +typedef int (*hal_codec_message_cb)(hal_codec_message_s *message, void *user_data); + +/** + * @brief The structure type of the codec HAL functions. + * @since HAL_MODULE_CODEC 1.0 + */ +typedef struct _hal_backend_codec_funcs { + /**< Initialize HAL backend handle */ + int (*init)(hal_codec_type_e type, void **codec_handle); + /**< Deinitialize HAL backend handle */ + int (*deinit)(void *codec_handle); + /**< Configure codec */ + int (*configure)(void *codec_handle, int width, int height, hal_codec_format_e in_format, hal_codec_format_e out_format, bool is_secure); + /**< Release codec */ + int (*release)(void *codec_handle); + /**< Start codec */ + int (*start)(void *codec_handle, hal_codec_message_cb callback, void *user_data); + /**< Stop codec */ + int (*stop)(void *codec_handle); + /**< Flush codec */ + int (*flush)(void *codec_handle); + /**< Decode data */ + int (*decode)(void *codec_handle, hal_codec_buffer_s *buffer); + /**< Encode data */ + int (*encode)(void *codec_handle, hal_codec_buffer_s *buffer); + /**< Release output buffer */ + int (*release_output_buffer)(void *codec_handle, int buffer_index); + /**< Get state of codec */ + int (*get_state)(void *codec_handle, hal_codec_state_e *state); + /**< Set command for various settings */ + int (*set_command)(void *codec_handle, hal_codec_command_e command, void *value); + /**< Get command for various settings */ + int (*get_command)(void *codec_handle, hal_codec_command_e command, void **value); + /**< Set batch command for multiple settings */ + int (*set_batch_command)(void *codec_handle, hal_codec_batch_command_control_s *batch_command, hal_codec_command_e *error_command); +} hal_backend_codec_funcs; + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif +#endif /* __HAL_CODEC_INTERFACE_1__ */ diff --git a/include/hal-codec-interface.h b/include/hal-codec-interface.h new file mode 100644 index 0000000..d4671bf --- /dev/null +++ b/include/hal-codec-interface.h @@ -0,0 +1,24 @@ +/* + * HAL (Hardware Abstract Layer) interface API for Codec + * + * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * + * 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 __HAL_CODEC_INTERFACE__ +#define __HAL_CODEC_INTERFACE__ + +#include + +#endif /* __HAL_CODEC_INTERFACE__ */ diff --git a/include/hal-codec.h b/include/hal-codec.h new file mode 100644 index 0000000..d93299d --- /dev/null +++ b/include/hal-codec.h @@ -0,0 +1,289 @@ +/* + * HAL (Hardware Abstract Layer) API for Codec + * + * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * + * 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 __HAL_CODEC__ +#define __HAL_CODEC__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file hal-codec.h + * @brief This file contains the Tizen codec HAL API, related structures and enumerations. + * @since HAL_MODULE_CODEC 1.0 + */ + +/** + * @addtogroup HAL_CODEC_MODULE + * @{ + */ + +/** + * @brief Initializes new handle of codec HAL. + * @since HAL_MODULE_CODEC 1.0 + * @param[in] type The type of codec + * @param[out] codec_handle The newly returned handle to the codec HAL + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_OUT_OF_MEMORY Out of memory + * @post If it succeeds, the codec state will be #HAL_CODEC_STATE_INITIALIZED. + * @see hal_codec_deinit() + */ +int hal_codec_init(hal_codec_type_e type, void **codec_handle); + +/** + * @brief Deinitializes handle of codec HAL. + * @since HAL_MODULE_CODEC 1.0 + * @param[in] codec_handle The handle to the codec HAL + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @see hal_codec_init() + */ +int hal_codec_deinit(void *codec_handle); + +/** + * @brief Configures codec. + * @since HAL_MODULE_CODEC 1.0 + * @param[in] codec_handle The handle to the codec HAL + * @param[in] width The width of buffer to be processed + * @param[in] height The height of buffer to be processed + * @param[in] in_format The format of input buffer to be processed + * @param[in] out_format The format of output buffer to be processed + * @param[in] is_secure The flag which indicates whether secure mode or not + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_PERMISSION_DENIED The access to the resources can not be granted + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_INVALID_STATE Invalid state + * @retval #HAL_CODEC_ERROR_INVALID_OPERATION Invalid operation + * @retval #HAL_CODEC_ERROR_DEVICE_BUSY The device is being used in another application or is performing other operations + * @retval #HAL_CODEC_ERROR_NOT_IMPLEMENTED The feature is not implemented + * @pre The codec state must be set to #HAL_CODEC_STATE_INITIALIZED. + * @post If it succeeds, the codec state will be #HAL_CODEC_STATE_CONFIGURED. + */ +int hal_codec_configure(void *codec_handle, int width, int height, hal_codec_format_e in_format, hal_codec_format_e out_format, bool is_secure); + +/** + * @brief Releases codec. + * @since HAL_MODULE_CODEC 1.0 + * @param[in] codec_handle The handle to the codec HAL + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_INVALID_STATE Invalid state + * @retval #HAL_CODEC_ERROR_INVALID_OPERATION Invalid operation + * @retval #HAL_CODEC_ERROR_DEVICE_BUSY The device is being used in another application or is performing other operations + * @retval #HAL_CODEC_ERROR_NOT_IMPLEMENTED The feature is not implemented + * @pre The codec state must be set to #HAL_CODEC_STATE_CONFIGURED. + * @post If it succeeds, the codec state will be #HAL_CODEC_STATE_INITIALIZED. + */ +int hal_codec_release(void *codec_handle); + +/** + * @brief Starts codec. + * @since HAL_MODULE_CODEC 1.0 + * @param[in] codec_handle The handle to the codec HAL + * @param[in] callback The callback function for codec message + * @param[in] user_data The user data to be passed to the @a callback + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_INVALID_STATE Invalid state + * @retval #HAL_CODEC_ERROR_INVALID_OPERATION Invalid operation + * @retval #HAL_CODEC_ERROR_DEVICE_BUSY The device is being used in another application or is performing other operations + * @retval #HAL_CODEC_ERROR_NOT_IMPLEMENTED The feature is not implemented + * @pre The codec state must be set to #HAL_CODEC_STATE_CONFIGURED. + * @post If it succeeds, the codec state will be #HAL_CODEC_STATE_STARTED. + * @see hal_codec_stop() + */ +int hal_codec_start(void *codec_handle, hal_codec_message_cb callback, void *user_data); + +/** + * @brief Stops codec. + * @since HAL_MODULE_CODEC 1.0 + * @param[in] codec_handle The handle to the codec HAL + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_INVALID_STATE Invalid state + * @retval #HAL_CODEC_ERROR_INVALID_OPERATION Invalid operation + * @retval #HAL_CODEC_ERROR_NOT_IMPLEMENTED The feature is not implemented + * @pre The codec state must be set to #HAL_CODEC_STATE_STARTED. + * @post The codec state will be #HAL_CODEC_STATE_CONFIGURED. + * @see hal_codec_start() + */ +int hal_codec_stop(void *codec_handle); + +/** + * @brief Flushes codec. + * @since HAL_MODULE_CODEC 1.0 + * @param[in] codec_handle The handle to the codec HAL + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_INVALID_STATE Invalid state + * @retval #HAL_CODEC_ERROR_INVALID_OPERATION Invalid operation + * @retval #HAL_CODEC_ERROR_DEVICE_BUSY The device is being used in another application or is performing other operations + * @retval #HAL_CODEC_ERROR_NOT_IMPLEMENTED The feature is not implemented + * @pre The codec state must be set to #CODEC_STATE_STARTED. + * @see hal_codec_start() + */ +int hal_codec_flush(void *codec_handle); + +/** + * @brief Decodes data. + * @since HAL_MODULE_CODEC 1.0 + * @remarks The buffer should not be released until before gets #HAL_CODEC_MESSAGE_TYPE_INPUT_BUFFER_USED message. + * @param[in] codec_handle The handle to the codec HAL + * @param[in] buffer The buffer to be decoded + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_INVALID_STATE Invalid state + * @retval #HAL_CODEC_ERROR_INVALID_OPERATION Invalid operation + * @retval #HAL_CODEC_ERROR_DEVICE_BUSY The device is being used in another application or is performing other operations + * @retval #HAL_CODEC_ERROR_NOT_IMPLEMENTED The feature is not implemented + * @pre The codec state must be set to #HAL_CODEC_STATE_STARTED. + * @see hal_codec_start() + */ +int hal_codec_decode(void *codec_handle, hal_codec_buffer_s *buffer); + +/** + * @brief Encodes data. + * @since HAL_MODULE_CODEC 1.0 + * @remarks The buffer should not be released until before gets #HAL_CODEC_MESSAGE_TYPE_INPUT_BUFFER_USED message. + * @param[in] codec_handle The handle to the codec HAL + * @param[in] buffer The buffer to be encoded + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_INVALID_STATE Invalid state + * @retval #HAL_CODEC_ERROR_INVALID_OPERATION Invalid operation + * @retval #HAL_CODEC_ERROR_DEVICE_BUSY The device is being used in another application or is performing other operations + * @retval #HAL_CODEC_ERROR_NOT_IMPLEMENTED The feature is not implemented + * @pre The codec state must be set to #HAL_CODEC_STATE_STARTED. + * @see hal_codec_start() + */ +int hal_codec_encode(void *codec_handle, hal_codec_buffer_s *buffer); + +/** + * @brief Release the output buffer to codec. + * @since HAL_MODULE_CODEC 1.0 + * @remarks The output buffer should be released with this function after use it. + * @param[in] codec_handle The handle to the codec HAL + * @param[in] buffer_index The index of output buffer to be released + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_INVALID_STATE Invalid state + * @retval #HAL_CODEC_ERROR_INVALID_OPERATION Invalid operation + * @retval #HAL_CODEC_ERROR_NOT_IMPLEMENTED The feature is not implemented + * @see hal_codec_start_preview() + */ +int hal_codec_release_output_buffer(void *codec_handle, int buffer_index); + +/** + * @brief Gets the state of codec. + * @since HAL_MODULE_CODEC 1.0 + * @param[in] codec_handle The handle to the codec HAL + * @param[out] state The current state of the codec + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_INVALID_OPERATION Invalid operation + * @retval #HAL_CODEC_ERROR_NOT_IMPLEMENTED The feature is not implemented + */ +int hal_codec_get_state(void *codec_handle, hal_codec_state_e *state); + +/** + * @brief Sets the various command and value to control codec. + * @since HAL_MODULE_CODEC 1.0 + * @param[in] codec_handle The handle to the codec HAL + * @param[in] command The command to control the codec device + * @param[in] value The value to set + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_INVALID_OPERATION Invalid operation + * @retval #HAL_CODEC_ERROR_INVALID_STATE Invalid state + * @retval #HAL_CODEC_ERROR_NOT_IMPLEMENTED The feature is not implemented + * @see hal_codec_get_command() + */ +int hal_codec_set_command(void *codec_handle, hal_codec_command_e command, void *value); + +/** + * @brief Gets the current value of command. + * @since HAL_MODULE_CODEC 1.0 + * @param[in] codec_handle The handle to the codec HAL + * @param[in] command The command to control the codec device + * @param[out] value The value to get + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_INVALID_OPERATION Invalid operation + * @retval #HAL_CODEC_ERROR_INVALID_STATE Invalid state + * @retval #HAL_CODEC_ERROR_DEVICE_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_NOT_IMPLEMENTED The feature is not implemented + * @see hal_codec_set_command() + */ +int hal_codec_get_command(void *codec_handle, hal_codec_command_e command, void **value); + +/** + * @brief Sets a set of commands. + * @since HAL_MODULE_CODEC 1.0 + * @remarks error_command will be set if error is returned from the function. + * @param[in] codec_handle The handle to the codec HAL + * @param[in] batch_command The batch command to set + * @param[out] error_command The error command + * @return @c 0 on success, otherwise a negative error value + * @retval #HAL_CODEC_ERROR_NONE Successful + * @retval #HAL_CODEC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HAL_CODEC_ERROR_INVALID_OPERATION Invalid operation + * @retval #HAL_CODEC_ERROR_INVALID_STATE Invalid state + * @retval #HAL_CODEC_ERROR_DEVICE_NOT_SUPPORTED The feature is not supported + * @retval #HAL_CODEC_ERROR_NOT_IMPLEMENTED The feature is not implemented + * @see hal_codec_set_command() + * @see hal_codec_get_command() + */ +int hal_codec_set_batch_command(void *codec_handle, hal_codec_batch_command_control_s *batch_command, hal_codec_command_e *error_command); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* __HAL_CODEC__ */ diff --git a/packaging/hal-api-codec-manifest.xml b/packaging/hal-api-codec-manifest.xml new file mode 100644 index 0000000..ef7b3ef --- /dev/null +++ b/packaging/hal-api-codec-manifest.xml @@ -0,0 +1,8 @@ + + + + HAL_MODULE_CODEC + 1.0 + + + diff --git a/packaging/hal-api-codec.spec b/packaging/hal-api-codec.spec index f1a6a66..5d05100 100644 --- a/packaging/hal-api-codec.spec +++ b/packaging/hal-api-codec.spec @@ -1,51 +1,77 @@ %define module_name codec %define name hal-api-%{module_name} %define res_path /testcase/res/codec +%define enable_test 1 ### main package ######### Name: %{name} Summary: %{name} interface -Version: 0.0.2 +Version: 1.0.0 Release: 0 Group: Development/Libraries License: Apache-2.0 Source0: %{name}-%{version}.tar.gz +Source1: %{name}-manifest.xml Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig BuildRequires: cmake BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(hal-api-common) +%if "%{enable_test}" == "1" BuildRequires: pkgconfig(gmock) -BuildRequires: pkgconfig(gstreamer-1.0) -BuildRequires: pkgconfig(gstreamer-plugins-base-1.0) -BuildRequires: pkgconfig(iniparser) -BuildRequires: pkgconfig(libtbm) +%endif %description %{name} interface package for product vendor developer +### devel package ######### +%package devel +Summary: %{name} interface +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +%{name} interface development package for product vendor developer + + +%if "%{enable_test}" == "1" ### test package ######### %package haltests Summary: tests for %{name} %description haltests Haltests for %{name} +%endif ### build and install ######### %prep %setup -q +%if "%{enable_test}" == "1" export CXXFLAGS+=" -D_LARGEFILE64_SOURCE -DSYSCONFDIR=\\\"%{_hal_sysconfdir}\\\" -DTEST_FILES_PATH=\\\"%{_datadir}%{res_path}\\\"" -%cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DCMAKE_LIBDIR_PREFIX=%{_libdir} -DTESTCASE_RES_DIR=%{_datadir}%{res_path} +%endif + +%cmake . \ +%if "%{enable_test}" == "1" + -DENABLE_TESTS=YES\ + -DTESTCASE_RES_DIR=%{_datadir}%{res_path}\ +%endif + -DCMAKE_INSTALL_PREFIX=%{_prefix}\ + -DCMAKE_LIBDIR_PREFIX=%{_libdir} %build make %{?jobs:-j%jobs} %install rm -rf %{buildroot} +mkdir -p %{buildroot}%{_sysconfdir}/hal +cp %{SOURCE1} %{buildroot}%{_sysconfdir}/hal/ +%if "%{enable_test}" == "1" install -d -m 755 %{buildroot}%{_datadir}%{res_path} install -m 644 tests/res/* %{buildroot}%{_datadir}%{res_path} +%endif %make_install %clean @@ -53,12 +79,31 @@ rm -rf %{buildroot} %post /sbin/ldconfig +/usr/bin/hal-compatibility-checker --reset %postun /sbin/ldconfig +/usr/bin/hal-compatibility-checker --reset + + +%files +%manifest %{name}.manifest +%license LICENSE +%defattr(-,root,root,-) +%{_libdir}/hal/*.so.* +%{_sysconfdir}/hal/%{name}-manifest.xml +%files devel +%defattr(-,root,root,-) +%{_includedir}/hal/*.h +%{_libdir}/hal/*.so +%{_libdir}/pkgconfig/*.pc + +%if "%{enable_test}" == "1" %files haltests %manifest %{name}-haltests.manifest %{_bindir}/hal/codec-haltests %{_datadir}%{res_path}/* +%endif + diff --git a/src/hal-api-codec.c b/src/hal-api-codec.c new file mode 100644 index 0000000..15664c6 --- /dev/null +++ b/src/hal-api-codec.c @@ -0,0 +1,312 @@ +/* + * HAL (Hardware Abstract Layer) API Codec + * + * Copyright (c) 2024 Samsung Electronics Co., Ltd. + * + * 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 "hal-codec.h" + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "HALAPI_CODEC" + +#define HAL_CODEC_RETURN_IF_FAILED(arg, ret) \ + do {\ + if (!(arg)) {\ + SLOGE("[%s]failed, return[%s]", #arg, #ret);\ + return (ret);\ + }\ + } while (0) + +#define HAL_CODEC_DO_RETURN_IF_FAILED(arg, do_something, ret) \ + do {\ + if (!(arg)) {\ + SLOGE("[%s]failed, return[%s]", #arg, #ret);\ + do_something;\ + return (ret);\ + }\ + } while (0); + + +typedef struct _hal_codec_s { + void *backend; + hal_backend_codec_funcs *funcs; +} hal_codec_s; + + +static int hal_codec_init_backend(void **data, void *user_data) +{ + if (!data) { + SLOGE("NULL data"); + return -EINVAL; + } + + *data = g_new0(hal_backend_codec_funcs, 1); + + SLOGI("new - codec HAL funcs[%p], size[%zu]", + *data, sizeof(hal_backend_codec_funcs)); + + return 0; +} + + +static int hal_codec_exit_backend(void *data, void *user_data) +{ + if (!data) { + SLOGE("NULL data"); + return -EINVAL; + } + + SLOGI("release - codec HAL funcs[%p], size[%zu]", + data, sizeof(hal_backend_codec_funcs)); + + g_free(data); + + return 0; +} + + +int hal_codec_init(hal_codec_type_e type, void **codec_handle) +{ + int ret = 0; + hal_codec_s *new_handle = NULL; + + HAL_CODEC_RETURN_IF_FAILED(codec_handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + + SLOGI("start"); + + new_handle = g_new0(hal_codec_s, 1); + + ret = hal_common_get_backend_v2(HAL_MODULE_CODEC, + (void **)&new_handle->funcs, + NULL, + hal_codec_init_backend); + if (ret != 0) { + SLOGE("Failed to get backend"); + goto __HAL_INIT_FAILED; + } + + if (!new_handle->funcs || !new_handle->funcs->init) { + SLOGE("invalid ptr[%p]", new_handle->funcs); + goto __HAL_INIT_FAILED; + } + + ret = new_handle->funcs->init(type, &new_handle->backend); + if (ret != HAL_CODEC_ERROR_NONE) { + SLOGE("backend init failed[0x%x]", ret); + goto __HAL_INIT_FAILED; + } + + *codec_handle = (void *)new_handle; + + SLOGI("done"); + + return HAL_CODEC_ERROR_NONE; + +__HAL_INIT_FAILED: + if (new_handle->funcs) { + hal_common_put_backend_v2(HAL_MODULE_CODEC, + (void *)new_handle->funcs, + NULL, + hal_codec_exit_backend); + } + + g_free(new_handle); + + return HAL_CODEC_ERROR_INTERNAL; +} + + +int hal_codec_deinit(void *codec_handle) +{ + int ret = 0; + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->deinit, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + SLOGI("start"); + + ret = handle->funcs->deinit(handle->backend); + if (ret != HAL_CODEC_ERROR_NONE) { + SLOGE("deinit failed[0x%x]", ret); + return ret; + } + + hal_common_put_backend_v2(HAL_MODULE_CODEC, + (void *)handle->funcs, + NULL, + hal_codec_exit_backend); + + g_free(handle); + + SLOGI("done"); + + return HAL_CODEC_ERROR_NONE; +} + + +int hal_codec_configure(void *codec_handle, int width, int height, hal_codec_format_e in_format, hal_codec_format_e out_format, bool is_secure) +{ + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->configure, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + return handle->funcs->configure(handle->backend, width, height, in_format, out_format, is_secure); +} + + +int hal_codec_release(void *codec_handle) +{ + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->release, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + return handle->funcs->release(handle->backend); +} + + +int hal_codec_start(void *codec_handle, hal_codec_message_cb callback, void *user_data) +{ + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->start, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + return handle->funcs->start(handle->backend, callback, user_data); +} + + +int hal_codec_stop(void *codec_handle) +{ + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->stop, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + return handle->funcs->stop(handle->backend); +} + + +int hal_codec_flush(void *codec_handle) +{ + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->flush, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + return handle->funcs->flush(handle->backend); +} + + +int hal_codec_decode(void *codec_handle, hal_codec_buffer_s *buffer) +{ + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->decode, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + return handle->funcs->decode(handle->backend, buffer); +} + + +int hal_codec_encode(void *codec_handle, hal_codec_buffer_s *buffer) +{ + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->encode, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + return handle->funcs->encode(handle->backend, buffer); +} + + +int hal_codec_release_output_buffer(void *codec_handle, int buffer_index) +{ + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->release_output_buffer, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + return handle->funcs->release_output_buffer(handle->backend, buffer_index); +} + + +int hal_codec_get_state(void *codec_handle, hal_codec_state_e *state) +{ + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->get_state, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + return handle->funcs->get_state(handle->backend, state); +} + + +int hal_codec_set_command(void *codec_handle, hal_codec_command_e command, void *value) +{ + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->set_command, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + return handle->funcs->set_command(handle->backend, command, value); +} + + +int hal_codec_get_command(void *codec_handle, hal_codec_command_e command, void **value) +{ + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->get_command, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + return handle->funcs->get_command(handle->backend, command, value); +} + + +int hal_codec_set_batch_command(void *codec_handle, hal_codec_batch_command_control_s *batch_command, hal_codec_command_e *error_command) +{ + hal_codec_s *handle = (hal_codec_s *)codec_handle; + + HAL_CODEC_RETURN_IF_FAILED(handle, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs, HAL_CODEC_ERROR_INVALID_PARAMETER); + HAL_CODEC_RETURN_IF_FAILED(handle->funcs->set_batch_command, HAL_CODEC_ERROR_NOT_IMPLEMENTED); + + return handle->funcs->set_batch_command(handle->backend, batch_command, error_command); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a5f7081..f7c6bec 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,14 +1,12 @@ SET(HAL_CODEC_TEST "codec-haltests") -SET(PREFIX ${CMAKE_INSTALL_PREFIX}) -SET(EXEC_PREFIX "${CMAKE_INSTALL_PREFIX}/bin") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -Werror") AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR}/ HALTEST_SRCS) ADD_EXECUTABLE(${HAL_CODEC_TEST} ${HALTEST_SRCS}) INCLUDE(FindPkgConfig) -pkg_check_modules(${HAL_CODEC_TEST} REQUIRED glib-2.0 gmock gstreamer-1.0 gstreamer-plugins-base-1.0 iniparser libtbm) +pkg_check_modules(${HAL_CODEC_TEST} REQUIRED glib-2.0 gmock) FOREACH(flag ${${HAL_CODEC_TEST}_CFLAGS}) SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") @@ -16,7 +14,9 @@ ENDFOREACH(flag) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CFLAGS} -fPIC -pie -Wall") -TARGET_LINK_LIBRARIES(${HAL_CODEC_TEST} ${${HAL_CODEC_TEST}_LDFLAGS}) +ADD_DEFINITIONS("-DRES_DIR=\"${TESTCASE_RES_DIR}\"") + +TARGET_LINK_LIBRARIES(${HAL_CODEC_TEST} ${PROJECT_NAME} ${${HAL_CODEC_TEST}_LDFLAGS}) SET_TARGET_PROPERTIES(${HAL_CODEC_TEST} PROPERTIES COMPILE_FLAGS "-fPIE") SET_TARGET_PROPERTIES(${HAL_CODEC_TEST} PROPERTIES LINK_FLAGS "-pie") diff --git a/tests/codec_hal_test.cpp b/tests/codec_hal_test.cpp index 58dfc1b..93dc09e 100644 --- a/tests/codec_hal_test.cpp +++ b/tests/codec_hal_test.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 Samsung Electronics Co., Ltd. All rights reserved. + * Copyright (c) 2024 Samsung Electronics Co., Ltd. All rights reserved. * * Contact: Jeongmo Yang * @@ -19,173 +19,34 @@ #include #include #include -#include #include #include -#include -#include -#include -#include +#include +#include -using namespace std; -typedef struct _codec_list_t codec_list_t; -#define CNAME_SIZE 512 -#define CODEC_INI_MAX_STRLEN 256 -#define DEFAULT_PORT "GST_PORT" -#define CODEC_INI_DEFAULT_PATH SYSCONFDIR"/multimedia/mmfw_media_codec.ini" - -#define CODEC_INI_GET_STRING(x_dict, x_item, x_ini, x_default) \ -do {\ - const char *str = iniparser_getstring(x_dict, x_ini, x_default); \ - \ - if (str && \ - (strlen(str) > 0) && \ - (strlen(str) < CODEC_INI_MAX_STRLEN)) \ - strncpy(x_item, str, strlen(str) + 1); \ - else \ - strncpy(x_item, x_default, strlen(x_default) + 1); \ -} while (0) - -typedef enum { - H263, - H264, - MPEG4 -} codec_list_e; - -typedef enum { - DECODER, - ENCODER -} codec_type_e; - -struct _codec_list_t { - codec_list_e ename; - char cname[CODEC_INI_MAX_STRLEN]; - char plugins[2][CODEC_INI_MAX_STRLEN]; -}; - -static codec_list_t codec_list[] = { - { H263, "h263", }, - { H264, "h264", }, - { MPEG4, "mpeg4" }, -}; - -void get_plugins_list_from_ini(dictionary *dict, codec_list_t *codec_list, int codec_num) -{ - int i, j; - int index = 0; - char *token = NULL; - char *usr_ptr = NULL; - const char *delimiters = " ,"; - size_t len; - char port_name[CNAME_SIZE]; - char temp[CNAME_SIZE]; - char cname[CNAME_SIZE]; - const char *type[2]; - type[DECODER] = ":hw_decoder"; - type[ENCODER] = ":hw_encoder"; - - CODEC_INI_GET_STRING(dict, port_name, (char *)"port_in_use:media_codec_port", (char *)DEFAULT_PORT); - - if (strcmp(port_name, DEFAULT_PORT) == 0) { - for (i = 0; i < 2; i++) { - for (j = 0; j < codec_num; j++) { - index = 0; - - snprintf(cname, CNAME_SIZE, "%s", codec_list[j].cname); - len = strlen(cname); - snprintf(cname + len, CNAME_SIZE - len, "%s", type[i]); - CODEC_INI_GET_STRING(dict, temp, cname, (char *)""); - token = strtok_r(temp, delimiters, &usr_ptr); - - while (token) { - if (token && index == 0) - strncpy(codec_list[j].plugins[i], token, strlen(token) + 1); - token = strtok_r(NULL, delimiters, &usr_ptr); - index++; - } - } - } - } -} - -static void -pad_added_cb(GstElement * demux, GstPad * pad, GstBin * pipeline) -{ - GstElement *sink, *parse, *codec; - GstCaps *caps; - - GST_INFO_OBJECT(pad, "got pad"); - - caps = gst_pad_query_caps(pad, NULL); - gchar *caps_str = gst_caps_to_string(caps); - gst_caps_unref(caps); - - if (strstr(caps_str, "h264")) { - parse = gst_element_factory_make("h264parse", NULL); - codec = gst_element_factory_make(codec_list[H264].plugins[DECODER], NULL); - } else if (strstr(caps_str, "h263")) { - parse = gst_element_factory_make("h263parse", NULL); - codec = gst_element_factory_make(codec_list[H263].plugins[DECODER], NULL); - } else if (strstr(caps_str, "video/mpeg")) { - parse = gst_element_factory_make("mpeg4videoparse", NULL); - codec = gst_element_factory_make(codec_list[MPEG4].plugins[DECODER], NULL); - } else { - GST_WARNING_OBJECT(pad, "non video pad"); - g_free(caps_str); - return; - } - - sink = gst_element_factory_make("fakesink", NULL); - gst_bin_add_many(GST_BIN(pipeline), parse, codec, sink, NULL); - gst_element_link_many(demux, parse, codec, sink, NULL); - - gst_element_set_state(parse, GST_STATE_PAUSED); - gst_element_set_state(codec, GST_STATE_PAUSED); - gst_element_set_state(sink, GST_STATE_PAUSED); - g_free(caps_str); -} -static GstBusSyncReply -error_cb(GstBus * bus, GstMessage * msg, gpointer user_data) -{ - if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) { - const gchar *file = (const gchar *)user_data; - GError *err = NULL; - gchar *dbg = NULL; +using namespace std; - gst_message_parse_error(msg, &err, &dbg); - g_error("ERROR for %s: %s\n%s\n", file, err->message, dbg); - } - return GST_BUS_PASS; -} +#define CONTENTS_H264_PATH RES_DIR"/decode_test.h264" +#define CONTENTS_H264_FRAME_NUM 10 -gboolean bus_callback(GstBus *bus, GstMessage *msg, gpointer data) -{ - switch (GST_MESSAGE_TYPE(msg)) { - case GST_MESSAGE_EOS: - break; - case GST_MESSAGE_ERROR: - break; - default: - break; - } - return TRUE; -} +#define CODEC_SUPPORT_CHECK \ + do {\ + if (!gCodecSupported) {\ + cout << "CODEC NOT SUPPORTED" << endl;\ + ASSERT_EQ(ret, HAL_CODEC_ERROR_NOT_SUPPORTED);\ + return;\ + }\ + } while (0) -void buffer_add(GstElement *element, GstBuffer *buffer, GstPad *pad, gpointer data) -{ -} +#define DUMP_OUTPUT_BUFFER -static gboolean __is_hw_codec_supported(codec_list_e codec, codec_type_e type) -{ - if (strlen(codec_list[codec].plugins[type]) == 0) { - std::cout << "NO HW CODEC SUPPORTED" << std::endl; - return FALSE; - } - return TRUE; -} +static int decode_test_frame_size[CONTENTS_H264_FRAME_NUM] = {151919, 84650, 8389, 20692, 18090, 18737, 17585, 18476, 11879, 10796}; +static int ret; +static bool gCodecSupported; +static void *gHalHandle; /* * main class @@ -193,622 +54,311 @@ static gboolean __is_hw_codec_supported(codec_list_e codec, codec_type_e type) class CodecHalTest : public testing::Test { public: - virtual void SetUp() { - return; + gCodecSupported = true; + + ret = hal_codec_init(HAL_CODEC_TYPE_DECODER, &gHalHandle); + if (ret == HAL_CODEC_ERROR_NONE) { + cout << "Codec HAL init - handle: " << gHalHandle << endl; + return; + } + + if (ret == HAL_CODEC_ERROR_NOT_SUPPORTED) { + cout << "Codec HAL Not Supported" << endl; + gCodecSupported = false; + return; + } + + cout << "Codec HAL init failed " << ret << endl; } virtual void TearDown() { + if (gHalHandle) { + cout << "Codec HAL deinit - handle: " << gHalHandle << endl; + hal_codec_deinit(gHalHandle); + gHalHandle = nullptr; + } + + ReleaseContents(); return; } -}; - -/** - * @testcase InitH263DecoderP - * @since_tizen 6.5 - * @author SR(jm80.yang) - * @reviewer SR(heechul.jeon) - * @type auto - * @description Positive, Initialize H.263 Decoder Plugin - * @apicovered N/A - * @passcase when h263 decoder plugin exists pipeline can be changed to GST_STATE_PAUSED - * @failcase when the state is not changed to GST_STATE_PAUSED - * @precondition None - * @postcondition None - */ -TEST_F(CodecHalTest, InitH263DecoderP) -{ - GstElement *sink, *src, *codec, *pipeline; - GstStateChangeReturn ret; - - if (!__is_hw_codec_supported(H263, DECODER)) - return; - - pipeline = gst_pipeline_new("pipeline"); - src = gst_element_factory_make("fakesrc", NULL); - codec = gst_element_factory_make(codec_list[H263].plugins[DECODER], NULL); - sink = gst_element_factory_make("fakesink", NULL); +#ifdef DUMP_OUTPUT_BUFFER + static void DumpBuffer(hal_codec_buffer_s *buffer, const char *dumpPath) + { + static int dumpCount = 0; - gst_bin_add_many(GST_BIN(pipeline), src, codec, sink, NULL); + if (!buffer || !dumpPath) { + cout << "DumpBuffer : buffer[" << buffer << "], path[" << dumpPath << "]" << endl; + return; + } - ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); - EXPECT_NE(ret, GST_STATE_CHANGE_FAILURE); + fstream fout(dumpPath, ios_base::out | ios_base::app); + uint32_t totalWrite = 0; - gst_object_unref(pipeline); -} + for (uint32_t i = 0 ; i < buffer->planes.num_planes ; i++) { + totalWrite += buffer->planes.plane[i].bytesused; + fout.write((const char *)buffer->planes.plane[i].data, buffer->planes.plane[i].bytesused); + } -/** - * @testcase InitH264DecoderP - * @since_tizen 6.5 - * @author SR(jm80.yang) - * @reviewer SR(heechul.jeon) - * @type auto - * @description Positive, Initialize H.263 Decoder Plugin - * @apicovered N/A - * @passcase when h264 decoder plugin exists pipeline can be changed to GST_STATE_PAUSED - * @failcase when the state is not changed to GST_STATE_PAUSED - * @precondition None - * @postcondition None - */ -TEST_F(CodecHalTest, InitH264DecoderP) -{ - GstElement *sink, *src, *codec, *pipeline; - GstStateChangeReturn ret; + dumpCount++; + cout << "Dump[count:" << dumpCount << "] buffer size[" << totalWrite << "]" << endl; - if (!__is_hw_codec_supported(H264, DECODER)) - return; + fout.close(); + } +#endif - pipeline = gst_pipeline_new("pipeline"); - src = gst_element_factory_make("fakesrc", NULL); - codec = gst_element_factory_make(codec_list[H264].plugins[DECODER], NULL); - sink = gst_element_factory_make("fakesink", NULL); + static int MessageCb(hal_codec_message_s *message, void *user_data) + { + int *decoded_count = (int *)user_data; - gst_bin_add_many(GST_BIN(pipeline), src, codec, sink, NULL); + if (!message) { + cout << "Codec HAL : NULL message" << endl; + return 0; + } - ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); - EXPECT_NE(ret, GST_STATE_CHANGE_FAILURE); + cout << "Codec HAL : message type[" << message->type << "]" << endl; - gst_object_unref(pipeline); -} + switch (message->type) { + case HAL_CODEC_MESSAGE_TYPE_INPUT_BUFFER_USED: + cout << "Codec HAL : INPUT BUFFER USED p:" << message->buffer << endl; + break; + case HAL_CODEC_MESSAGE_TYPE_OUTPUT_BUFFER: + if (decoded_count) + (*decoded_count)++; -/** - * @testcase InitMpeg4DecoderP - * @since_tizen 6.5 - * @author SR(jm80.yang) - * @reviewer SR(heechul.jeon) - * @type auto - * @description Positive, Initialize MPEG4 Decoder Plugin - * @apicovered N/A - * @passcase when MPEG4 decoder plugin exists pipeline can be changed to GST_STATE_PAUSED - * @failcase when the state is not changed to GST_STATE_PAUSED - * @precondition None - * @postcondition None - */ -TEST_F(CodecHalTest, InitMpeg4DecoderP) -{ - GstElement *sink, *src, *codec, *pipeline; - GstStateChangeReturn ret; + cout << "Codec HAL : OUTPUT BUFFER index: " << message->buffer->index << endl; +#ifdef DUMP_OUTPUT_BUFFER + DumpBuffer(message->buffer, "/home/owner/media/dump.yuv"); +#endif + hal_codec_release_output_buffer(gHalHandle, message->buffer->index); + cout << "Codec HAL : OUTPUT BUFFER Released" << endl; + break; + default: + break; + } - if (!__is_hw_codec_supported(MPEG4, DECODER)) - return; + return 0; + } - pipeline = gst_pipeline_new("pipeline"); - src = gst_element_factory_make("fakesrc", NULL); - codec = gst_element_factory_make(codec_list[MPEG4].plugins[DECODER], NULL); - sink = gst_element_factory_make("fakesink", NULL); + int GetContents(const char *path) + { + GError *error = nullptr; - gst_bin_add_many(GST_BIN(pipeline), src, codec, sink, NULL); + if (mappedFile_) + g_mapped_file_unref(mappedFile_); - ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); - EXPECT_NE(ret, GST_STATE_CHANGE_FAILURE); + mappedFile_ = g_mapped_file_new(path, FALSE, &error); + if (!mappedFile_) { + cout << "Codec HAL : get contents[" << path << "] failed" << endl; + return -1; + } - gst_object_unref(pipeline); -} + mappedFileLength_ = g_mapped_file_get_length(mappedFile_); + mappedFileContents_ = g_mapped_file_get_contents(mappedFile_); + mappedFileOffset_ = 0; -/** - * @testcase InitH263EncoderP - * @since_tizen 6.5 - * @author SR(jm80.yang) - * @reviewer SR(heechul.jeon) - * @type auto - * @description Positive, Initialize H.263 Encoder Plugin - * @apicovered N/A - * @passcase when H.263 encoder plugin exists pipeline can be changed to GST_STATE_PAUSED - * @failcase when the state is not changed to GST_STATE_PAUSED - * @precondition None - * @postcondition None - */ -TEST_F(CodecHalTest, InitH263EncoderP) -{ - GstElement *sink, *src, *codec, *pipeline; - GstStateChangeReturn ret; - - if (!__is_hw_codec_supported(H263, ENCODER)) - return; + cout << " Codec HAL : get contents[" << path << "] OK, length : " << mappedFileLength_ << endl; - pipeline = gst_pipeline_new("pipeline"); - src = gst_element_factory_make("fakesrc", NULL); - codec = gst_element_factory_make(codec_list[H263].plugins[ENCODER], NULL); - sink = gst_element_factory_make("fakesink", NULL); + return 0; + } - gst_bin_add_many(GST_BIN(pipeline), src, codec, sink, NULL); + void ReleaseContents(void) + { + if (mappedFile_) { + g_mapped_file_unref(mappedFile_); + mappedFile_ = nullptr; + } - ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); - EXPECT_NE(ret, GST_STATE_CHANGE_FAILURE); + mappedFileLength_ = 0; + mappedFileContents_ = nullptr; + } - gst_object_unref(pipeline); -} + GMappedFile *mappedFile_ {}; + gsize mappedFileLength_ {}; + gchar *mappedFileContents_ {}; + gsize mappedFileOffset_ {}; +}; /** - * @testcase InitH264EncoderP - * @since_tizen 6.5 + * @testcase InitP + * @since_tizen 9.0 * @author SR(jm80.yang) * @reviewer SR(heechul.jeon) * @type auto - * @description Positive, Initialize H.264 Encoder Plugin - * @apicovered N/A - * @passcase when H.264 encoder plugin exists pipeline can be changed to GST_STATE_PAUSED - * @failcase when the state is not changed to GST_STATE_PAUSED + * @description Positive, Initialize Codec HAL handle + * @apicovered hal_codec_init + * @passcase when hal_codec_init returns HAL_CODEC_ERROR_NONE and the handle "gHalHandle" is not a NULL pointer + * @failcase when handle "gHalHandle" is a NULL pointer * @precondition None * @postcondition None */ -TEST_F(CodecHalTest, InitH264EncoderP) +TEST_F(CodecHalTest, InitP) { - GstElement *sink, *src, *codec, *pipeline; - GstStateChangeReturn ret; + CODEC_SUPPORT_CHECK; - if (!__is_hw_codec_supported(H264, ENCODER)) - return; - - pipeline = gst_pipeline_new("pipeline"); - src = gst_element_factory_make("fakesrc", NULL); - codec = gst_element_factory_make(codec_list[H264].plugins[ENCODER], NULL); - sink = gst_element_factory_make("fakesink", NULL); - - gst_bin_add_many(GST_BIN(pipeline), src, codec, sink, NULL); - - ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); - EXPECT_NE(ret, GST_STATE_CHANGE_FAILURE); - - gst_object_unref(pipeline); + ASSERT_NE(gHalHandle, nullptr); } /** - * @testcase InitMPEG4EncoderP - * @since_tizen 6.5 + * @testcase DeinitP + * @since_tizen 9.0 * @author SR(jm80.yang) * @reviewer SR(heechul.jeon) * @type auto - * @description Positive, Initialize H.264 Encoder Plugin - * @apicovered N/A - * @passcase when MPEG4 encoder plugin exists pipeline can be changed to GST_STATE_PAUSED - * @failcase when the state is not changed to GST_STATE_PAUSED + * @description Positive, Deinitialize Codec HAL handle + * @apicovered hal_codec_init, hal_codec_deinit + * @passcase when hal_codec_deinit returns HAL_CODEC_ERROR_NONE + * @failcase when hal_codec_deinit does not return HAL_CODEC_ERROR_NONE * @precondition None * @postcondition None */ -TEST_F(CodecHalTest, InitMpeg4EncoderP) +TEST_F(CodecHalTest, DeinitP) { - GstElement *sink, *src, *codec, *pipeline; - GstStateChangeReturn ret; + void *hal_handle = nullptr; - if (!__is_hw_codec_supported(MPEG4, ENCODER)) - return; + CODEC_SUPPORT_CHECK; - pipeline = gst_pipeline_new("pipeline"); - src = gst_element_factory_make("fakesrc", NULL); - codec = gst_element_factory_make(codec_list[MPEG4].plugins[ENCODER], NULL); - sink = gst_element_factory_make("fakesink", NULL); + ret = hal_codec_init(HAL_CODEC_TYPE_DECODER, &hal_handle); - gst_bin_add_many(GST_BIN(pipeline), src, codec, sink, NULL); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); + ASSERT_NE(hal_handle, nullptr); - ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); - EXPECT_NE(ret, GST_STATE_CHANGE_FAILURE); + ret = hal_codec_deinit(hal_handle); - gst_object_unref(pipeline); + EXPECT_EQ(ret, HAL_CODEC_ERROR_NONE); } /** - * @testcase DecodeH264P - * @since_tizen 6.5 + * @testcase ConfigureReleaseP + * @since_tizen 9.0 * @author SR(jm80.yang) * @reviewer SR(heechul.jeon) * @type auto - * @description Positive, Decode H.264 Decoder Plugin - * @apicovered N/A - * @passcase when h264 decoder decode stream, pipeline can be changed to GST_STATE_PLAYING - * @failcase when the state is not changed to GST_STATE_PLAYING + * @description Positive, Configure and release codec + * @apicovered hal_codec_configure, hal_codec_release + * @passcase when hal_codec_configure and hal_codec_release return HAL_CODEC_ERROR_NONE + * @failcase when hal_codec_configure or hal_codec_release do not return HAL_CODEC_ERROR_NONE * @precondition None * @postcondition None */ -TEST_F(CodecHalTest, DecodeH264P) +TEST_F(CodecHalTest, ConfigureReleaseP) { - GstStateChangeReturn state_ret; - GstElement *src, *demux, *pipeline; - GstMessage *msg; - GstBus *bus; - gchar *path; - - if (!__is_hw_codec_supported(H264, DECODER)) - return; - - pipeline = gst_pipeline_new("pipeline"); - - src = gst_element_factory_make("filesrc", NULL); - - demux = gst_element_factory_make("qtdemux", NULL); - - bus = gst_element_get_bus(pipeline); - - /* kids, don't use a sync handler for this at home, really; we do because - * we just want to abort and nothing else */ - gst_bus_set_sync_handler(bus, error_cb, (gpointer) "meerkat.mp4", NULL); - - gst_bin_add_many(GST_BIN(pipeline), src, demux, NULL); - - gst_element_link(src, demux); + CODEC_SUPPORT_CHECK; - path = g_build_filename(TEST_FILES_PATH, "meerkat.mp4", NULL); - GST_INFO("reading file '%s'", path); - g_object_set(src, "location", path, NULL); + ASSERT_NE(gHalHandle, nullptr); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); - /* can't link uridecodebin and sink yet, do that later */ - g_signal_connect(demux, "pad-added", G_CALLBACK(pad_added_cb), pipeline); + ret = hal_codec_configure(gHalHandle, 1920, 1080, HAL_CODEC_FORMAT_H264, HAL_CODEC_FORMAT_NV12, false); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); - state_ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); - - if (state_ret == GST_STATE_CHANGE_ASYNC) { - GST_INFO("waiting for pipeline to reach PAUSED state"); - state_ret = gst_element_get_state(pipeline, NULL, NULL, -1); - } - - state_ret = gst_element_set_state(pipeline, GST_STATE_PLAYING); - EXPECT_NE(state_ret, GST_STATE_CHANGE_FAILURE); - - GST_INFO("PAUSED, let's decode"); - msg = gst_bus_timed_pop_filtered(bus, 10 * GST_SECOND, GST_MESSAGE_EOS); - GST_INFO("Done, got EOS message"); - - gst_message_unref(msg); - gst_object_unref(bus); - - gst_element_set_state(pipeline, GST_STATE_NULL); - EXPECT_EQ(state_ret, GST_STATE_CHANGE_SUCCESS); - - gst_object_unref(pipeline); - g_free(path); + ret = hal_codec_release(gHalHandle); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); } /** - * @testcase DecodeH263P - * @since_tizen 6.5 + * @testcase StartStopP + * @since_tizen 9.0 * @author SR(jm80.yang) * @reviewer SR(heechul.jeon) * @type auto - * @description Positive, Decode H.263 Decoder Plugin - * @apicovered N/A - * @passcase when h263 decoder decode stream, pipeline can be changed to GST_STATE_PLAYING - * @failcase when the state is not changed to GST_STATE_PLAYING + * @description Positive, Configure and release codec + * @apicovered hal_codec_start, hal_codec_stop + * @passcase when hal_codec_start and hal_codec_stop return HAL_CODEC_ERROR_NONE + * @failcase when hal_codec_start or hal_codec_stop do not return HAL_CODEC_ERROR_NONE * @precondition None * @postcondition None */ -TEST_F(CodecHalTest, DecodeH263P) +TEST_F(CodecHalTest, StartStopP) { - GstStateChangeReturn state_ret; - GstElement *src, *demux, *pipeline; - GstMessage *msg; - GstBus *bus; - gchar *path; - - if (!__is_hw_codec_supported(H263, DECODER)) - return; - - pipeline = gst_pipeline_new("pipeline"); - - src = gst_element_factory_make("filesrc", NULL); - - demux = gst_element_factory_make("qtdemux", NULL); - - bus = gst_element_get_bus(pipeline); + CODEC_SUPPORT_CHECK; - /* kids, don't use a sync handler for this at home, really; we do because - * we just want to abort and nothing else */ - gst_bus_set_sync_handler(bus, error_cb, (gpointer)"she.3gp", NULL); + ASSERT_NE(gHalHandle, nullptr); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); - gst_bin_add_many(GST_BIN(pipeline), src, demux, NULL); + ret = hal_codec_configure(gHalHandle, 1920, 1080, HAL_CODEC_FORMAT_H264, HAL_CODEC_FORMAT_NV12, false); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); - gst_element_link(src, demux); + ret = hal_codec_start(gHalHandle, CodecHalTest::MessageCb, NULL); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); - path = g_build_filename(TEST_FILES_PATH, "she.3gp", NULL); - GST_INFO("reading file '%s'", path); - g_object_set(src, "location", path, NULL); + usleep(100000); - /* can't link uridecodebin and sink yet, do that later */ - g_signal_connect(demux, "pad-added", G_CALLBACK(pad_added_cb), pipeline); + ret = hal_codec_stop(gHalHandle); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); - state_ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); - - if (state_ret == GST_STATE_CHANGE_ASYNC) { - GST_INFO("waiting for pipeline to reach PAUSED state"); - state_ret = gst_element_get_state(pipeline, NULL, NULL, -1); - } - - state_ret = gst_element_set_state(pipeline, GST_STATE_PLAYING); - EXPECT_NE(state_ret, GST_STATE_CHANGE_FAILURE); - - GST_INFO("PAUSED, let's decode"); - msg = gst_bus_timed_pop_filtered(bus, 10 * GST_SECOND, GST_MESSAGE_EOS); - GST_INFO("Done, got EOS message"); - - gst_message_unref(msg); - gst_object_unref(bus); - - state_ret = gst_element_set_state(pipeline, GST_STATE_NULL); - EXPECT_EQ(state_ret, GST_STATE_CHANGE_SUCCESS); - gst_object_unref(pipeline); - - g_free(path); + ret = hal_codec_release(gHalHandle); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); } /** - * @testcase DecodeMPEG4P - * @since_tizen 6.5 + * @testcase DecodeP + * @since_tizen 9.0 * @author SR(jm80.yang) * @reviewer SR(heechul.jeon) * @type auto - * @description Positive, Decode MPEG4 Decoder Plugin - * @apicovered N/A - * @passcase when MPEG4 decoder decode stream, pipeline can be changed to GST_STATE_PLAYING - * @failcase when the state is not changed to GST_STATE_PLAYING + * @description Positive, Decode buffer + * @apicovered hal_codec_decode + * @passcase when hal_codec_decode returns HAL_CODEC_ERROR_NONE and get decoded buffers + * @failcase when hal_codec_decode does not return HAL_CODEC_ERROR_NONE or decoded buffer is not come * @precondition None * @postcondition None */ -TEST_F(CodecHalTest, DecodeMPEG4P) +TEST_F(CodecHalTest, DecodeP) { - GstStateChangeReturn state_ret; - GstElement *src, *demux, *pipeline; - GstMessage *msg; - GstBus *bus; - gchar *path; - - if (!__is_hw_codec_supported(MPEG4, DECODER)) - return; - - pipeline = gst_pipeline_new("pipeline"); - - src = gst_element_factory_make("filesrc", NULL); - - demux = gst_element_factory_make("qtdemux", NULL); - - bus = gst_element_get_bus(pipeline); + int offset = 0; + int decoded_count = 0; + hal_codec_buffer_s buffer[CONTENTS_H264_FRAME_NUM]; + CODEC_SUPPORT_CHECK; - /* kids, don't use a sync handler for this at home, really; we do because - * we just want to abort and nothing else */ - gst_bus_set_sync_handler(bus, error_cb, (gpointer)"mv.MP4", NULL); + ASSERT_NE(gHalHandle, nullptr); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); - gst_bin_add_many(GST_BIN(pipeline), src, demux, NULL); + ret = hal_codec_configure(gHalHandle, 1920, 1080, HAL_CODEC_FORMAT_H264, HAL_CODEC_FORMAT_NV12, false); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); - gst_element_link(src, demux); + ret = hal_codec_start(gHalHandle, CodecHalTest::MessageCb, (void *)&decoded_count); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); - path = g_build_filename(TEST_FILES_PATH, "mv.MP4", NULL); - GST_INFO("reading file '%s'", path); - g_object_set(src, "location", path, NULL); + ret = GetContents(CONTENTS_H264_PATH); + ASSERT_EQ(ret, 0); - /* can't link uridecodebin and sink yet, do that later */ - g_signal_connect(demux, "pad-added", G_CALLBACK(pad_added_cb), pipeline); + for (uint64_t i = 0 ; i < CONTENTS_H264_FRAME_NUM ; i++) { + memset(&buffer[i], 0x0, sizeof(hal_codec_buffer_s)); - state_ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); - - if (state_ret == GST_STATE_CHANGE_ASYNC) { - GST_INFO("waiting for pipeline to reach PAUSED state"); - state_ret = gst_element_get_state(pipeline, NULL, NULL, -1); - } - - state_ret = gst_element_set_state(pipeline, GST_STATE_PLAYING); - EXPECT_NE(state_ret, GST_STATE_CHANGE_FAILURE); - - GST_INFO("PAUSED, let's decode"); - msg = gst_bus_timed_pop_filtered(bus, 10 * GST_SECOND, GST_MESSAGE_EOS); - GST_INFO("Done, got EOS message"); - - gst_message_unref(msg); - gst_object_unref(bus); - - state_ret = gst_element_set_state(pipeline, GST_STATE_NULL); - EXPECT_EQ(state_ret, GST_STATE_CHANGE_SUCCESS); - gst_object_unref(pipeline); - - g_free(path); -} - -#if 0 -/** - * @testcase EncodeH264P - * @since_tizen 6.5 - * @author SR(jm80.yang) - * @reviewer SR(heechul.jeon) - * @type auto - * @description Positive, Encode H.264 Decoder Plugin - * @apicovered N/A - * @passcase when H.264 encoder encode buffer, outbuffer will be dequed - * @failcase when the state is not changed to GST_STATE_PLAYING or the error occur - * @precondition None - * @postcondition None - */ -TEST_F(CodecHalTest, EncodeH264P) -{ - GstStateChangeReturn state_ret; - GstElement *sink, *src, *codec, *pipeline; - GstMessage *msg; - GstBus *bus; - gchar *path; - gint bus_watch_id; - gulong signal_handoff; - GstBuffer *buffer; - GstAllocator *allocator; - GstMemory *mem; - GstVideoInfo vinfo; - tbm_surface_h surface; - int i; - int ret; - - pipeline = gst_pipeline_new("pipeline"); - - src = gst_element_factory_make("appsrc", NULL); - - codec = gst_element_factory_make(codec_list[H264].plugins[ENCODER], NULL); - - bus = gst_element_get_bus(pipeline); - bus_watch_id = gst_bus_add_watch(bus, bus_callback, NULL); - gst_bin_add_many(GST_BIN(pipeline), src, codec, sink, NULL); - gst_element_link_many(src, codec, sink, NULL); - - signal_handoff = g_signal_connect(sink, "handoff", G_CALLBACK(buffer_add), NULL); - state_ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); - - if (state_ret == GST_STATE_CHANGE_ASYNC) { - GST_INFO("waiting for pipeline to reach PAUSED state"); - state_ret = gst_element_get_state(pipeline, NULL, NULL, -1); - } + buffer[i].size = decode_test_frame_size[i]; + buffer[i].planes.plane[0].data = (unsigned char *)(mappedFileContents_ + offset); + buffer[i].planes.plane[0].size = buffer[i].size; + buffer[i].planes.plane[0].bytesused = buffer[i].size; + buffer[i].meta.timestamp = i * 1000000000; /* ns */ - state_ret = gst_element_set_state(pipeline, GST_STATE_PLAYING); - EXPECT_NE(state_ret, GST_STATE_CHANGE_FAILURE); + cout << " Codec HAL : [" << i << "] decode buffer: size[" << buffer[i].planes.plane[0].bytesused << "]" << endl; - allocator = gst_tizen_allocator_new(); + ret = hal_codec_decode(gHalHandle, &buffer[i]); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); - for (i = 0; i < 5; i++) { - surface = tbm_surface_internal_create_with_flags(640, 480, TBM_FORMAT_NV12, TBM_BO_NONCACHABLE); - mem = gst_tizen_allocator_alloc_surface(allocator, &vinfo, surface, NULL, NULL); - gst_buffer_append_memory(buffer, mem); - ret = gst_app_src_push_buffer((GstAppSrc*)src, buffer); + offset += decode_test_frame_size[i]; } - g_signal_handler_disconnect(sink, signal_handoff); - gst_object_unref(bus); - - state_ret = gst_element_set_state(pipeline, GST_STATE_NULL); - EXPECT_EQ(state_ret, GST_STATE_CHANGE_SUCCESS); - - gst_object_unref(pipeline); -} - -/** - * @testcase EncodeH263P - * @since_tizen 6.5 - * @author SR(jm80.yang) - * @reviewer SR(heechul.jeon) - * @type auto - * @description Positive, Encode H.263 Decoder Plugin - * @apicovered N/A - * @passcase when H.263 encoder encode buffer, outbuffer will be dequed - * @failcase when the state is not changed to GST_STATE_PLAYING or the error occur - * @precondition None - * @postcondition None - */ -TEST_F(CodecHalTest, EncodeH263P) -{ - GstStateChangeReturn state_ret; - GstElement *sink, *src, *codec, *pipeline; - GstMessage *msg; - GstBus *bus; - gchar *path; - gint bus_watch_id; - - pipeline = gst_pipeline_new("pipeline"); - - src = gst_element_factory_make("appsrc", NULL); + usleep(1000000); - codec = gst_element_factory_make(codec_list[H263].plugins[ENCODER], NULL); + ASSERT_NE(decoded_count, 0); - bus = gst_element_get_bus(pipeline); - bus_watch_id = gst_bus_add_watch(bus, bus_callback, NULL); - gst_bin_add_many(GST_BIN(pipeline), src, codec, sink, NULL); - gst_element_link_many(src, codec, sink, NULL); - - state_ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); - - if (state_ret == GST_STATE_CHANGE_ASYNC) { - GST_INFO("waiting for pipeline to reach PAUSED state"); - state_ret = gst_element_get_state(pipeline, NULL, NULL, -1); - } + ReleaseContents(); - state_ret = gst_element_set_state(pipeline, GST_STATE_PLAYING); - EXPECT_NE(state_ret, GST_STATE_CHANGE_FAILURE); + ret = hal_codec_stop(gHalHandle); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); - GST_INFO("PAUSED, let's encode"); - gst_object_unref(bus); - - state_ret = gst_element_set_state(pipeline, GST_STATE_NULL); - EXPECT_EQ(state_ret, GST_STATE_CHANGE_SUCCESS); - gst_object_unref(pipeline); + ret = hal_codec_release(gHalHandle); + ASSERT_EQ(ret, HAL_CODEC_ERROR_NONE); } -/** - * @testcase EncodeMPEG4P - * @since_tizen 6.5 - * @author SR(jm80.yang) - * @reviewer SR(heechul.jeon) - * @type auto - * @description Positive, Encode MPEG4 Decoder Plugin - * @apicovered N/A - * @passcase when MPEG4 encoder encode buffer, outbuffer will be dequed - * @failcase when the state is not changed to GST_STATE_PLAYING or the error occur - * @precondition None - * @postcondition None - */ -TEST_F(CodecHalTest, EncodeMPEG4P) -{ - GstStateChangeReturn state_ret; - GstElement *sink, *src, *codec, *pipeline; - GstMessage *msg; - GstBus *bus; - gchar *path; - gint bus_watch_id; - - pipeline = gst_pipeline_new("pipeline"); - - src = gst_element_factory_make("appsrc", NULL); - - codec = gst_element_factory_make(codec_list[MPEG4].plugins[ENCODER], NULL); - - bus = gst_element_get_bus(pipeline); - bus_watch_id = gst_bus_add_watch(bus, bus_callback, NULL); - gst_bin_add_many(GST_BIN(pipeline), src, codec, sink, NULL); - gst_element_link_many(src, codec, sink, NULL); - - state_ret = gst_element_set_state(pipeline, GST_STATE_PAUSED); - - if (state_ret == GST_STATE_CHANGE_ASYNC) { - GST_INFO("waiting for pipeline to reach PAUSED state"); - state_ret = gst_element_get_state(pipeline, NULL, NULL, -1); - } - - state_ret = gst_element_set_state(pipeline, GST_STATE_PLAYING); - EXPECT_NE(state_ret, GST_STATE_CHANGE_FAILURE); - - GST_INFO("PAUSED, let's encode"); - gst_object_unref(bus); - - state_ret = gst_element_set_state(pipeline, GST_STATE_NULL); - EXPECT_EQ(state_ret, GST_STATE_CHANGE_SUCCESS); - gst_object_unref(pipeline); -} -#endif int main(int argc, char **argv) { - int codec_num; - dictionary *dict; - - gst_init(&argc, &argv); - dict = iniparser_load(CODEC_INI_DEFAULT_PATH); - - codec_num = sizeof(codec_list) / sizeof(codec_list[0]); - get_plugins_list_from_ini(dict, codec_list, codec_num); - iniparser_freedict(dict); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/tests/res/decode_test.h264 b/tests/res/decode_test.h264 new file mode 100644 index 0000000..42da372 Binary files /dev/null and b/tests/res/decode_test.h264 differ diff --git a/tests/res/meerkat.mp4 b/tests/res/meerkat.mp4 deleted file mode 100644 index 69270dc..0000000 Binary files a/tests/res/meerkat.mp4 and /dev/null differ diff --git a/tests/res/mv.MP4 b/tests/res/mv.MP4 deleted file mode 100644 index 15b0e54..0000000 Binary files a/tests/res/mv.MP4 and /dev/null differ diff --git a/tests/res/she.3gp b/tests/res/she.3gp deleted file mode 100644 index 419d465..0000000 Binary files a/tests/res/she.3gp and /dev/null differ