diff options
author | Linux Build Service Account <lnxbuild@localhost> | 2015-11-21 17:55:54 -0800 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2015-11-21 17:55:54 -0800 |
commit | 418b5fab13b31e10cc954db33b68ddef5b6d0fbb (patch) | |
tree | dede256eb0a757e5b3e4b27baf8090e606328bcb | |
parent | 6e5aa04372146c3a2ab04fdf19b7b18a3f12a4c6 (diff) | |
parent | e592d0a7da065572dafca837edbd2c656852935b (diff) | |
download | android_hardware_qcom_media-418b5fab13b31e10cc954db33b68ddef5b6d0fbb.tar.gz android_hardware_qcom_media-418b5fab13b31e10cc954db33b68ddef5b6d0fbb.tar.bz2 android_hardware_qcom_media-418b5fab13b31e10cc954db33b68ddef5b6d0fbb.zip |
Merge "mm-video: swvdec: Add SwVdec OMX component."
-rw-r--r-- | mm-video-v4l2/vidc/vdec/Android.mk | 26 | ||||
-rw-r--r-- | mm-video-v4l2/vidc/vdec/inc/omx_swvdec.h | 459 | ||||
-rw-r--r-- | mm-video-v4l2/vidc/vdec/inc/omx_swvdec_utils.h | 179 | ||||
-rw-r--r-- | mm-video-v4l2/vidc/vdec/src/omx_swvdec.cpp | 5835 | ||||
-rw-r--r-- | mm-video-v4l2/vidc/vdec/src/omx_swvdec_utils.cpp | 461 |
5 files changed, 6960 insertions, 0 deletions
diff --git a/mm-video-v4l2/vidc/vdec/Android.mk b/mm-video-v4l2/vidc/vdec/Android.mk index 0d27319f..f741e88c 100644 --- a/mm-video-v4l2/vidc/vdec/Android.mk +++ b/mm-video-v4l2/vidc/vdec/Android.mk @@ -31,6 +31,7 @@ TARGETS_THAT_HAVE_VENUS_HEVC := apq8084 msm8994 msm8996 TARGETS_THAT_NEED_HEVC_LIB := msm8974 msm8610 msm8226 msm8916 TARGETS_THAT_NEED_SW_HEVC := msm8974 msm8226 msm8916 TARGETS_THAT_SUPPORT_UBWC := msm8996 +TARGETS_THAT_NEED_SW_VDEC := msm8937 ifeq ($(call is-board-platform-in-list, $(TARGETS_THAT_USE_HEVC_ADSP_HEAP)),true) libmm-vdec-def += -D_HEVC_USE_ADSP_HEAP_ @@ -74,6 +75,7 @@ libmm-vdec-inc += $(TOP)/frameworks/native/include/media/hardware libmm-vdec-inc += $(TOP)/hardware/qcom/media/libc2dcolorconvert libmm-vdec-inc += $(TOP)/frameworks/av/include/media/stagefright libmm-vdec-inc += $(TARGET_OUT_HEADERS)/mm-video/SwVdec +libmm-vdec-inc += $(TARGET_OUT_HEADERS)/mm-video/swvdec libmm-vdec-inc += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include ifeq ($(PLATFORM_SDK_VERSION), 18) #JB_MR2 @@ -162,7 +164,31 @@ LOCAL_SRC_FILES += src/hevc_utils.cpp LOCAL_STATIC_LIBRARIES := libOmxVidcCommon include $(BUILD_SHARED_LIBRARY) +endif +endif + +# --------------------------------------------------------------------------------- +# Make the Shared library (libOmxSwVdec) +# --------------------------------------------------------------------------------- + +include $(CLEAR_VARS) +ifneq "$(wildcard $(QCPATH) )" "" +ifeq ($(call is-board-platform-in-list, $(TARGETS_THAT_NEED_SW_VDEC)),true) + +LOCAL_MODULE := libOmxSwVdec +LOCAL_MODULE_TAGS := optional +LOCAL_CFLAGS := $(libmm-vdec-def) +LOCAL_C_INCLUDES += $(libmm-vdec-inc) +LOCAL_ADDITIONAL_DEPENDENCIES := $(libmm-vdec-add-dep) +LOCAL_PRELINK_MODULE := false +LOCAL_SHARED_LIBRARIES := liblog libcutils +LOCAL_SHARED_LIBRARIES += libswvdec + +LOCAL_SRC_FILES := src/omx_swvdec.cpp +LOCAL_SRC_FILES += src/omx_swvdec_utils.cpp + +include $(BUILD_SHARED_LIBRARY) endif endif diff --git a/mm-video-v4l2/vidc/vdec/inc/omx_swvdec.h b/mm-video-v4l2/vidc/vdec/inc/omx_swvdec.h new file mode 100644 index 00000000..78aae672 --- /dev/null +++ b/mm-video-v4l2/vidc/vdec/inc/omx_swvdec.h @@ -0,0 +1,459 @@ +/** + * @copyright + * + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * @file + * + * omx_swvdec.h + * + * @brief + * + * OMX software video decoder component header. + */ + +#ifndef _OMX_SWVDEC_H_ +#define _OMX_SWVDEC_H_ + +#include <pthread.h> +#include <semaphore.h> + +#include <linux/msm_ion.h> +#include <linux/msm_vidc_dec.h> + +#include "qc_omx_component.h" + +#include "omx_swvdec_utils.h" + +#include "swvdec_types.h" + +using namespace android; + +/// OMX SwVdec version date +#define OMX_SWVDEC_VERSION_DATE "2015-11-09T18:33:31+0530" + +#define OMX_SPEC_VERSION 0x00000101 ///< OMX specification version + +#define OMX_SWVDEC_NUM_INSTANCES 1 ///< number of OMX SwVdec instances + +// @todo Make this macro default and store in a variable? +#define OMX_SWVDEC_IP_BUFFER_COUNT 5 ///< OMX SwVdec input buffer count + +/// frame rate structure +typedef struct { + unsigned int fps_numerator; ///< fps numerator + unsigned int fps_denominator; ///< fps denominator +} FRAME_RATE; + +#define DEFAULT_FPS_NUMERATOR 30 ///< default fps numerator +#define DEFAULT_FPS_DENOMINATOR 1 ///< default fps denominator + +/// frame dimensions structure +typedef struct { + unsigned int width; ///< frame width + unsigned int height; ///< frame height +} FRAME_DIMENSIONS; + +/// frame attributes structure +typedef struct { + unsigned int stride; ///< frame stride + unsigned int scanlines; ///< frame scanlines + unsigned int size; ///< frame size +} FRAME_ATTRIBUTES; + +/// asynchronous thread structure +typedef struct { + sem_t sem_thread_created; ///< thread created semaphore + sem_t sem_event; ///< event semaphore + pthread_t handle; ///< thread handle + bool created; ///< thread created? + bool exit; ///< thread exit variable +} ASYNC_THREAD; + +/// @cond + +struct vdec_ion { + int ion_fd_device; + struct ion_fd_data ion_fd_data; + struct ion_allocation_data ion_alloc_data; +}; + +typedef struct { + OMX_BUFFERHEADERTYPE buffer_header; + struct vdec_ion ion_info; + struct vdec_bufferpayload buffer_payload; + SWVDEC_BUFFER buffer_swvdec; + bool buffer_populated; +} OMX_SWVDEC_BUFFER_INFO; + +/// @endcond + +/// port structure +typedef struct { + OMX_PARAM_PORTDEFINITIONTYPE def; ///< definition + OMX_BOOL enabled; ///< enabled? + OMX_BOOL populated; ///< populated? + OMX_BOOL unpopulated; ///< unpopulated? + OMX_BOOL flush_inprogress; ///< flush inprogress? + unsigned int num_pending_buffers; ///< # of pending buffers +} OMX_SWVDEC_PORT; + +/// meta_buffer information structure +typedef struct { + unsigned int fd; ///< file descriptor + unsigned int dup_fd; ///< duplicate file descriptor + unsigned int offset; ///< offset + unsigned int ref_count; ///< reference count +} OMX_SWVDEC_META_BUFFER_INFO; + +#define DEFAULT_FRAME_WIDTH 1920 ///< default frame width +#define DEFAULT_FRAME_HEIGHT 1088 ///< default frame height + +#define DEFAULT_ALIGNMENT_STRIDE 128 ///< default stride alignment +#define DEFAULT_ALIGNMENT_SCANLINES_Y 32 ///< default Y scanlines alignment +#define DEFAULT_ALIGNMENT_SCANLINES_UV 16 ///< default UV scanlines alignment +#define DEFAULT_ALIGNMENT_SIZE 4096 ///< default size alignment + +#define MAX(x, y) (((x) > (y)) ? (x) : (y)) ///< maximum +#define MIN(x, y) (((x) < (y)) ? (x) : (y)) ///< minimum +#define ALIGN(x, y) (((x) + ((y) - 1)) & (~((y) - 1))) + ///< align 'x' to next highest multiple of 'y' + +/// macro to print 'command type' string +#define OMX_COMMANDTYPE_STRING(x) \ + ((x == OMX_CommandStateSet) ? "OMX_CommandStateSet" : \ + ((x == OMX_CommandFlush) ? "OMX_CommandFlush" : \ + ((x == OMX_CommandPortDisable) ? "OMX_CommandPortDisable" : \ + ((x == OMX_CommandPortEnable) ? "OMX_CommandPortEnable" : \ + "unknown")))) + +/// macro to print 'state type' string +#define OMX_STATETYPE_STRING(x) \ + ((x == OMX_StateInvalid) ? "OMX_StateInvalid" : \ + ((x == OMX_StateLoaded) ? "OMX_StateLoaded" : \ + ((x == OMX_StateIdle) ? "OMX_StateIdle" : \ + ((x == OMX_StateExecuting) ? "OMX_StateExecuting" : \ + ((x == OMX_StatePause) ? "OMX_StatePause" : \ + ((x == OMX_StateWaitForResources) ? "OMX_StateWaitForResources" : \ + "unknown")))))) + +enum { + OMX_CORE_PORT_INDEX_IP = 0, ///< input port index + OMX_CORE_PORT_INDEX_OP = 1 ///< output port index +}; + +extern "C" { + OMX_API void *get_omx_component_factory_fn(void); +}; + +/// OMX SwVdec component class; derived from QC OMX component base class +class omx_swvdec : public qc_omx_component +{ +public: + + omx_swvdec(); + + virtual ~omx_swvdec(); + + // derived class versions of base class pure virtual functions + + OMX_ERRORTYPE component_init(OMX_STRING cmp_name); + OMX_ERRORTYPE component_deinit(OMX_HANDLETYPE cmp_handle); + OMX_ERRORTYPE get_component_version(OMX_HANDLETYPE cmp_handle, + OMX_STRING cmp_name, + OMX_VERSIONTYPE *p_cmp_version, + OMX_VERSIONTYPE *p_spec_version, + OMX_UUIDTYPE *p_cmp_UUID); + OMX_ERRORTYPE send_command(OMX_HANDLETYPE cmp_handle, + OMX_COMMANDTYPE cmd, + OMX_U32 param, + OMX_PTR p_cmd_data); + OMX_ERRORTYPE get_parameter(OMX_HANDLETYPE cmp_handle, + OMX_INDEXTYPE param_index, + OMX_PTR p_param_data); + OMX_ERRORTYPE set_parameter(OMX_HANDLETYPE cmp_handle, + OMX_INDEXTYPE param_index, + OMX_PTR p_param_data); + OMX_ERRORTYPE get_config(OMX_HANDLETYPE cmp_handle, + OMX_INDEXTYPE config_index, + OMX_PTR p_config_data); + OMX_ERRORTYPE set_config(OMX_HANDLETYPE cmp_handle, + OMX_INDEXTYPE config_index, + OMX_PTR p_config_data); + OMX_ERRORTYPE get_extension_index(OMX_HANDLETYPE cmp_handle, + OMX_STRING param_name, + OMX_INDEXTYPE *p_index_type); + OMX_ERRORTYPE get_state(OMX_HANDLETYPE cmp_handle, + OMX_STATETYPE *p_state); + OMX_ERRORTYPE component_tunnel_request(OMX_HANDLETYPE cmp_handle, + OMX_U32 port, + OMX_HANDLETYPE peer_component, + OMX_U32 peer_port, + OMX_TUNNELSETUPTYPE *p_tunnel_setup); + OMX_ERRORTYPE use_buffer(OMX_HANDLETYPE cmp_handle, + OMX_BUFFERHEADERTYPE **pp_buffer_hdr, + OMX_U32 port, + OMX_PTR p_app_data, + OMX_U32 bytes, + OMX_U8 *p_buffer); + OMX_ERRORTYPE allocate_buffer(OMX_HANDLETYPE cmp_handle, + OMX_BUFFERHEADERTYPE **pp_buffer_hdr, + OMX_U32 port, + OMX_PTR p_app_data, + OMX_U32 bytes); + OMX_ERRORTYPE free_buffer(OMX_HANDLETYPE cmp_handle, + OMX_U32 port, + OMX_BUFFERHEADERTYPE *p_buffer); + OMX_ERRORTYPE empty_this_buffer(OMX_HANDLETYPE cmp_handle, + OMX_BUFFERHEADERTYPE *p_buffer_hdr); + OMX_ERRORTYPE fill_this_buffer(OMX_HANDLETYPE cmp_handle, + OMX_BUFFERHEADERTYPE *p_buffer_hdr); + OMX_ERRORTYPE set_callbacks(OMX_HANDLETYPE cmp_handle, + OMX_CALLBACKTYPE *p_callbacks, + OMX_PTR p_app_data); + OMX_ERRORTYPE use_EGL_image(OMX_HANDLETYPE cmp_handle, + OMX_BUFFERHEADERTYPE **pp_buffer_hdr, + OMX_U32 port, + OMX_PTR p_app_data, + void *egl_image); + OMX_ERRORTYPE component_role_enum(OMX_HANDLETYPE cmp_handle, + OMX_U8 *p_role, + OMX_U32 index); + + // SwVdec callback functions + + static SWVDEC_STATUS swvdec_empty_buffer_done_callback( + SWVDEC_HANDLE swvdec_handle, + SWVDEC_BUFFER *p_buffer_ip, + void *p_client_handle); + static SWVDEC_STATUS swvdec_fill_buffer_done_callback( + SWVDEC_HANDLE swvdec_handle, + SWVDEC_BUFFER *p_buffer_op, + void *p_client_handle); + static SWVDEC_STATUS swvdec_event_handler_callback( + SWVDEC_HANDLE swvdec_handle, + SWVDEC_EVENT event, + void *p_data, + void *p_client_handle); + +private: + + OMX_STATETYPE m_state; ///< component state + + unsigned int m_status_flags; ///< status flags + + char m_cmp_name[OMX_MAX_STRINGNAME_SIZE]; ///< component name + char m_role_name[OMX_MAX_STRINGNAME_SIZE]; ///< component role name + + SWVDEC_CODEC m_swvdec_codec; ///< SwVdec codec type + SWVDEC_HANDLE m_swvdec_handle; ///< SwVdec handle + bool m_swvdec_created; ///< SwVdec created? + + OMX_VIDEO_CODINGTYPE m_omx_video_codingtype; ///< OMX video coding type + OMX_COLOR_FORMATTYPE m_omx_color_formattype; ///< OMX color format type + + FRAME_RATE m_frame_rate; ///< frame rate + FRAME_DIMENSIONS m_frame_dimensions; ///< frame dimensions + FRAME_ATTRIBUTES m_frame_attributes; ///< frame attributes + + ASYNC_THREAD m_async_thread; ///< asynchronous thread + + omx_swvdec_queue m_queue_command; ///< command queue + omx_swvdec_queue m_queue_port_ip; ///< input port queue for ETBs & EBDs + omx_swvdec_queue m_queue_port_op; ///< output port queue for FTBs & FBDs + + OMX_SWVDEC_PORT m_port_ip; ///< input port + OMX_SWVDEC_PORT m_port_op; ///< output port + + OMX_CALLBACKTYPE m_callback; ///< IL client callback structure + OMX_PTR m_app_data; ///< IL client app data pointer + + OMX_PRIORITYMGMTTYPE m_prio_mgmt; ///< priority management + + bool m_sync_frame_decoding_mode; ///< sync frame decoding mode enabled? + bool m_android_native_buffers; ///< android native buffers enabled? + bool m_meta_buffer_mode; ///< meta buffer mode enabled? + + bool m_port_reconfig_inprogress; ///< port reconfiguration in progress? + + sem_t m_sem_cmd; ///< semaphore for command processing + + OMX_SWVDEC_BUFFER_INFO *m_buffer_array_ip; ///< input buffer info array + OMX_SWVDEC_BUFFER_INFO *m_buffer_array_op; ///< output buffer info array + + OMX_SWVDEC_META_BUFFER_INFO *m_meta_buffer_array; ///< metabuffer info array + pthread_mutex_t m_meta_buffer_array_mutex; + ///< mutex for metabuffer info array + + omx_swvdec_ts_list m_ts_list; ///< timestamp list + + omx_swvdec_diag m_diag; ///< diagnostics class variable + + OMX_ERRORTYPE set_frame_dimensions(unsigned int width, + unsigned int height); + OMX_ERRORTYPE set_frame_attributes(unsigned int alignment_stride, + unsigned int alignment_scanlines_y, + unsigned int alignment_scanlines_uv, + unsigned int alignment_size); + + OMX_ERRORTYPE get_video_port_format( + OMX_VIDEO_PARAM_PORTFORMATTYPE *p_port_format); + OMX_ERRORTYPE set_video_port_format( + OMX_VIDEO_PARAM_PORTFORMATTYPE *p_port_format); + + OMX_ERRORTYPE get_port_definition(OMX_PARAM_PORTDEFINITIONTYPE *p_port_def); + OMX_ERRORTYPE set_port_definition(OMX_PARAM_PORTDEFINITIONTYPE *p_port_def); + + OMX_ERRORTYPE get_supported_profilelevel( + OMX_VIDEO_PARAM_PROFILELEVELTYPE *p_profilelevel); + + OMX_ERRORTYPE describe_color_format(DescribeColorFormatParams *p_params); + + OMX_ERRORTYPE set_port_definition_qcom( + OMX_QCOM_PARAM_PORTDEFINITIONTYPE *p_port_def); + + // functions to set SwVdec properties with OMX component properties + + OMX_ERRORTYPE set_frame_dimensions_swvdec(); + OMX_ERRORTYPE set_frame_attributes_swvdec(); + + // functions to get SwVdec properties and set OMX component properties + + OMX_ERRORTYPE get_frame_dimensions_swvdec(); + OMX_ERRORTYPE get_frame_attributes_swvdec(); + OMX_ERRORTYPE get_buffer_requirements_swvdec(unsigned int port_index); + + // buffer allocation & de-allocation functions + OMX_ERRORTYPE buffer_allocate_ip(OMX_BUFFERHEADERTYPE **pp_buffer_hdr, + OMX_PTR p_app_data, + OMX_U32 size); + OMX_ERRORTYPE buffer_allocate_op(OMX_BUFFERHEADERTYPE **pp_buffer_hdr, + OMX_PTR p_app_data, + OMX_U32 size); + OMX_ERRORTYPE buffer_allocate_ip_info_array(); + OMX_ERRORTYPE buffer_allocate_op_info_array(); + OMX_ERRORTYPE buffer_use_op(OMX_BUFFERHEADERTYPE **pp_buffer_hdr, + OMX_PTR p_app_data, + OMX_U32 size, + OMX_U8 *p_buffer); + OMX_ERRORTYPE buffer_deallocate_ip(OMX_BUFFERHEADERTYPE *p_buffer_hdr); + OMX_ERRORTYPE buffer_deallocate_op(OMX_BUFFERHEADERTYPE *p_buffer_hdr); + void buffer_deallocate_ip_info_array(); + void buffer_deallocate_op_info_array(); + + OMX_ERRORTYPE meta_buffer_array_allocate(); + void meta_buffer_array_deallocate(); + void meta_buffer_ref_add(unsigned int index, + unsigned int fd, + unsigned int offset); + void meta_buffer_ref_remove(unsigned int fd, unsigned int offset); + + OMX_BOOL port_ip_populated(); + OMX_BOOL port_op_populated(); + + OMX_ERRORTYPE flush(unsigned int port_index); + + int ion_memory_alloc_map(struct ion_allocation_data *p_alloc_data, + struct ion_fd_data *p_fd_data, + OMX_U32 size, + OMX_U32 alignment); + void ion_memory_free(struct vdec_ion *p_ion_buf_info); + + // component callback functions + + void swvdec_empty_buffer_done(SWVDEC_BUFFER *p_buffer_ip); + void swvdec_fill_buffer_done(SWVDEC_BUFFER *p_buffer_op); + void swvdec_event_handler(SWVDEC_EVENT event, void *p_data); + + OMX_ERRORTYPE retval_swvdec2omx(SWVDEC_STATUS retval_swvdec); + + // status bits for pending events + enum { + PENDING_STATE_LOADED_TO_IDLE, ///< loaded to idle state + PENDING_STATE_EXECUTING_TO_IDLE, ///< executing to idle state + PENDING_STATE_IDLE_TO_LOADED, ///< idle to loaded state + PENDING_PORT_ENABLE_IP, ///< enablement of ip port + PENDING_PORT_ENABLE_OP, ///< enablement of op port + PENDING_PORT_DISABLE_IP, ///< disablement of ip port + PENDING_PORT_DISABLE_OP, ///< disablement of op port + PENDING_PORT_FLUSH_IP, ///< flush of ip port + PENDING_PORT_FLUSH_OP ///< flush of op port + }; + + // events raised internally + enum { + OMX_SWVDEC_EVENT_CMD, ///< command event + OMX_SWVDEC_EVENT_CMD_ACK, ///< command acknowledgement + OMX_SWVDEC_EVENT_ERROR, ///< error event + OMX_SWVDEC_EVENT_ETB, ///< ETB event + OMX_SWVDEC_EVENT_EBD, ///< EBD event + OMX_SWVDEC_EVENT_FTB, ///< FTB event + OMX_SWVDEC_EVENT_FBD, ///< FBD event + OMX_SWVDEC_EVENT_EOS, ///< EOS event + OMX_SWVDEC_EVENT_FLUSH_PORT_IP, ///< flush ip port event + OMX_SWVDEC_EVENT_FLUSH_PORT_OP, ///< flush op port event + OMX_SWVDEC_EVENT_PORT_RECONFIG ///< port reconfig event + }; + + OMX_ERRORTYPE async_thread_create(); + void async_thread_destroy(); + + static void async_thread(void *p_cmp); + + bool async_post_event(unsigned long event_id, + unsigned long event_param1, + unsigned long event_param2); + + static void async_process_event(void *p_cmp); + + OMX_ERRORTYPE async_process_event_cmd(OMX_COMMANDTYPE cmd, OMX_U32 param); + OMX_ERRORTYPE async_process_event_cmd_ack(OMX_COMMANDTYPE cmd, + OMX_U32 param); + OMX_ERRORTYPE async_process_event_error(OMX_ERRORTYPE error_code); + OMX_ERRORTYPE async_process_event_cmd_state_set(bool *p_cmd_ack, + OMX_STATETYPE state_new); + OMX_ERRORTYPE async_process_event_cmd_flush(unsigned int port_index); + OMX_ERRORTYPE async_process_event_cmd_port_disable( + bool *p_cmd_ack, + unsigned int port_index); + OMX_ERRORTYPE async_process_event_cmd_port_enable(bool *p_cmd_ack, + unsigned int port_index); + OMX_ERRORTYPE async_process_event_etb(OMX_BUFFERHEADERTYPE *p_buffer_hdr, + unsigned int index); + OMX_ERRORTYPE async_process_event_ftb(OMX_BUFFERHEADERTYPE *p_buffer_hdr, + unsigned int index); + OMX_ERRORTYPE async_process_event_ebd(OMX_BUFFERHEADERTYPE *p_buffer_hdr, + unsigned int index); + OMX_ERRORTYPE async_process_event_fbd(OMX_BUFFERHEADERTYPE *p_buffer_hdr, + unsigned int index); + OMX_ERRORTYPE async_process_event_eos(); + OMX_ERRORTYPE async_process_event_flush_port_ip(); + OMX_ERRORTYPE async_process_event_flush_port_op(); + OMX_ERRORTYPE async_process_event_port_reconfig(); +}; + +#endif // #ifndef _OMX_SWVDEC_H_ diff --git a/mm-video-v4l2/vidc/vdec/inc/omx_swvdec_utils.h b/mm-video-v4l2/vidc/vdec/inc/omx_swvdec_utils.h new file mode 100644 index 00000000..acc8cc95 --- /dev/null +++ b/mm-video-v4l2/vidc/vdec/inc/omx_swvdec_utils.h @@ -0,0 +1,179 @@ +/** + * @copyright + * + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * @file + * + * omx_swvdec_utils.h + * + * @brief + * + * OMX software video decoder utility functions header. + */ + +#ifndef _OMX_SWVDEC_UTILS_H_ +#define _OMX_SWVDEC_UTILS_H_ + +#include <pthread.h> + +#include <cutils/log.h> + +extern unsigned int g_omx_swvdec_logmask; + ///< global OMX SwVdec logmask variable extern declaration + +void omx_swvdec_log_init(); + +#define OMX_SWVDEC_LOGMASK_LOW 4 ///< 100: logmask for low priority logs +#define OMX_SWVDEC_LOGMASK_HIGH 2 ///< 010: logmask for high priority logs +#define OMX_SWVDEC_LOGMASK_ERROR 1 ///< 001: logmask for error priority logs + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "OMX_SWVDEC" ///< OMX SwVdec log tag + +/// low priority log message +#define OMX_SWVDEC_LOG_LOW(string, ...) \ + do { \ + if (g_omx_swvdec_logmask & OMX_SWVDEC_LOGMASK_LOW) \ + ALOGD("--- %s(): " string, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) + +/// high priority log message +#define OMX_SWVDEC_LOG_HIGH(string, ...) \ + do { \ + if (g_omx_swvdec_logmask & OMX_SWVDEC_LOGMASK_HIGH) \ + ALOGI("--- %s(): " string, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) + +/// error priority log message +#define OMX_SWVDEC_LOG_ERROR(string, ...) \ + do { \ + if (g_omx_swvdec_logmask & OMX_SWVDEC_LOGMASK_ERROR) \ + ALOGE("!!! %s(): " string, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) + +/// high priority log message for OMX SwVdec API calls +#define OMX_SWVDEC_LOG_API(string, ...) \ + do { \ + if (g_omx_swvdec_logmask & OMX_SWVDEC_LOGMASK_HIGH) \ + ALOGI(">>> %s(): " string, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) + +/// high priority log message for OMX SwVdec callbacks +#define OMX_SWVDEC_LOG_CALLBACK(string, ...) \ + do { \ + if (g_omx_swvdec_logmask & OMX_SWVDEC_LOGMASK_HIGH) \ + ALOGI("<<< %s(): " string, __FUNCTION__, ##__VA_ARGS__); \ + } while (0) + +#define OMX_SWVDEC_QUEUE_ELEMENTS 100 ///< number of elements in queue + +/// OMX SwVdec event information structure +typedef struct { + unsigned long event_id; ///< event ID + unsigned long event_param1; ///< event parameter 1 + unsigned long event_param2; ///< event parameter 2 +} OMX_SWVDEC_EVENT_INFO; + +/// OMX SwVdec queue class +class omx_swvdec_queue +{ +public: + omx_swvdec_queue(); + ~omx_swvdec_queue(); + + bool push(OMX_SWVDEC_EVENT_INFO *p_event_info); + bool pop(OMX_SWVDEC_EVENT_INFO *p_event_info); + +private: + OMX_SWVDEC_EVENT_INFO m_queue[OMX_SWVDEC_QUEUE_ELEMENTS]; + ///< event queue + unsigned int m_count_total; ///< count of total elements + unsigned int m_count_filled; ///< count of filled elements + unsigned int m_index_write; ///< queue index for writing + unsigned int m_index_read; ///< queue index for reading + pthread_mutex_t m_mutex; ///< mutex for queue access +}; + +#define OMX_SWVDEC_TS_LIST_ELEMENTS 100 + ///< number of elements in timestamp list + +/// OMX SwVdec timestamp element structure. +typedef struct { + bool filled; ///< element filled? + long long timestamp; ///< timestamp +} OMX_SWVDEC_TS_ELEMENT; + +/// OMX SwVdec timestamp list class +class omx_swvdec_ts_list +{ +public: + omx_swvdec_ts_list(); + ~omx_swvdec_ts_list(); + + void reset(); + bool push(long long timestamp); + bool pop(long long *p_timestamp); + +private: + OMX_SWVDEC_TS_ELEMENT m_list[OMX_SWVDEC_TS_LIST_ELEMENTS]; + ///< list of timestamp elements + int m_count_filled; ///< count of filled elements + pthread_mutex_t m_mutex; ///< mutex for list access +}; + +#define DIAG_FILENAME_IP "/data/misc/media/input.bin" ///< input filename +#define DIAG_FILENAME_OP "/data/misc/media/output.yuv" ///< output filename + +/// OMX SwVdec diagnostics class +class omx_swvdec_diag +{ +public: + omx_swvdec_diag(); + ~omx_swvdec_diag(); + + void dump_ip(unsigned char *p_buffer, unsigned int filled_length); + void dump_op(unsigned char *p_buffer, + unsigned int width, + unsigned int height, + unsigned int stride, + unsigned int scanlines); + +private: + unsigned int m_dump_ip; ///< dump input bitstream + unsigned int m_dump_op; ///< dump output YUV + + char *m_filename_ip; ///< input filename string + char *m_filename_op; ///< output filename string + + FILE *m_file_ip; ///< input file handle + FILE *m_file_op; ///< output file handle +}; + +#endif // #ifndef _OMX_SWVDEC_UTILS_H_ diff --git a/mm-video-v4l2/vidc/vdec/src/omx_swvdec.cpp b/mm-video-v4l2/vidc/vdec/src/omx_swvdec.cpp new file mode 100644 index 00000000..54c1df66 --- /dev/null +++ b/mm-video-v4l2/vidc/vdec/src/omx_swvdec.cpp @@ -0,0 +1,5835 @@ +/** + * @copyright + * + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * @file + * + * omx_swvdec.cpp + * + * @brief + * + * OMX software video decoder component source. + */ + +#include <assert.h> +#include <fcntl.h> +#include <sys/mman.h> + +#include <media/hardware/HardwareAPI.h> +#include <gralloc_priv.h> + +#include "OMX_QCOMExtns.h" + +#include "omx_swvdec.h" + +#include "swvdec_api.h" + +/** + * ---------------- + * PUBLIC FUNCTIONS + * ---------------- + */ + +/** + * @brief Create & return component class instance. + * + * @retval Pointer to new component class instance. + */ +void *get_omx_component_factory_fn(void) +{ + return new omx_swvdec; +} + +/** + * @brief Component constructor. + */ +omx_swvdec::omx_swvdec(): + m_state(OMX_StateInvalid), + m_status_flags(0), + m_swvdec_codec(SWVDEC_CODEC_INVALID), + m_swvdec_handle(NULL), + m_swvdec_created(false), + m_omx_video_codingtype(OMX_VIDEO_CodingUnused), + m_omx_color_formattype(OMX_COLOR_FormatUnused), + m_sync_frame_decoding_mode(false), + m_android_native_buffers(false), + m_meta_buffer_mode(false), + m_port_reconfig_inprogress(false), + m_buffer_array_ip(NULL), + m_buffer_array_op(NULL), + m_meta_buffer_array(NULL) +{ + // memset all member variables that are composite structures + memset(&m_cmp, 0, sizeof(m_cmp)); // part of base class + memset(&m_cmp_name[0], 0, sizeof(m_cmp_name)); + memset(&m_role_name[0], 0, sizeof(m_role_name)); + memset(&m_frame_rate, 0, sizeof(m_frame_rate)); + memset(&m_frame_dimensions, 0, sizeof(m_frame_dimensions)); + memset(&m_frame_attributes, 0, sizeof(m_frame_attributes)); + memset(&m_async_thread, 0, sizeof(m_async_thread)); + memset(&m_port_ip, 0, sizeof(m_port_ip)); + memset(&m_port_op, 0, sizeof(m_port_op)); + memset(&m_callback, 0, sizeof(m_callback)); + memset(&m_app_data, 0, sizeof(m_app_data)); + memset(&m_prio_mgmt, 0, sizeof(m_prio_mgmt)); + memset(&m_sem_cmd, 0, sizeof(m_sem_cmd)); + memset(&m_meta_buffer_array_mutex, 0, sizeof(m_meta_buffer_array_mutex)); + + // null-terminate component name & role name strings + m_cmp_name[0] = '\0'; + m_role_name[0] = '\0'; + + // ports are enabled & unpopulated by default + m_port_ip.enabled = OMX_TRUE; + m_port_op.enabled = OMX_TRUE; + m_port_ip.unpopulated = OMX_TRUE; + m_port_op.unpopulated = OMX_TRUE; +} + +/** + * @brief Component destructor. + */ +omx_swvdec::~omx_swvdec() +{ +} + +/** + * @brief Initialize component. + * + * @param[in] cmp_name: Component name string. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::component_init(OMX_STRING cmp_name) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + OMX_SWVDEC_LOG_API("'%s', version date: %s", + cmp_name, + OMX_SWVDEC_VERSION_DATE); + + omx_swvdec_log_init(); + + if (m_state != OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("disallowed in state %s", + OMX_STATETYPE_STRING(m_state)); + retval = OMX_ErrorIncorrectStateOperation; + goto component_init_exit; + } + + // set up codec type variables based on component name string + + if (!strncmp(cmp_name, + "OMX.qti.video.decoder.mpeg4sw", + OMX_MAX_STRINGNAME_SIZE)) + { + OMX_SWVDEC_LOG_LOW("'video_decoder.mpeg4'"); + + strlcpy(m_cmp_name, cmp_name, OMX_MAX_STRINGNAME_SIZE); + strlcpy(m_role_name, "video_decoder.mpeg4", OMX_MAX_STRINGNAME_SIZE); + + m_swvdec_codec = SWVDEC_CODEC_MPEG4; + m_omx_video_codingtype = OMX_VIDEO_CodingMPEG4; + } + else if (!strncmp(cmp_name, + "OMX.qti.video.decoder.h263sw", + OMX_MAX_STRINGNAME_SIZE)) + { + OMX_SWVDEC_LOG_LOW("video_decoder.h263"); + + strlcpy(m_cmp_name, cmp_name, OMX_MAX_STRINGNAME_SIZE); + strlcpy(m_role_name, "video_decoder.h263", OMX_MAX_STRINGNAME_SIZE); + + m_swvdec_codec = SWVDEC_CODEC_H263; + m_omx_video_codingtype = OMX_VIDEO_CodingH263; + } + else if (((!strncmp(cmp_name, + "OMX.qti.video.decoder.divxsw", + OMX_MAX_STRINGNAME_SIZE))) || + ((!strncmp(cmp_name, + "OMX.qti.video.decoder.divx4sw", + OMX_MAX_STRINGNAME_SIZE)))) + { + OMX_SWVDEC_LOG_LOW("video_decoder.divx"); + + strlcpy(m_cmp_name, cmp_name, OMX_MAX_STRINGNAME_SIZE); + strlcpy(m_role_name, "video_decoder.divx", OMX_MAX_STRINGNAME_SIZE); + + m_swvdec_codec = SWVDEC_CODEC_MPEG4; + m_omx_video_codingtype = ((OMX_VIDEO_CODINGTYPE) QOMX_VIDEO_CodingDivx); + } + else + { + OMX_SWVDEC_LOG_ERROR("'%s': invalid component name", cmp_name); + retval = OMX_ErrorInvalidComponentName; + goto component_init_exit; + } + + m_omx_color_formattype = + (OMX_COLOR_FORMATTYPE) OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m; + + m_frame_rate.fps_numerator = DEFAULT_FPS_NUMERATOR; + m_frame_rate.fps_denominator = DEFAULT_FPS_DENOMINATOR; + + { + SWVDEC_CALLBACK callback; + + SWVDEC_STATUS retval_swvdec; + + // initialize SwVdec core library + + callback.pfn_empty_buffer_done = swvdec_empty_buffer_done_callback; + callback.pfn_fill_buffer_done = swvdec_fill_buffer_done_callback; + callback.pfn_event_notification = swvdec_event_handler_callback; + callback.p_client = this; + + if ((retval_swvdec = swvdec_init(&m_swvdec_handle, + m_swvdec_codec, + &callback)) != + SWVDEC_STATUS_SUCCESS) + { + retval = retval_swvdec2omx(retval_swvdec); + goto component_init_exit; + } + + m_swvdec_created = true; + + // set frame dimensions for OMX component & SwVdec core + if ((retval = set_frame_dimensions(DEFAULT_FRAME_WIDTH, + DEFAULT_FRAME_HEIGHT)) != + OMX_ErrorNone) + { + goto component_init_exit; + } + + // set frame attributes for OMX component & SwVdec core + if ((retval = set_frame_attributes(DEFAULT_ALIGNMENT_STRIDE, + DEFAULT_ALIGNMENT_SCANLINES_Y, + DEFAULT_ALIGNMENT_SCANLINES_UV, + DEFAULT_ALIGNMENT_SIZE)) != + OMX_ErrorNone) + { + goto component_init_exit; + } + } + + // get SwVdec buffer requirements for input port; set m_port_ip + if ((retval = get_buffer_requirements_swvdec(OMX_CORE_PORT_INDEX_IP)) != + OMX_ErrorNone) + { + goto component_init_exit; + } + + // get SwVdec buffer requirements for output port; set m_port_op + if ((retval = get_buffer_requirements_swvdec(OMX_CORE_PORT_INDEX_OP)) != + OMX_ErrorNone) + { + goto component_init_exit; + } + + // create callback thread's mutex & condition variable + if ((retval = async_thread_create()) != OMX_ErrorNone) + { + goto component_init_exit; + } + + // create semaphore for command processing + if (sem_init(&m_sem_cmd, 0, 0)) + { + OMX_SWVDEC_LOG_ERROR("failed to create command processing semaphore"); + retval = OMX_ErrorInsufficientResources; + goto component_init_exit; + } + + // create mutex for meta buffer info array + if (pthread_mutex_init(&m_meta_buffer_array_mutex, NULL)) + { + OMX_SWVDEC_LOG_ERROR("failed to create meta buffer info array mutex"); + retval = OMX_ErrorInsufficientResources; + goto component_init_exit; + } + + // move to 'loaded' state + OMX_SWVDEC_LOG_HIGH("OMX_StateInvalid -> OMX_StateLoaded"); + m_state = OMX_StateLoaded; + +component_init_exit: + return retval; +} + +/** + * @brief De-initialize component. + * + * @param[in] cmp_handle: Component handle. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::component_deinit(OMX_HANDLETYPE cmp_handle) +{ + OMX_SWVDEC_LOG_API(""); + + if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + } + + pthread_mutex_destroy(&m_meta_buffer_array_mutex); + + sem_destroy(&m_sem_cmd); + + async_thread_destroy(); + + if (m_swvdec_created) + { + swvdec_deinit(m_swvdec_handle); + m_swvdec_handle = NULL; + } + + OMX_SWVDEC_LOG_HIGH("all done, goodbye!"); + + return OMX_ErrorNone; +} + +/** + * @brief Get component version. + * + * @param[in] cmp_handle: Component handle. + * @param[in] cmp_name: Component name string. + * @param[in,out] p_cmp_version: Pointer to component version variable. + * @param[in,out] p_spec_version: Pointer to OMX spec version variable. + * @param[in,out] p_cmp_UUID: Pointer to component UUID variable. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::get_component_version(OMX_HANDLETYPE cmp_handle, + OMX_STRING cmp_name, + OMX_VERSIONTYPE *p_cmp_version, + OMX_VERSIONTYPE *p_spec_version, + OMX_UUIDTYPE *p_cmp_UUID) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + (void) p_cmp_UUID; + + OMX_SWVDEC_LOG_API(""); + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else if (strncmp(cmp_name, m_cmp_name, sizeof(m_cmp_name))) + { + OMX_SWVDEC_LOG_ERROR("'%s': invalid component name", cmp_name); + retval = OMX_ErrorInvalidComponentName; + } + else if (p_cmp_version == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_cmp_version = NULL"); + retval = OMX_ErrorBadParameter; + } + else if (p_spec_version == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_spec_version = NULL"); + retval = OMX_ErrorBadParameter; + } + else + { + p_spec_version->nVersion = OMX_SPEC_VERSION; + } + +get_component_version_exit: + return retval; +} + +/** + * @brief Send command to component. + * + * @param[in] cmp_handle: Component handle. + * @param[in] cmd: Command. + * @param[in] param: Command parameter. + * @param[in] p_cmd_data: Pointer to command data. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::send_command(OMX_HANDLETYPE cmp_handle, + OMX_COMMANDTYPE cmd, + OMX_U32 param, + OMX_PTR p_cmd_data) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + (void) p_cmd_data; // prevent warning for unused function argument + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + goto send_command_exit; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + goto send_command_exit; + } + + switch (cmd) + { + + case OMX_CommandStateSet: + { + OMX_SWVDEC_LOG_API("%s, %s", + OMX_COMMANDTYPE_STRING(cmd), + OMX_STATETYPE_STRING((OMX_STATETYPE) param)); + break; + } + + case OMX_CommandFlush: + case OMX_CommandPortDisable: + case OMX_CommandPortEnable: + { + OMX_SWVDEC_LOG_API("%s, port index %d", + OMX_COMMANDTYPE_STRING(cmd), + param); + + if ((param != OMX_CORE_PORT_INDEX_IP) && + (param != OMX_CORE_PORT_INDEX_OP) && + (param != OMX_ALL)) + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", param); + retval = OMX_ErrorBadPortIndex; + } + break; + } + + default: + { + OMX_SWVDEC_LOG_API("cmd %d, param %d", cmd, param); + + OMX_SWVDEC_LOG_ERROR("cmd '%d' invalid", cmd); + retval = OMX_ErrorBadParameter; + break; + } + + } // switch (cmd) + + if (retval == OMX_ErrorNone) + { + if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + } + } + + if (retval != OMX_ErrorNone) + { + // command not processed; return error code via event handler callback + async_post_event(OMX_SWVDEC_EVENT_ERROR, retval, 0); + } + else + { + // post command event + async_post_event(OMX_SWVDEC_EVENT_CMD, cmd, param); + + // wait on command semaphore + sem_wait(&m_sem_cmd); + } + +send_command_exit: + return retval; +} + +/** + * @brief Get a parameter from component. + * + * @param[in] cmp_handle: Component handle. + * @param[in] param_index: Parameter index. + * @param[in,out] p_param_data: Pointer to parameter data. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::get_parameter(OMX_HANDLETYPE cmp_handle, + OMX_INDEXTYPE param_index, + OMX_PTR p_param_data) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else if (p_param_data == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_param_data = NULL"); + retval = OMX_ErrorBadParameter; + } + + if (retval != OMX_ErrorNone) + { + goto get_parameter_exit; + } + + switch (param_index) + { + + case OMX_IndexParamAudioInit: + { + OMX_PORT_PARAM_TYPE *p_port_param = + (OMX_PORT_PARAM_TYPE *) p_param_data; + + p_port_param->nPorts = 0; + p_port_param->nStartPortNumber = 0; + + OMX_SWVDEC_LOG_API("OMX_IndexParamAudioInit: " + "%d port(s), start port %d", + p_port_param->nPorts, + p_port_param->nStartPortNumber); + break; + } + + case OMX_IndexParamImageInit: + { + OMX_PORT_PARAM_TYPE *p_port_param = + (OMX_PORT_PARAM_TYPE *) p_param_data; + + p_port_param->nPorts = 0; + p_port_param->nStartPortNumber = 0; + + OMX_SWVDEC_LOG_API("OMX_IndexParamImageInit: " + "%d port(s), start port %d", + p_port_param->nPorts, + p_port_param->nStartPortNumber); + break; + } + + case OMX_IndexParamVideoInit: + { + OMX_PORT_PARAM_TYPE *p_port_param = + (OMX_PORT_PARAM_TYPE *) p_param_data; + + p_port_param->nPorts = 2; + p_port_param->nStartPortNumber = 0; + + OMX_SWVDEC_LOG_API("OMX_IndexParamVideoInit: " + "%d port(s), start port %d", + p_port_param->nPorts, + p_port_param->nStartPortNumber); + break; + } + + case OMX_IndexParamOtherInit: + { + OMX_PORT_PARAM_TYPE *p_port_param = + (OMX_PORT_PARAM_TYPE *) p_param_data; + + p_port_param->nPorts = 0; + p_port_param->nStartPortNumber = 0; + + OMX_SWVDEC_LOG_API("OMX_IndexParamOtherInit: " + "%d port(s), start port %d", + p_port_param->nPorts, + p_port_param->nStartPortNumber); + break; + } + + case OMX_IndexConfigPriorityMgmt: + { + OMX_PRIORITYMGMTTYPE *p_prio_mgmt = + (OMX_PRIORITYMGMTTYPE *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_IndexConfigPriorityMgmt"); + + memcpy(p_prio_mgmt, &m_prio_mgmt, sizeof(OMX_PRIORITYMGMTTYPE)); + break; + } + + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *p_cmp_role = + (OMX_PARAM_COMPONENTROLETYPE *) p_param_data; + + strlcpy((char *) p_cmp_role->cRole, + m_role_name, + OMX_MAX_STRINGNAME_SIZE); + + OMX_SWVDEC_LOG_API("OMX_IndexParamStandardComponentRole: %s", + p_cmp_role->cRole); + break; + } + + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *p_port_def = + (OMX_PARAM_PORTDEFINITIONTYPE *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_IndexParamPortDefinition, port index %d", + p_port_def->nPortIndex); + + retval = get_port_definition(p_port_def); + break; + } + + case OMX_IndexParamCompBufferSupplier: + { + OMX_PARAM_BUFFERSUPPLIERTYPE *p_buffer_supplier = + (OMX_PARAM_BUFFERSUPPLIERTYPE *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_IndexParamCompBufferSupplier, port index %d", + p_buffer_supplier->nPortIndex); + + if ((p_buffer_supplier->nPortIndex == OMX_CORE_PORT_INDEX_IP) || + (p_buffer_supplier->nPortIndex == OMX_CORE_PORT_INDEX_OP)) + { + p_buffer_supplier->eBufferSupplier = OMX_BufferSupplyUnspecified; + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_buffer_supplier->nPortIndex); + retval = OMX_ErrorBadPortIndex; + } + + break; + } + + case OMX_IndexParamVideoPortFormat: + { + OMX_VIDEO_PARAM_PORTFORMATTYPE *p_port_format = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_IndexParamVideoPortFormat, " + "port index %d, index %d", + p_port_format->nPortIndex, + p_port_format->nIndex); + + retval = get_video_port_format(p_port_format); + break; + } + + case OMX_IndexParamVideoMpeg2: + { + OMX_SWVDEC_LOG_ERROR("OMX_IndexParamVideoMpeg2: unsupported"); + retval = OMX_ErrorUnsupportedIndex; + break; + } + + case OMX_IndexParamVideoMpeg4: + { + OMX_SWVDEC_LOG_API("OMX_IndexParamVideoMpeg4: unsupported"); + retval = OMX_ErrorUnsupportedIndex; + break; + } + + case OMX_IndexParamVideoAvc: + { + OMX_SWVDEC_LOG_API("OMX_IndexParamVideoAvc: unsupported"); + retval = OMX_ErrorUnsupportedIndex; + break; + } + + case OMX_IndexParamVideoH263: + { + OMX_SWVDEC_LOG_API("OMX_IndexParamVideoH263: unsupported"); + retval = OMX_ErrorUnsupportedIndex; + break; + } + + case OMX_IndexParamVideoProfileLevelQuerySupported: + { + OMX_VIDEO_PARAM_PROFILELEVELTYPE *p_profilelevel = + (OMX_VIDEO_PARAM_PROFILELEVELTYPE *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_IndexParamVideoProfileLevelQuerySupported, " + "port index %d, profile index %d", + p_profilelevel->nPortIndex, + p_profilelevel->nProfileIndex); + + retval = get_supported_profilelevel(p_profilelevel); + break; + } + + default: + { + /** + * Vendor-specific extension indices checked here since they are not + * part of the OMX_INDEXTYPE enumerated type. + */ + + switch ((OMX_QCOM_EXTN_INDEXTYPE) param_index) + { + + case OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage: + { + GetAndroidNativeBufferUsageParams *p_buffer_usage = + (GetAndroidNativeBufferUsageParams *) p_param_data; + + OMX_SWVDEC_LOG_API( + "OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage, " + "port index %d", p_buffer_usage->nPortIndex); + + if (p_buffer_usage->nPortIndex == OMX_CORE_PORT_INDEX_OP) + { + p_buffer_usage->nUsage = (GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | + GRALLOC_USAGE_SW_READ_OFTEN | + GRALLOC_USAGE_SW_WRITE_OFTEN); + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_buffer_usage->nPortIndex); + retval = OMX_ErrorBadPortIndex; + } + break; + } + + case OMX_QcomIndexFlexibleYUVDescription: + { + OMX_SWVDEC_LOG_API("OMX_QcomIndexFlexibleYUVDescription"); + + retval = describe_color_format((DescribeColorFormatParams *) + p_param_data); + break; + } + + default: + { + OMX_SWVDEC_LOG_ERROR("param index '0x%08x' invalid"); + retval = OMX_ErrorBadParameter; + break; + } + + } // switch ((OMX_QCOM_EXTN_INDEXTYPE) param_index) + + } // default case + + } // switch (param_index) + +get_parameter_exit: + return retval; +} + +/** + * @brief Set a parameter to component. + * + * @param[in] cmp_handle: Component handle. + * @param[in] param_index: Parameter index. + * @param[in] p_param_data: Pointer to parameter data. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::set_parameter(OMX_HANDLETYPE cmp_handle, + OMX_INDEXTYPE param_index, + OMX_PTR p_param_data) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else if (p_param_data == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_param_data = NULL"); + retval = OMX_ErrorBadParameter; + } + else if ((m_state != OMX_StateLoaded) && + (m_port_reconfig_inprogress == false)) + { + OMX_SWVDEC_LOG_ERROR("disallowed in state %s", + OMX_STATETYPE_STRING(m_state)); + retval = OMX_ErrorIncorrectStateOperation; + } + + if (retval != OMX_ErrorNone) + { + goto set_parameter_exit; + } + + switch (param_index) + { + + case OMX_IndexParamPriorityMgmt: + { + OMX_PRIORITYMGMTTYPE *p_prio_mgmt = + (OMX_PRIORITYMGMTTYPE *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_IndexConfigPriorityMgmt: " + "group ID %d, group priority %d", + p_prio_mgmt->nGroupID, + p_prio_mgmt->nGroupPriority); + + if (m_state != OMX_StateLoaded) + { + OMX_SWVDEC_LOG_ERROR("'%d' state invalid; " + "should be in loaded state", + m_state); + retval = OMX_ErrorIncorrectStateOperation; + } + else + { + memcpy(&m_prio_mgmt, p_prio_mgmt, sizeof(OMX_PRIORITYMGMTTYPE)); + } + + break; + } + + case OMX_IndexParamStandardComponentRole: + { + OMX_PARAM_COMPONENTROLETYPE *p_cmp_role = + (OMX_PARAM_COMPONENTROLETYPE *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_IndexParamStandardComponentRole '%s'", + p_cmp_role->cRole); + + if (m_state != OMX_StateLoaded) + { + OMX_SWVDEC_LOG_ERROR("'%d' state invalid; " + "should be in loaded state", + m_state); + retval = OMX_ErrorIncorrectStateOperation; + } + else + { + if (strncmp((char *) p_cmp_role->cRole, + m_role_name, + OMX_MAX_STRINGNAME_SIZE)) + { + OMX_SWVDEC_LOG_ERROR("'%s': invalid component role name", + p_cmp_role->cRole); + retval = OMX_ErrorBadParameter; + } + } + + break; + } + + case OMX_IndexParamPortDefinition: + { + OMX_PARAM_PORTDEFINITIONTYPE *p_port_def = + (OMX_PARAM_PORTDEFINITIONTYPE *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_IndexParamPortDefinition, port index %d", + p_port_def->nPortIndex); + + if ((m_state != OMX_StateLoaded) && + (((p_port_def->nPortIndex == OMX_CORE_PORT_INDEX_IP) && + (m_port_ip.enabled == OMX_TRUE) && + (m_port_ip.populated == OMX_TRUE)) || + ((p_port_def->nPortIndex == OMX_CORE_PORT_INDEX_OP) && + (m_port_op.enabled == OMX_TRUE) && + (m_port_op.populated == OMX_TRUE)))) + { + OMX_SWVDEC_LOG_ERROR("OMX_IndexParamPortDefinition " + "disallowed in state %s " + "while port %d is enabled & populated", + OMX_STATETYPE_STRING(m_state), + p_port_def->nPortIndex); + + retval = OMX_ErrorIncorrectStateOperation; + } + else + { + retval = set_port_definition(p_port_def); + } + + break; + } + + case OMX_IndexParamCompBufferSupplier: + { + OMX_PARAM_BUFFERSUPPLIERTYPE *p_buffer_supplier = + (OMX_PARAM_BUFFERSUPPLIERTYPE *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_IndexParamCompBufferSupplier: " + "port index %d, buffer supplier %d", + p_buffer_supplier->nPortIndex, + (int) p_buffer_supplier->eBufferSupplier); + + if ((p_buffer_supplier->nPortIndex != OMX_CORE_PORT_INDEX_IP) && + (p_buffer_supplier->nPortIndex != OMX_CORE_PORT_INDEX_OP)) + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_buffer_supplier->nPortIndex); + retval = OMX_ErrorBadPortIndex; + } + + break; + } + + case OMX_IndexParamVideoPortFormat: + { + OMX_VIDEO_PARAM_PORTFORMATTYPE *p_port_format = + (OMX_VIDEO_PARAM_PORTFORMATTYPE *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_IndexParamVideoPortFormat, port index %d", + p_port_format->nPortIndex); + + if ((m_state != OMX_StateLoaded) && + (((p_port_format->nPortIndex == OMX_CORE_PORT_INDEX_IP) && + (m_port_ip.enabled == OMX_TRUE) && + (m_port_ip.populated == OMX_TRUE)) || + ((p_port_format->nPortIndex == OMX_CORE_PORT_INDEX_OP) && + (m_port_op.enabled == OMX_TRUE) && + (m_port_op.populated == OMX_TRUE)))) + { + OMX_SWVDEC_LOG_ERROR("OMX_IndexParamVideoPortFormat " + "disallowed in state %s " + "while port %d is enabled & populated", + OMX_STATETYPE_STRING(m_state), + p_port_format->nPortIndex); + + retval = OMX_ErrorIncorrectStateOperation; + } + else + { + retval = set_video_port_format(p_port_format); + } + + break; + } + + case OMX_IndexParamVideoMpeg2: + { + OMX_SWVDEC_LOG_ERROR("OMX_IndexParamVideoMpeg2 unsupported"); + retval = OMX_ErrorUnsupportedIndex; + break; + } + + case OMX_IndexParamVideoMpeg4: + { + OMX_SWVDEC_LOG_API("OMX_IndexParamVideoMpeg4 unsupported"); + retval = OMX_ErrorUnsupportedIndex; + break; + } + + case OMX_IndexParamVideoAvc: + { + OMX_SWVDEC_LOG_API("OMX_IndexParamVideoAvc unsupported"); + retval = OMX_ErrorUnsupportedIndex; + break; + } + + case OMX_IndexParamVideoH263: + { + OMX_SWVDEC_LOG_API("OMX_IndexParamVideoH263 unsupported"); + retval = OMX_ErrorUnsupportedIndex; + break; + } + + default: + { + /** + * Vendor-specific extension indices checked here since they are not + * part of the OMX_INDEXTYPE enumerated type. + */ + + switch ((OMX_QCOM_EXTN_INDEXTYPE) param_index) + { + + case OMX_QcomIndexPortDefn: + { + OMX_QCOM_PARAM_PORTDEFINITIONTYPE *p_port_def = + (OMX_QCOM_PARAM_PORTDEFINITIONTYPE *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_QcomIndexPortDefn, port index %d", + p_port_def->nPortIndex); + + if ((m_state != OMX_StateLoaded) && + (((p_port_def->nPortIndex == OMX_CORE_PORT_INDEX_IP) && + (m_port_ip.enabled == OMX_TRUE) && + (m_port_ip.populated == OMX_TRUE)) || + ((p_port_def->nPortIndex == OMX_CORE_PORT_INDEX_OP) && + (m_port_op.enabled == OMX_TRUE) && + (m_port_op.populated == OMX_TRUE)))) + { + OMX_SWVDEC_LOG_ERROR("OMX_QcomIndexPortDefn " + "disallowed in state %s " + "while port %d is enabled & populated", + OMX_STATETYPE_STRING(m_state), + p_port_def->nPortIndex); + + retval = OMX_ErrorIncorrectStateOperation; + } + else + { + retval = set_port_definition_qcom(p_port_def); + } + + break; + } + + case OMX_QcomIndexParamVideoDivx: + { + OMX_SWVDEC_LOG_API("OMX_QcomIndexParamVideoDivx"); + OMX_SWVDEC_LOG_ERROR("OMX_QcomIndexParamVideoDivx unsupported"); + retval = OMX_ErrorUnsupportedIndex; + break; + } + + case OMX_QcomIndexParamVideoSyncFrameDecodingMode: + { + OMX_SWVDEC_LOG_API("OMX_QcomIndexParamVideoSyncFrameDecodingMode"); + m_sync_frame_decoding_mode = true; + break; + } + + case OMX_QcomIndexParamVideoDecoderPictureOrder: + { + QOMX_VIDEO_DECODER_PICTURE_ORDER *p_picture_order = + (QOMX_VIDEO_DECODER_PICTURE_ORDER *) p_param_data; + + switch (p_picture_order->eOutputPictureOrder) + { + + case QOMX_VIDEO_DISPLAY_ORDER: + { + OMX_SWVDEC_LOG_API( + "OMX_QcomIndexParamVideoDecoderPictureOrder, " + "QOMX_VIDEO_DISPLAY_ORDER"); + break; + } + + case QOMX_VIDEO_DECODE_ORDER: + { + OMX_SWVDEC_LOG_ERROR( + "OMX_QcomIndexParamVideoDecoderPictureOrder, " + "QOMX_VIDEO_DECODE_ORDER; unsupported"); + + retval = OMX_ErrorUnsupportedSetting; + break; + } + + default: + { + OMX_SWVDEC_LOG_ERROR( + "OMX_QcomIndexParamVideoDecoderPictureOrder, %d; invalid"); + + retval = OMX_ErrorBadParameter; + break; + } + + } + break; + } + + case OMX_GoogleAndroidIndexEnableAndroidNativeBuffers: + { + OMX_SWVDEC_LOG_API( + "OMX_GoogleAndroidIndexEnableAndroidNativeBuffers, %s", + (((EnableAndroidNativeBuffersParams *) p_param_data)->enable ? + "enable" : + "disable")); + + m_android_native_buffers = + (bool) (((EnableAndroidNativeBuffersParams *) + p_param_data)->enable); + + break; + } + + case OMX_GoogleAndroidIndexUseAndroidNativeBuffer: + { + OMX_SWVDEC_LOG_ERROR("OMX_GoogleAndroidIndexUseAndroidNativeBuffer " + "unsupported"); + + retval = OMX_ErrorUnsupportedIndex; + break; + } + + case OMX_QcomIndexParamEnableTimeStampReorder: + { + OMX_SWVDEC_LOG_API( + "OMX_QcomIndexParamEnableTimeStampReorder, %s", + (((QOMX_INDEXTIMESTAMPREORDER *) p_param_data)->bEnable ? + "enable" : + "disable")); + + break; + } + + case OMX_QcomIndexParamVideoMetaBufferMode: + { + StoreMetaDataInBuffersParams *p_meta_data = + (StoreMetaDataInBuffersParams *) p_param_data; + + OMX_SWVDEC_LOG_API("OMX_QcomIndexParamVideoMetaBufferMode, " + "port index %d, %s", + p_meta_data->nPortIndex, + (p_meta_data->bStoreMetaData ? + "enabled" : + "disabled")); + + if (p_meta_data->nPortIndex == OMX_CORE_PORT_INDEX_OP) + { + m_meta_buffer_mode = (bool) p_meta_data->bStoreMetaData; + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_meta_data->nPortIndex); + retval = OMX_ErrorBadPortIndex; + } + + break; + } + + default: + { + OMX_SWVDEC_LOG_ERROR("param index '0x%08x' invalid"); + retval = OMX_ErrorBadParameter; + break; + } + + } // switch ((OMX_QCOM_EXTN_INDEXTYPE) param_index) + + break; + } // default case + + } // switch (param_index) + +set_parameter_exit: + return retval; +} + +/** + * @brief Get a configuration from component. + * + * @param[in] cmp_handle: Component handle. + * @param[in] config_index: Configuration index. + * @param[in] p_config_data: Pointer to configuration data. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::get_config(OMX_HANDLETYPE cmp_handle, + OMX_INDEXTYPE config_index, + OMX_PTR p_config_data) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + goto get_config_exit; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + goto get_config_exit; + } + else if (p_config_data == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_config_data = NULL"); + retval = OMX_ErrorBadParameter; + goto get_config_exit; + } + + switch (config_index) + { + + case OMX_IndexConfigCommonOutputCrop: + { + OMX_CONFIG_RECTTYPE *p_recttype = (OMX_CONFIG_RECTTYPE *) p_config_data; + + OMX_SWVDEC_LOG_API("OMX_IndexConfigCommonOutputCrop, port index %d", + p_recttype->nPortIndex); + + if (p_recttype->nPortIndex == OMX_CORE_PORT_INDEX_OP) + { + p_recttype->nLeft = 0; + p_recttype->nTop = 0; + p_recttype->nWidth = m_frame_dimensions.width; + p_recttype->nHeight = m_frame_dimensions.height; + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_recttype->nPortIndex); + retval = OMX_ErrorBadPortIndex; + } + + break; + } + + default: + { + switch ((OMX_QCOM_EXTN_INDEXTYPE) config_index) + { + + case OMX_QcomIndexConfigInterlaced: + { + OMX_QCOM_CONFIG_INTERLACETYPE *p_config_interlacetype = + (OMX_QCOM_CONFIG_INTERLACETYPE *) p_config_data; + + OMX_SWVDEC_LOG_API("OMX_QcomIndexConfigInterlaced, " + "port index %d, index %d", + p_config_interlacetype->nPortIndex, + p_config_interlacetype->nIndex); + + if (p_config_interlacetype->nPortIndex == OMX_CORE_PORT_INDEX_OP) + { + if (p_config_interlacetype->nIndex == 0) + { + p_config_interlacetype->eInterlaceType = + OMX_QCOM_InterlaceFrameProgressive; + } + else if (p_config_interlacetype->nIndex == 1) + { + p_config_interlacetype->eInterlaceType = + OMX_QCOM_InterlaceInterleaveFrameTopFieldFirst; + } + else if (p_config_interlacetype->nIndex == 2) + { + p_config_interlacetype->eInterlaceType = + OMX_QCOM_InterlaceInterleaveFrameBottomFieldFirst; + } + else + { + OMX_SWVDEC_LOG_ERROR("index '%d' unsupported; " + "no more interlaced types", + p_config_interlacetype->nIndex); + retval = OMX_ErrorNoMore; + } + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_config_interlacetype->nPortIndex); + retval = OMX_ErrorBadPortIndex; + } + + break; + } + + case OMX_QcomIndexQueryNumberOfVideoDecInstance: + { + QOMX_VIDEO_QUERY_DECODER_INSTANCES *p_decoder_instances = + (QOMX_VIDEO_QUERY_DECODER_INSTANCES *) p_config_data; + + OMX_SWVDEC_LOG_API("OMX_QcomIndexQueryNumberOfVideoDecInstance"); + + p_decoder_instances->nNumOfInstances = OMX_SWVDEC_NUM_INSTANCES; + break; + } + + case OMX_QcomIndexConfigVideoFramePackingArrangement: + { + OMX_SWVDEC_LOG_API( + "OMX_QcomIndexConfigVideoFramePackingArrangement"); + + OMX_SWVDEC_LOG_ERROR( + "OMX_QcomIndexConfigVideoFramePackingArrangement unsupported"); + + retval = OMX_ErrorUnsupportedIndex; + break; + } + + default: + { + OMX_SWVDEC_LOG_ERROR("config index '%d' invalid", config_index); + retval = OMX_ErrorBadParameter; + break; + } + + } // switch ((OMX_QCOM_EXTN_INDEXTYPE) config_index) + + break; + } + + } // switch (config_index) + +get_config_exit: + return retval; +} + +/** + * @brief Set a configuration to component. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::set_config(OMX_HANDLETYPE cmp_handle, + OMX_INDEXTYPE config_index, + OMX_PTR p_config_data) +{ + (void) cmp_handle; + (void) config_index; + (void) p_config_data; + + OMX_SWVDEC_LOG_ERROR("not implemented"); + + return OMX_ErrorNotImplemented; +} + +/** + * @brief Translate a vendor-specific extension string to a standard index type. + * + * @param[in] cmp_handle: Component handle. + * @param[in] param_name: Parameter name (extension string). + * @param[in,out] p_index_type: Pointer to extension string's index type. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::get_extension_index(OMX_HANDLETYPE cmp_handle, + OMX_STRING param_name, + OMX_INDEXTYPE *p_index_type) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else if (p_index_type == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_index_type = NULL"); + retval = OMX_ErrorBadParameter; + } + + if (retval != OMX_ErrorNone) + goto get_extension_index_exit; + + OMX_SWVDEC_LOG_API("'%s'", param_name); + + if (!strncmp(param_name, + "OMX.QCOM.index.param.video.SyncFrameDecodingMode", + OMX_MAX_STRINGNAME_SIZE)) + { + *p_index_type = + (OMX_INDEXTYPE) OMX_QcomIndexParamVideoSyncFrameDecodingMode; + } + else if (!strncmp(param_name, + "OMX.QCOM.index.param.IndexExtraData", + OMX_MAX_STRINGNAME_SIZE)) + { + *p_index_type = (OMX_INDEXTYPE) OMX_QcomIndexParamIndexExtraDataType; + } + else if (!strncmp(param_name, + "OMX.google.android.index.enableAndroidNativeBuffers", + OMX_MAX_STRINGNAME_SIZE)) + { + *p_index_type = + (OMX_INDEXTYPE) OMX_GoogleAndroidIndexEnableAndroidNativeBuffers; + } + else if (!strncmp(param_name, + "OMX.google.android.index.useAndroidNativeBuffer2", + OMX_MAX_STRINGNAME_SIZE)) + { + *p_index_type = + (OMX_INDEXTYPE) OMX_GoogleAndroidIndexUseAndroidNativeBuffer2; + } + else if (!strncmp(param_name, + "OMX.google.android.index.useAndroidNativeBuffer", + OMX_MAX_STRINGNAME_SIZE)) + { + *p_index_type = + (OMX_INDEXTYPE) OMX_GoogleAndroidIndexUseAndroidNativeBuffer; + } + else if (!strncmp(param_name, + "OMX.google.android.index.getAndroidNativeBufferUsage", + OMX_MAX_STRINGNAME_SIZE)) + { + *p_index_type = + (OMX_INDEXTYPE) OMX_GoogleAndroidIndexGetAndroidNativeBufferUsage; + } + else if (!strncmp(param_name, + "OMX.google.android.index.storeMetaDataInBuffers", + OMX_MAX_STRINGNAME_SIZE)) + { + *p_index_type = (OMX_INDEXTYPE) OMX_QcomIndexParamVideoMetaBufferMode; + } + else if (!strncmp(param_name, + "OMX.google.android.index.describeColorFormat", + OMX_MAX_STRINGNAME_SIZE)) + { + *p_index_type = (OMX_INDEXTYPE) OMX_QcomIndexFlexibleYUVDescription; + } + else + { + OMX_SWVDEC_LOG_ERROR("'%s': not implemented", param_name); + retval = OMX_ErrorNotImplemented; + } + +get_extension_index_exit: + return retval; +} + +/** + * @brief Get component state. + * + * @param[in] cmp_handle: Component handle. + * @param[in,out] p_state: Pointer to state variable. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::get_state(OMX_HANDLETYPE cmp_handle, + OMX_STATETYPE *p_state) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else + { + OMX_SWVDEC_LOG_API("%s", OMX_STATETYPE_STRING(m_state)); + *p_state = m_state; + } + + return retval; +} + +/** + * @brief Component tunnel request. + * + * @retval OMX_ErrorNotImplemented + */ +OMX_ERRORTYPE omx_swvdec::component_tunnel_request( + OMX_HANDLETYPE cmp_handle, + OMX_U32 port, + OMX_HANDLETYPE peer_component, + OMX_U32 peer_port, + OMX_TUNNELSETUPTYPE *p_tunnel_setup) +{ + (void) cmp_handle; + (void) port; + (void) peer_component; + (void) peer_port; + (void) p_tunnel_setup; + + OMX_SWVDEC_LOG_API(""); + + OMX_SWVDEC_LOG_ERROR("not implemented"); + + return OMX_ErrorNotImplemented; +} + +/** + * @brief Use buffer. + * + * @param[in] cmp_handle: Component handle. + * @param[in,out] pp_buffer_hdr: Pointer to pointer to buffer header type + * structure. + * @param[in] port: Port index. + * @param[in] p_app_data: Pointer to IL client app data. + * @param[in] bytes: Size of buffer to be allocated in bytes. + * @param[in] p_buffer: Pointer to buffer to be used. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::use_buffer(OMX_HANDLETYPE cmp_handle, + OMX_BUFFERHEADERTYPE **pp_buffer_hdr, + OMX_U32 port, + OMX_PTR p_app_data, + OMX_U32 bytes, + OMX_U8 *p_buffer) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else if (pp_buffer_hdr == NULL) + { + OMX_SWVDEC_LOG_ERROR("pp_buffer_hdr = NULL"); + retval = OMX_ErrorBadParameter; + } + else + { + OMX_SWVDEC_LOG_API("port index %d, %p", port, p_buffer); + + if (port == OMX_CORE_PORT_INDEX_OP) + { + retval = buffer_use_op(pp_buffer_hdr, p_app_data, bytes, p_buffer); + + if (retval == OMX_ErrorNone) + { + SWVDEC_STATUS retval_swvdec; + + if ((m_status_flags & (1 << PENDING_STATE_LOADED_TO_IDLE)) && + (m_port_ip.populated == OMX_TRUE) && + (m_port_op.populated == OMX_TRUE)) + { + // start SwVdec + if ((retval_swvdec = swvdec_start(m_swvdec_handle)) != + SWVDEC_STATUS_SUCCESS) + { + OMX_SWVDEC_LOG_ERROR("failed to start SwVdec"); + retval = retval_swvdec2omx(retval_swvdec); + goto use_buffer_exit; + } + + m_status_flags &= ~(1 << PENDING_STATE_LOADED_TO_IDLE); + + async_post_event(OMX_SWVDEC_EVENT_CMD_ACK, + OMX_CommandStateSet, + OMX_StateIdle); + } + + if ((m_status_flags & (1 << PENDING_PORT_ENABLE_OP)) && + (m_port_op.populated == OMX_TRUE)) + { + if (m_port_reconfig_inprogress) + { + // start SwVdec + if ((retval_swvdec = swvdec_start(m_swvdec_handle)) != + SWVDEC_STATUS_SUCCESS) + { + OMX_SWVDEC_LOG_ERROR("failed to start SwVdec"); + retval = retval_swvdec2omx(retval_swvdec); + } + } + + m_status_flags &= ~(1 << PENDING_PORT_ENABLE_OP); + + async_post_event(OMX_SWVDEC_EVENT_CMD_ACK, + OMX_CommandPortEnable, + OMX_CORE_PORT_INDEX_OP); + } + } + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", port); + retval = OMX_ErrorBadPortIndex; + } + } + +use_buffer_exit: + return retval; +} + +/** + * @brief Allocate new buffer & associated header. + * + * @param[in] cmp_handle: Component handle. + * @param[in,out] pp_buffer_hdr: Pointer to pointer to buffer header type + * structure. + * @param[in] port: Port index. + * @param[in] p_app_data: Pointer to IL client app data. + * @param[in] bytes: Size of buffer to be allocated in bytes. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::allocate_buffer(OMX_HANDLETYPE cmp_handle, + OMX_BUFFERHEADERTYPE **pp_buffer_hdr, + OMX_U32 port, + OMX_PTR p_app_data, + OMX_U32 bytes) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else if (pp_buffer_hdr == NULL) + { + OMX_SWVDEC_LOG_ERROR("pp_buffer_hdr = NULL"); + retval = OMX_ErrorBadParameter; + } + else + { + OMX_SWVDEC_LOG_API("port index %d, %d bytes", port, bytes); + + if (port == OMX_CORE_PORT_INDEX_IP) + { + retval = buffer_allocate_ip(pp_buffer_hdr, + p_app_data, + bytes); + } + else if (port == OMX_CORE_PORT_INDEX_OP) + { + if (m_meta_buffer_mode == true) + { + OMX_SWVDEC_LOG_ERROR("'meta buffer mode' enabled"); + retval = OMX_ErrorBadParameter; + } + else if (m_android_native_buffers == true) + { + OMX_SWVDEC_LOG_ERROR("'android native buffers' enabled"); + retval = OMX_ErrorBadParameter; + } + else + { + retval = buffer_allocate_op(pp_buffer_hdr, + p_app_data, + bytes); + } + } + else + { + OMX_SWVDEC_LOG_ERROR("port index %d invalid", port); + retval = OMX_ErrorBadPortIndex; + } + + if (retval == OMX_ErrorNone) + { + SWVDEC_STATUS retval_swvdec; + + if ((m_status_flags & (1 << PENDING_STATE_LOADED_TO_IDLE)) && + (m_port_ip.populated == OMX_TRUE) && + (m_port_op.populated == OMX_TRUE)) + { + // start SwVdec + if ((retval_swvdec = swvdec_start(m_swvdec_handle)) != + SWVDEC_STATUS_SUCCESS) + { + OMX_SWVDEC_LOG_ERROR("failed to start SwVdec"); + retval = retval_swvdec2omx(retval_swvdec); + goto allocate_buffer_exit; + } + + m_status_flags &= ~(1 << PENDING_STATE_LOADED_TO_IDLE); + + async_post_event(OMX_SWVDEC_EVENT_CMD_ACK, + OMX_CommandStateSet, + OMX_StateIdle); + } + + if ((m_status_flags & (1 << PENDING_PORT_ENABLE_IP)) && + (m_port_ip.populated == OMX_TRUE)) + { + m_status_flags &= ~(1 << PENDING_PORT_ENABLE_IP); + + async_post_event(OMX_SWVDEC_EVENT_CMD_ACK, + OMX_CommandPortEnable, + OMX_CORE_PORT_INDEX_IP); + } + + if ((m_status_flags & (1 << PENDING_PORT_ENABLE_OP)) && + (m_port_op.populated == OMX_TRUE)) + { + if (m_port_reconfig_inprogress) + { + // start SwVdec + if ((retval_swvdec = swvdec_start(m_swvdec_handle)) != + SWVDEC_STATUS_SUCCESS) + { + OMX_SWVDEC_LOG_ERROR("failed to start SwVdec"); + retval = retval_swvdec2omx(retval_swvdec); + } + } + + m_status_flags &= ~(1 << PENDING_PORT_ENABLE_OP); + + async_post_event(OMX_SWVDEC_EVENT_CMD_ACK, + OMX_CommandPortEnable, + OMX_CORE_PORT_INDEX_OP); + } + } + } + +allocate_buffer_exit: + return retval; +} + +/** + * @brief Release buffer & associated header. + * + * @param[in] cmp_handle: Component handle. + * @param[in] port: Port index. + * @param[in] p_buffer_hdr: Pointer to buffer's buffer header. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::free_buffer(OMX_HANDLETYPE cmp_handle, + OMX_U32 port, + OMX_BUFFERHEADERTYPE *p_buffer_hdr) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else if (p_buffer_hdr == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_buffer_hdr = NULL"); + retval = OMX_ErrorBadParameter; + } + else if ((port != OMX_CORE_PORT_INDEX_IP) && + (port != OMX_CORE_PORT_INDEX_OP)) + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", port); + retval = OMX_ErrorBadPortIndex; + } + else if (m_state != OMX_StateIdle) + { + if (m_state != OMX_StateExecuting) + { + OMX_SWVDEC_LOG_ERROR("disallowed in state %s", + OMX_STATETYPE_STRING(m_state)); + retval = OMX_ErrorIncorrectStateOperation; + } + else + { + if (((port == OMX_CORE_PORT_INDEX_IP) && m_port_ip.enabled) || + ((port == OMX_CORE_PORT_INDEX_OP) && m_port_op.enabled)) + { + OMX_SWVDEC_LOG_ERROR("port index %d not disabled", port); + retval = OMX_ErrorBadPortIndex; + } + } + } + + if (retval == OMX_ErrorNone) + { + OMX_SWVDEC_LOG_API("port index %d, %p", port, p_buffer_hdr); + + if (port == OMX_CORE_PORT_INDEX_IP) + { + retval = buffer_deallocate_ip(p_buffer_hdr); + } + else + { + retval = buffer_deallocate_op(p_buffer_hdr); + } + } + + if ((retval == OMX_ErrorNone) && + (m_status_flags & (1 << PENDING_STATE_IDLE_TO_LOADED))) + { + if ((m_port_ip.unpopulated == OMX_TRUE) && + (m_port_op.unpopulated == OMX_TRUE)) + { + SWVDEC_STATUS retval_swvdec; + + // stop SwVdec + if ((retval_swvdec = swvdec_stop(m_swvdec_handle)) == + SWVDEC_STATUS_SUCCESS) + { + m_status_flags &= ~(1 << PENDING_STATE_IDLE_TO_LOADED); + + async_post_event(OMX_SWVDEC_EVENT_CMD_ACK, + OMX_CommandStateSet, + OMX_StateLoaded); + } + else + { + OMX_SWVDEC_LOG_ERROR("failed to stop SwVdec"); + retval = retval_swvdec2omx(retval_swvdec); + } + } + } + + if ((retval == OMX_ErrorNone) && + (m_status_flags & (1 << PENDING_PORT_DISABLE_IP)) && + m_port_ip.unpopulated) + { + m_status_flags &= ~(1 << PENDING_PORT_DISABLE_IP); + + async_post_event(OMX_SWVDEC_EVENT_CMD_ACK, + OMX_CommandPortDisable, + OMX_CORE_PORT_INDEX_IP); + } + + if ((retval == OMX_ErrorNone) && + (m_status_flags & (1 << PENDING_PORT_DISABLE_OP)) && + m_port_op.unpopulated) + { + if (m_port_reconfig_inprogress) + { + SWVDEC_STATUS retval_swvdec; + + if ((retval_swvdec = swvdec_stop(m_swvdec_handle)) != + SWVDEC_STATUS_SUCCESS) + { + OMX_SWVDEC_LOG_ERROR("failed to stop SwVdec"); + retval = retval_swvdec2omx(retval_swvdec); + } + } + + m_status_flags &= ~(1 << PENDING_PORT_DISABLE_OP); + + async_post_event(OMX_SWVDEC_EVENT_CMD_ACK, + OMX_CommandPortDisable, + OMX_CORE_PORT_INDEX_OP); + } + + return retval; +} + +/** + * @brief Send a buffer to component's input port to be emptied. + * + * @param[in] cmp_handle: Component handle. + * @param[in] p_buffer_hdr: Pointer to buffer's buffer header. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::empty_this_buffer(OMX_HANDLETYPE cmp_handle, + OMX_BUFFERHEADERTYPE *p_buffer_hdr) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + unsigned int ii; + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else if (p_buffer_hdr == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_buffer_hdr = NULL"); + retval = OMX_ErrorBadParameter; + } + else if (p_buffer_hdr->pBuffer == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_buffer_hdr->pBuffer = NULL"); + retval = OMX_ErrorBadParameter; + } + else if (p_buffer_hdr->pInputPortPrivate == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_buffer_hdr->pInputPortPrivate = NULL"); + retval = OMX_ErrorBadParameter; + } + else if (m_port_ip.enabled == OMX_FALSE) + { + OMX_SWVDEC_LOG_ERROR("ip port disabled"); + retval = OMX_ErrorIncorrectStateOperation; + } + else if (p_buffer_hdr->nInputPortIndex != OMX_CORE_PORT_INDEX_IP) + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_buffer_hdr->nInputPortIndex); + retval = OMX_ErrorBadPortIndex; + } + + if (retval != OMX_ErrorNone) + { + goto empty_this_buffer_exit; + } + + for (ii = 0; ii < m_port_ip.def.nBufferCountActual; ii++) + { + if (p_buffer_hdr == &(m_buffer_array_ip[ii].buffer_header)) + { + OMX_SWVDEC_LOG_LOW("ip buffer %p has index %d", + p_buffer_hdr->pBuffer, + ii); + break; + } + } + + if (ii == m_port_ip.def.nBufferCountActual) + { + OMX_SWVDEC_LOG_ERROR("ip buffer %p not found", + p_buffer_hdr->pBuffer); + retval = OMX_ErrorBadParameter; + goto empty_this_buffer_exit; + } + + if (m_sync_frame_decoding_mode && + ((p_buffer_hdr->nFlags & OMX_BUFFERFLAG_CODECCONFIG) == 0)) + { + p_buffer_hdr->nFlags |= OMX_BUFFERFLAG_EOS; + } + + OMX_SWVDEC_LOG_API("%p: buffer %p, flags 0x%08x, filled length %d, " + "timestamp %lld", + p_buffer_hdr, + p_buffer_hdr->pBuffer, + p_buffer_hdr->nFlags, + p_buffer_hdr->nFilledLen, + p_buffer_hdr->nTimeStamp); + + async_post_event(OMX_SWVDEC_EVENT_ETB, + (unsigned long) p_buffer_hdr, + (unsigned long) ii); + +empty_this_buffer_exit: + return retval; +} + +/** + * @brief Send a buffer to component's output port to be filled. + * + * @param[in] cmp_handle: Component handle. + * @param[in] p_buffer_hdr: Pointer to buffer's buffer header. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::fill_this_buffer(OMX_HANDLETYPE cmp_handle, + OMX_BUFFERHEADERTYPE *p_buffer_hdr) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + unsigned int ii; + + SWVDEC_BUFFER *p_buffer_swvdec; + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else if (p_buffer_hdr == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_buffer_hdr = NULL"); + retval = OMX_ErrorBadParameter; + } + else if (p_buffer_hdr->pBuffer == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_buffer_hdr->pBuffer = NULL"); + retval = OMX_ErrorBadParameter; + } + else if (p_buffer_hdr->pOutputPortPrivate == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_buffer_hdr->pOutputPortPrivate = NULL"); + retval = OMX_ErrorBadParameter; + } + else if (m_port_op.enabled == OMX_FALSE) + { + OMX_SWVDEC_LOG_ERROR("op port disabled"); + retval = OMX_ErrorIncorrectStateOperation; + } + else if (p_buffer_hdr->nOutputPortIndex != OMX_CORE_PORT_INDEX_OP) + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_buffer_hdr->nOutputPortIndex); + retval = OMX_ErrorBadPortIndex; + } + + if (retval != OMX_ErrorNone) + { + goto fill_this_buffer_exit; + } + + OMX_SWVDEC_LOG_API("%p", p_buffer_hdr); + + for (ii = 0; ii < m_port_op.def.nBufferCountActual; ii++) + { + if (p_buffer_hdr == &(m_buffer_array_op[ii].buffer_header)) + { + OMX_SWVDEC_LOG_LOW("op buffer %p has index %d", + p_buffer_hdr->pBuffer, + ii); + break; + } + } + + if (ii == m_port_op.def.nBufferCountActual) + { + OMX_SWVDEC_LOG_ERROR("op buffer %p not found", + p_buffer_hdr->pBuffer); + retval = OMX_ErrorBadParameter; + goto fill_this_buffer_exit; + } + + p_buffer_swvdec = &m_buffer_array_op[ii].buffer_swvdec; + + if (m_meta_buffer_mode) + { + struct VideoDecoderOutputMetaData *p_meta_data; + + private_handle_t *p_private_handle; + + struct vdec_bufferpayload *p_buffer_payload; + + p_meta_data = + (struct VideoDecoderOutputMetaData *) p_buffer_hdr->pBuffer; + + p_private_handle = (private_handle_t *) (p_meta_data->pHandle); + + p_buffer_payload = &m_buffer_array_op[ii].buffer_payload; + + if (p_private_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR( + "p_buffer_hdr->pBuffer->pHandle = NULL"); + + retval = OMX_ErrorBadParameter; + goto fill_this_buffer_exit; + } + + pthread_mutex_lock(&m_meta_buffer_array_mutex); + + if (m_meta_buffer_array[ii].ref_count == 0) + { + unsigned char *bufferaddr; + + bufferaddr = (unsigned char *) mmap(NULL, + m_port_op.def.nBufferSize, + PROT_READ | PROT_WRITE, + MAP_SHARED, + p_private_handle->fd, + 0); + + if (bufferaddr == MAP_FAILED) + { + OMX_SWVDEC_LOG_ERROR("mmap() failed for " + "fd %d of size %d", + p_private_handle->fd, + m_port_op.def.nBufferSize); + + retval = OMX_ErrorInsufficientResources; + goto fill_this_buffer_exit; + } + + p_buffer_payload->bufferaddr = bufferaddr; + p_buffer_payload->pmem_fd = p_private_handle->fd; + p_buffer_payload->buffer_len = m_port_op.def.nBufferSize; + p_buffer_payload->mmaped_size = m_port_op.def.nBufferSize; + + p_buffer_swvdec->p_buffer = bufferaddr; + p_buffer_swvdec->size = m_port_op.def.nBufferSize; + p_buffer_swvdec->p_client_data = (void *) ((unsigned long) ii); + } + + pthread_mutex_unlock(&m_meta_buffer_array_mutex); + + meta_buffer_ref_add(ii, + p_buffer_payload->pmem_fd, + p_buffer_payload->offset); + } + + OMX_SWVDEC_LOG_LOW("%p: buffer %p", + p_buffer_hdr, + p_buffer_swvdec->p_buffer); + + async_post_event(OMX_SWVDEC_EVENT_FTB, + (unsigned long) p_buffer_hdr, + (unsigned long) ii); + +fill_this_buffer_exit: + return retval; +} + +/** + * @brief Set component's callback structure. + * + * @param[in] cmp_handle: Component handle. + * @param[in] p_callbacks: Pointer to callback structure. + * @param[in] p_app_data: Pointer to IL client app data. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::set_callbacks(OMX_HANDLETYPE cmp_handle, + OMX_CALLBACKTYPE *p_callbacks, + OMX_PTR p_app_data) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + OMX_SWVDEC_LOG_API(""); + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else if (p_callbacks->EventHandler == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_callbacks->EventHandler = NULL"); + retval = OMX_ErrorBadParameter; + } + else if (p_callbacks->EmptyBufferDone == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_callbacks->EmptyBufferDone = NULL"); + retval = OMX_ErrorBadParameter; + } + else if (p_callbacks->FillBufferDone == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_callbacks->FillBufferDone = NULL"); + retval = OMX_ErrorBadParameter; + } + else + { + m_callback = *p_callbacks; + m_app_data = p_app_data; + } + + return retval; +} + +/** + * @brief Use EGL image. + * + * @retval OMX_ErrorNotImplemented + */ +OMX_ERRORTYPE omx_swvdec::use_EGL_image(OMX_HANDLETYPE cmp_handle, + OMX_BUFFERHEADERTYPE **pp_buffer_hdr, + OMX_U32 port, + OMX_PTR p_app_data, + void *egl_image) +{ + (void) cmp_handle; + (void) pp_buffer_hdr; + (void) port; + (void) p_app_data; + (void) egl_image; + + OMX_SWVDEC_LOG_API(""); + + OMX_SWVDEC_LOG_ERROR("not implemented"); + + return OMX_ErrorNotImplemented; +} + +/** + * @brief Enumerate component role. + * + * @param[in] cmp_handle: Component handle. + * @param[in,out] p_role: Pointer to component role string. + * @param[in] index: Role index being queried. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::component_role_enum(OMX_HANDLETYPE cmp_handle, + OMX_U8 *p_role, + OMX_U32 index) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in invalid state"); + retval = OMX_ErrorInvalidState; + } + else if (cmp_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("cmp_handle = NULL"); + retval = OMX_ErrorInvalidComponent; + } + else if (index > 0) + { + OMX_SWVDEC_LOG_HIGH("index '%d' unsupported; no more roles", index); + retval = OMX_ErrorNoMore; + } + else + { + memcpy(p_role, m_role_name, OMX_MAX_STRINGNAME_SIZE); + OMX_SWVDEC_LOG_API("index '%d': '%s'", index, p_role); + } + + return retval; +} + +/** + * ------------------------- + * SwVdec callback functions + * ------------------------- + */ + +/** + * @brief SwVdec empty buffer done callback. + * + * @param[in] swvdec_handle: SwVdec handle. + * @param[in] p_buffer_ip: Pointer to input buffer structure. + * @param[in] p_client_handle: Pointer to SwVdec's client handle. + * + * @retval SWVDEC_STATUS_SUCCESS + * @retval SWVDEC_STATUS_NULL_POINTER + * @retval SWVDEC_STATUS_INVALID_PARAMETERS + */ +SWVDEC_STATUS omx_swvdec::swvdec_empty_buffer_done_callback( + SWVDEC_HANDLE swvdec_handle, + SWVDEC_BUFFER *p_buffer_ip, + void *p_client_handle) +{ + SWVDEC_STATUS retval = SWVDEC_STATUS_SUCCESS; + + if (p_buffer_ip == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_buffer_ip = NULL"); + retval = SWVDEC_STATUS_NULL_POINTER; + } + else if (p_client_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_client_handle = NULL"); + retval = SWVDEC_STATUS_NULL_POINTER; + } + else + { + omx_swvdec *p_omx_swvdec = (omx_swvdec *) p_client_handle; + + if (swvdec_handle != p_omx_swvdec->m_swvdec_handle) + { + OMX_SWVDEC_LOG_ERROR("invalid SwVdec handle"); + retval = SWVDEC_STATUS_INVALID_PARAMETERS; + } + else + { + p_omx_swvdec->swvdec_empty_buffer_done(p_buffer_ip); + } + } + + return retval; +} + +/** + * @brief SwVdec fill buffer done callback. + * + * @param[in] swvdec_handle: SwVdec handle. + * @param[in] p_buffer_op: Pointer to output buffer structure. + * @param[in] p_client_handle: Pointer to SwVdec's client handle. + * + * @retval SWVDEC_STATUS_SUCCESS + * @retval SWVDEC_STATUS_NULL_POINTER + * @retval SWVDEC_STATUS_INVALID_PARAMETERS + */ +SWVDEC_STATUS omx_swvdec::swvdec_fill_buffer_done_callback( + SWVDEC_HANDLE swvdec_handle, + SWVDEC_BUFFER *p_buffer_op, + void *p_client_handle) +{ + SWVDEC_STATUS retval = SWVDEC_STATUS_SUCCESS; + + if (p_buffer_op == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_buffer_op = NULL"); + retval = SWVDEC_STATUS_NULL_POINTER; + } + else if (p_client_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_client_handle = NULL"); + retval = SWVDEC_STATUS_NULL_POINTER; + } + else + { + omx_swvdec *p_omx_swvdec = (omx_swvdec *) p_client_handle; + + if (swvdec_handle != p_omx_swvdec->m_swvdec_handle) + { + OMX_SWVDEC_LOG_ERROR("invalid SwVdec handle"); + retval = SWVDEC_STATUS_INVALID_PARAMETERS; + } + else + { + p_omx_swvdec->swvdec_fill_buffer_done(p_buffer_op); + } + } + + return retval; +} + +/** + * @brief SwVdec event handler callback. + * + * @param[in] swvdec_handle: SwVdec handle. + * @param[in] event: Event. + * @param[in] p_data: Pointer to event-specific data. + * @param[in] p_client_handle: Pointer to SwVdec's client handle. + * + * @retval SWVDEC_STATUS_SUCCESS + * @retval SWVDEC_STATUS_NULL_POINTER + * @retval SWVDEC_STATUS_INVALID_PARAMETERS + */ +SWVDEC_STATUS omx_swvdec::swvdec_event_handler_callback( + SWVDEC_HANDLE swvdec_handle, + SWVDEC_EVENT event, + void *p_data, + void *p_client_handle) +{ + SWVDEC_STATUS retval = SWVDEC_STATUS_SUCCESS; + + if ((event == SWVDEC_EVENT_RELEASE_REFERENCE) && (p_data == NULL)) + { + OMX_SWVDEC_LOG_ERROR("p_data = NULL"); + retval = SWVDEC_STATUS_NULL_POINTER; + } + else if (p_client_handle == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_client_handle = NULL"); + retval = SWVDEC_STATUS_NULL_POINTER; + } + else + { + omx_swvdec *p_omx_swvdec = (omx_swvdec *) p_client_handle; + + if (swvdec_handle != p_omx_swvdec->m_swvdec_handle) + { + OMX_SWVDEC_LOG_ERROR("invalid SwVdec handle"); + retval = SWVDEC_STATUS_INVALID_PARAMETERS; + } + else + { + p_omx_swvdec->swvdec_event_handler(event, p_data); + } + } + + return retval; +} + +/** + * ----------------- + * PRIVATE FUNCTIONS + * ----------------- + */ + +/** + * @brief Set frame dimensions for OMX component & SwVdec core. + * + * @param[in] width: Frame width. + * @param[in] height: Frame height. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::set_frame_dimensions(unsigned int width, + unsigned int height) +{ + OMX_ERRORTYPE retval; + + m_frame_dimensions.width = width; + m_frame_dimensions.height = height; + + OMX_SWVDEC_LOG_HIGH("%d x %d", + m_frame_dimensions.width, + m_frame_dimensions.height); + + retval = set_frame_dimensions_swvdec(); + + return retval; +} + +/** + * @brief Set frame attributes for OMX component & SwVdec core, based on + * frame dimensions & alignment factors. + * + * @param[in] alignment_stride: Frame stride alignment factor. + * @param[in] alignment_scanlines_y: Frame luma scanlines alignment factor. + * @param[in] alignment_scanlines_uv: Frame chroma scanlines alignment factor. + * @param[in] alignment_size: Frame size alignment factor. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::set_frame_attributes( + unsigned int alignment_stride, + unsigned int alignment_scanlines_y, + unsigned int alignment_scanlines_uv, + unsigned int alignment_size) +{ + OMX_ERRORTYPE retval; + + unsigned int width = m_frame_dimensions.width; + unsigned int height = m_frame_dimensions.height; + + unsigned int scanlines_uv; + + unsigned int plane_size_y; + unsigned int plane_size_uv; + + m_frame_attributes.stride = ALIGN(width, alignment_stride); + m_frame_attributes.scanlines = ALIGN(height, alignment_scanlines_y); + + scanlines_uv = ALIGN(height / 2, alignment_scanlines_uv); + + plane_size_y = m_frame_attributes.stride * m_frame_attributes.scanlines; + plane_size_uv = m_frame_attributes.stride * scanlines_uv; + + m_frame_attributes.size = + ALIGN(plane_size_y + plane_size_uv, alignment_size); + + OMX_SWVDEC_LOG_HIGH("stride %d, scanlines %d, size %d", + m_frame_attributes.stride, + m_frame_attributes.scanlines, + m_frame_attributes.size); + + retval = set_frame_attributes_swvdec(); + + return retval; +} + +/** + * @brief Get video port format for input or output port. + * + * @param[in,out] p_port_format: Pointer to video port format type. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::get_video_port_format( + OMX_VIDEO_PARAM_PORTFORMATTYPE *p_port_format) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (p_port_format->nPortIndex == OMX_CORE_PORT_INDEX_IP) + { + if (p_port_format->nIndex == 0) + { + p_port_format->eColorFormat = OMX_COLOR_FormatUnused; + p_port_format->eCompressionFormat = m_omx_video_codingtype; + + OMX_SWVDEC_LOG_HIGH("color format 0x%08x, " + "compression format 0x%08x", + p_port_format->eColorFormat, + p_port_format->eCompressionFormat); + } + else + { + OMX_SWVDEC_LOG_HIGH("index '%d' unsupported; " + "no more compression formats", + p_port_format->nIndex); + retval = OMX_ErrorNoMore; + } + } + else if (p_port_format->nPortIndex == OMX_CORE_PORT_INDEX_OP) + { + if (p_port_format->nIndex == 0) + { + p_port_format->eColorFormat = + OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m; + p_port_format->eCompressionFormat = OMX_VIDEO_CodingUnused; + + OMX_SWVDEC_LOG_HIGH("color format 0x%08x, " + "compression format 0x%08x", + p_port_format->eColorFormat, + p_port_format->eCompressionFormat); + } + else if (p_port_format->nIndex == 1) + { + p_port_format->eColorFormat = OMX_COLOR_FormatYUV420SemiPlanar; + p_port_format->eCompressionFormat = OMX_VIDEO_CodingUnused; + + OMX_SWVDEC_LOG_HIGH("color format 0x%08x, " + "compression format 0x%08x", + p_port_format->eColorFormat, + p_port_format->eCompressionFormat); + } + // Here, add additional supported color formats as necessary. + else + { + OMX_SWVDEC_LOG_HIGH("index '%d' unsupported; no more color formats", + p_port_format->nIndex); + retval = OMX_ErrorNoMore; + } + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_port_format->nPortIndex); + retval = OMX_ErrorBadPortIndex; + } + + return retval; +} + +/** + * @brief Set video port format for input or output port. + * + * @param[in] p_port_format: Pointer to video port format type. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::set_video_port_format( + OMX_VIDEO_PARAM_PORTFORMATTYPE *p_port_format) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (p_port_format->nPortIndex == OMX_CORE_PORT_INDEX_IP) + { + // do nothing + OMX_SWVDEC_LOG_HIGH("OMX_IndexParamVideoPortFormat, port index 0; " + "doing nothing"); + } + else if (p_port_format->nPortIndex == OMX_CORE_PORT_INDEX_OP) + { + /** + * If color format specified by IL client is different from default, + * set alignment factors for new color format and call + * set_frame_attributes(). + */ + switch (p_port_format->eColorFormat) + { + + case OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m: + { + // do nothing; this is the default color format + OMX_SWVDEC_LOG_HIGH( + "'0x%08x': OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m", + p_port_format->eColorFormat); + break; + } + + case OMX_COLOR_FormatYUV420SemiPlanar: + { + OMX_SWVDEC_LOG_HIGH("'0x%08x': OMX_COLOR_FormatYUV420SemiPlanar", + p_port_format->eColorFormat); + + retval = set_frame_attributes(16, // stride alignment + 1, // Y scanlines alignment + 1, // UV scanlines alignment + 4096); // size alignment + break; + } + + default: + { + OMX_SWVDEC_LOG_ERROR("color format '0x%08x' invalid or unsupported", + p_port_format->eColorFormat); + retval = OMX_ErrorBadParameter; + break; + } + + } + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_port_format->nPortIndex); + retval = OMX_ErrorBadPortIndex; + } + +set_video_port_format_exit: + return retval; +} + +/** + * @brief Get port definition for input or output port. + * + * @param[in,out] p_port_def: Pointer to port definition type. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::get_port_definition( + OMX_PARAM_PORTDEFINITIONTYPE *p_port_def) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + p_port_def->eDomain = OMX_PortDomainVideo; + + if (p_port_def->nPortIndex == OMX_CORE_PORT_INDEX_IP) + { + if ((retval = get_buffer_requirements_swvdec(OMX_CORE_PORT_INDEX_IP)) != + OMX_ErrorNone) + { + goto get_port_definition_exit; + } + + p_port_def->eDir = OMX_DirInput; + p_port_def->nBufferCountActual = m_port_ip.def.nBufferCountActual; + p_port_def->nBufferCountMin = m_port_ip.def.nBufferCountMin; + p_port_def->nBufferSize = m_port_ip.def.nBufferSize; + p_port_def->bEnabled = m_port_ip.enabled; + p_port_def->bPopulated = m_port_ip.populated; + + OMX_SWVDEC_LOG_HIGH("port index %d: " + "count actual %d, count min %d, size %d", + p_port_def->nPortIndex, + p_port_def->nBufferCountActual, + p_port_def->nBufferCountMin, + p_port_def->nBufferSize); + + // frame dimensions & attributes don't apply to input port + + p_port_def->format.video.eColorFormat = OMX_COLOR_FormatUnused; + p_port_def->format.video.eCompressionFormat = m_omx_video_codingtype; + } + else if (p_port_def->nPortIndex == OMX_CORE_PORT_INDEX_OP) + { + unsigned int frame_width = m_frame_dimensions.width; + unsigned int frame_height = m_frame_dimensions.height; + + if ((retval = get_frame_dimensions_swvdec()) != OMX_ErrorNone) + { + goto get_port_definition_exit; + } + + p_port_def->format.video.nFrameWidth = m_frame_dimensions.width; + p_port_def->format.video.nFrameHeight = m_frame_dimensions.height; + + // if frame dimensions have changed, update frame attributes + if ((frame_width != m_frame_dimensions.width) || + (frame_height != m_frame_dimensions.height)) + { + if ((retval = set_frame_attributes(DEFAULT_ALIGNMENT_STRIDE, + DEFAULT_ALIGNMENT_SCANLINES_Y, + DEFAULT_ALIGNMENT_SCANLINES_UV, + DEFAULT_ALIGNMENT_SIZE)) != + OMX_ErrorNone) + { + goto get_port_definition_exit; + } + } + + if ((retval = get_frame_attributes_swvdec()) != OMX_ErrorNone) + { + goto get_port_definition_exit; + } + + p_port_def->format.video.nStride = m_frame_attributes.stride; + p_port_def->format.video.nSliceHeight = m_frame_attributes.scanlines; + + OMX_SWVDEC_LOG_HIGH("port index %d: " + "%d x %d, stride %d, sliceheight %d", + p_port_def->nPortIndex, + p_port_def->format.video.nFrameWidth, + p_port_def->format.video.nFrameHeight, + p_port_def->format.video.nStride, + p_port_def->format.video.nSliceHeight); + + /** + * Query to SwVdec core for buffer requirements is not allowed in + * executing state since it will overwrite the component's buffer + * requirements updated via the most recent set_parameter(). + * + * Buffer requirements communicated to component via set_parameter() are + * not propagated to SwVdec core. + * + * The only execption is if port reconfiguration is in progress, in + * which case the query to SwVdec core is required since buffer + * requirements can change based on new dimensions. + */ + if ((m_state != OMX_StateExecuting) || m_port_reconfig_inprogress) + { + if ((retval = + get_buffer_requirements_swvdec(OMX_CORE_PORT_INDEX_OP)) != + OMX_ErrorNone) + { + goto get_port_definition_exit; + } + } + + p_port_def->eDir = OMX_DirOutput; + p_port_def->nBufferCountActual = m_port_op.def.nBufferCountActual; + p_port_def->nBufferCountMin = m_port_op.def.nBufferCountMin; + p_port_def->nBufferSize = m_port_op.def.nBufferSize; + p_port_def->bEnabled = m_port_op.enabled; + p_port_def->bPopulated = m_port_op.populated; + + OMX_SWVDEC_LOG_HIGH("port index %d: " + "count actual %d, count min %d, size %d", + p_port_def->nPortIndex, + p_port_def->nBufferCountActual, + p_port_def->nBufferCountMin, + p_port_def->nBufferSize); + + p_port_def->format.video.eColorFormat = m_omx_color_formattype; + p_port_def->format.video.eCompressionFormat = OMX_VIDEO_CodingUnused; + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", p_port_def->nPortIndex); + retval = OMX_ErrorBadPortIndex; + } + +get_port_definition_exit: + return retval; +} + +/** + * @brief Set port definition for input or output port. + * + * @param[in] p_port_def: Pointer to port definition type. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::set_port_definition( + OMX_PARAM_PORTDEFINITIONTYPE *p_port_def) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + OMX_SWVDEC_LOG_HIGH("port index %d: " + "count actual %d, count min %d, size %d", + p_port_def->nPortIndex, + p_port_def->nBufferCountActual, + p_port_def->nBufferCountMin, + p_port_def->nBufferSize); + + if (p_port_def->nPortIndex == OMX_CORE_PORT_INDEX_IP) + { + m_port_ip.def.nBufferCountActual = p_port_def->nBufferCountActual; + m_port_ip.def.nBufferCountMin = p_port_def->nBufferCountMin; + m_port_ip.def.nBufferSize = p_port_def->nBufferSize; + } + else if (p_port_def->nPortIndex == OMX_CORE_PORT_INDEX_OP) + { + OMX_SWVDEC_LOG_HIGH("port index %d: %d x %d", + p_port_def->nPortIndex, + p_port_def->format.video.nFrameWidth, + p_port_def->format.video.nFrameHeight); + + m_port_op.def.nBufferCountActual = p_port_def->nBufferCountActual; + m_port_op.def.nBufferCountMin = p_port_def->nBufferCountMin; + m_port_op.def.nBufferSize = p_port_def->nBufferSize; + + retval = set_frame_dimensions(p_port_def->format.video.nFrameWidth, + p_port_def->format.video.nFrameHeight); + if (retval != OMX_ErrorNone) + goto set_port_definition_exit; + + m_frame_attributes.stride = p_port_def->format.video.nStride; + m_frame_attributes.scanlines = p_port_def->format.video.nSliceHeight; + m_frame_attributes.size = p_port_def->nBufferSize; + + retval = set_frame_attributes(DEFAULT_ALIGNMENT_STRIDE, + DEFAULT_ALIGNMENT_SCANLINES_Y, + DEFAULT_ALIGNMENT_SCANLINES_UV, + DEFAULT_ALIGNMENT_SIZE); + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", p_port_def->nPortIndex); + retval = OMX_ErrorBadPortIndex; + } + +set_port_definition_exit: + return retval; +} + +/** + * @brief Get supported profile & level. + * + * The supported profiles & levels are not queried from SwVdec core, but + * hard-coded. This should ideally be replaced with a query to SwVdec core. + * + * @param[in,out] p_profilelevel: Pointer to video profile & level type. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::get_supported_profilelevel( + OMX_VIDEO_PARAM_PROFILELEVELTYPE *p_profilelevel) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (p_profilelevel == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_profilelevel = NULL"); + retval = OMX_ErrorBadParameter; + goto get_supported_profilelevel_exit; + } + + if (p_profilelevel->nPortIndex != OMX_CORE_PORT_INDEX_IP) + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_profilelevel->nPortIndex); + retval = OMX_ErrorBadPortIndex; + goto get_supported_profilelevel_exit; + } + + if (m_omx_video_codingtype == OMX_VIDEO_CodingH263) + { + if (p_profilelevel->nProfileIndex == 0) + { + p_profilelevel->eProfile = OMX_VIDEO_H263ProfileBaseline; + p_profilelevel->eLevel = OMX_VIDEO_H263Level70; + OMX_SWVDEC_LOG_HIGH("H.263 baseline profile, level 70"); + } + else + { + OMX_SWVDEC_LOG_HIGH("profile index '%d' unsupported; " + "no more profiles", + p_profilelevel->nProfileIndex); + retval = OMX_ErrorNoMore; + } + } + else if ((m_omx_video_codingtype == OMX_VIDEO_CodingMPEG4) || + (m_omx_video_codingtype == + ((OMX_VIDEO_CODINGTYPE) QOMX_VIDEO_CodingDivx))) + { + if (p_profilelevel->nProfileIndex == 0) + { + p_profilelevel->eProfile = OMX_VIDEO_MPEG4ProfileSimple; + p_profilelevel->eLevel = OMX_VIDEO_MPEG4Level5; + OMX_SWVDEC_LOG_HIGH("MPEG-4 simple profile, level 5"); + } + else if (p_profilelevel->nProfileIndex == 1) + { + p_profilelevel->eProfile = OMX_VIDEO_MPEG4ProfileAdvancedSimple; + p_profilelevel->eLevel = OMX_VIDEO_MPEG4Level5; + OMX_SWVDEC_LOG_HIGH("MPEG-4 advanced simple profile, level 5"); + } + else + { + OMX_SWVDEC_LOG_HIGH("profile index '%d' unsupported; " + "no more profiles", + p_profilelevel->nProfileIndex); + retval = OMX_ErrorNoMore; + } + } + else + { + assert(0); + retval = OMX_ErrorUndefined; + } + +get_supported_profilelevel_exit: + return retval; +} + +/** + * @brief Describe color format. + * + * @param[in,out] p_params: Pointer to 'DescribeColorFormatParams' structure. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::describe_color_format( + DescribeColorFormatParams *p_params) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (p_params == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_params = NULL"); + retval = OMX_ErrorBadParameter; + } + else + { + MediaImage *p_img = &p_params->sMediaImage; + + switch (p_params->eColorFormat) + { + + case QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m: + { + size_t stride, scanlines; + + p_img->mType = MediaImage::MEDIA_IMAGE_TYPE_YUV; + p_img->mNumPlanes = 3; + + p_img->mWidth = p_params->nFrameWidth; + p_img->mHeight = p_params->nFrameHeight; + + stride = ALIGN(p_img->mWidth, DEFAULT_ALIGNMENT_STRIDE); + scanlines = ALIGN(p_img->mHeight, DEFAULT_ALIGNMENT_SCANLINES_Y); + + p_img->mBitDepth = 8; + + // plane 0 (Y) + p_img->mPlane[MediaImage::Y].mOffset = 0; + p_img->mPlane[MediaImage::Y].mColInc = 1; + p_img->mPlane[MediaImage::Y].mRowInc = stride; + p_img->mPlane[MediaImage::Y].mHorizSubsampling = 1; + p_img->mPlane[MediaImage::Y].mVertSubsampling = 1; + + // plane 1 (U) + p_img->mPlane[MediaImage::Y].mOffset = stride * scanlines; + p_img->mPlane[MediaImage::Y].mColInc = 2; + p_img->mPlane[MediaImage::Y].mRowInc = stride; + p_img->mPlane[MediaImage::Y].mHorizSubsampling = 2; + p_img->mPlane[MediaImage::Y].mVertSubsampling = 2; + + // plane 2 (V) + p_img->mPlane[MediaImage::Y].mOffset = stride * scanlines + 1; + p_img->mPlane[MediaImage::Y].mColInc = 2; + p_img->mPlane[MediaImage::Y].mRowInc = stride; + p_img->mPlane[MediaImage::Y].mHorizSubsampling = 2; + p_img->mPlane[MediaImage::Y].mVertSubsampling = 2; + + break; + } + + case OMX_COLOR_FormatYUV420SemiPlanar: + { + size_t stride, scanlines; + + p_img->mType = MediaImage::MEDIA_IMAGE_TYPE_YUV; + p_img->mNumPlanes = 3; + + p_img->mWidth = p_params->nFrameWidth; + p_img->mHeight = p_params->nFrameHeight; + + stride = ALIGN(p_img->mWidth, 16); + scanlines = ALIGN(p_img->mHeight, 1); + + p_img->mBitDepth = 8; + + // plane 0 (Y) + p_img->mPlane[MediaImage::Y].mOffset = 0; + p_img->mPlane[MediaImage::Y].mColInc = 1; + p_img->mPlane[MediaImage::Y].mRowInc = stride; + p_img->mPlane[MediaImage::Y].mHorizSubsampling = 1; + p_img->mPlane[MediaImage::Y].mVertSubsampling = 1; + + // plane 1 (U) + p_img->mPlane[MediaImage::Y].mOffset = stride * scanlines; + p_img->mPlane[MediaImage::Y].mColInc = 2; + p_img->mPlane[MediaImage::Y].mRowInc = stride; + p_img->mPlane[MediaImage::Y].mHorizSubsampling = 2; + p_img->mPlane[MediaImage::Y].mVertSubsampling = 2; + + // plane 2 (V) + p_img->mPlane[MediaImage::Y].mOffset = stride * scanlines + 1; + p_img->mPlane[MediaImage::Y].mColInc = 2; + p_img->mPlane[MediaImage::Y].mRowInc = stride; + p_img->mPlane[MediaImage::Y].mHorizSubsampling = 2; + p_img->mPlane[MediaImage::Y].mVertSubsampling = 2; + + break; + } + + default: + { + OMX_SWVDEC_LOG_ERROR("color format '0x%08x' invalid/unsupported", + p_params->eColorFormat); + + p_img->mType = MediaImage::MEDIA_IMAGE_TYPE_UNKNOWN; + + retval = OMX_ErrorBadParameter; + break; + } + + } // switch (p_params->eColorFormat) + } + + return retval; +} + +/** + * @brief Set QTI vendor-specific port definition for input or output port. + * + * @param[in] p_port_def: Pointer to QTI vendor-specific port definition type. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::set_port_definition_qcom( + OMX_QCOM_PARAM_PORTDEFINITIONTYPE *p_port_def) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (p_port_def->nPortIndex == OMX_CORE_PORT_INDEX_IP) + { + switch (p_port_def->nFramePackingFormat) + { + + case OMX_QCOM_FramePacking_Arbitrary: + { + OMX_SWVDEC_LOG_ERROR("OMX_QCOM_FramePacking_Arbitrary unsupported"); + retval = OMX_ErrorUnsupportedSetting; + break; + } + + case OMX_QCOM_FramePacking_OnlyOneCompleteFrame: + { + OMX_SWVDEC_LOG_HIGH( + "OMX_QCOM_FramePacking_OnlyOneCompleteFrame"); + break; + } + + default: + { + OMX_SWVDEC_LOG_ERROR( + "frame packing format '%d' unsupported"); + retval = OMX_ErrorUnsupportedSetting; + break; + } + + } + } + else if (p_port_def->nPortIndex == OMX_CORE_PORT_INDEX_OP) + { + OMX_SWVDEC_LOG_HIGH("nMemRegion %d, nCacheAttr %d", + p_port_def->nMemRegion, + p_port_def->nCacheAttr); + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", + p_port_def->nPortIndex); + retval = OMX_ErrorBadPortIndex; + } + + return retval; +} + +/** + * @brief Set SwVdec frame dimensions based on OMX component frame dimensions. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::set_frame_dimensions_swvdec() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + SWVDEC_PROPERTY property; + + SWVDEC_STATUS retval_swvdec; + + property.id = SWVDEC_PROPERTY_ID_FRAME_DIMENSIONS; + + property.info.frame_dimensions.width = m_frame_dimensions.width; + property.info.frame_dimensions.height = m_frame_dimensions.height; + + if ((retval_swvdec = swvdec_setproperty(m_swvdec_handle, &property)) != + SWVDEC_STATUS_SUCCESS) + { + retval = retval_swvdec2omx(retval_swvdec); + } + + return retval; +} + +/** + * @brief Set SwVdec frame attributes based on OMX component frame attributes. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::set_frame_attributes_swvdec() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + SWVDEC_FRAME_ATTRIBUTES *p_frame_attributes; + + SWVDEC_PROPERTY property; + + SWVDEC_STATUS retval_swvdec; + + p_frame_attributes = &property.info.frame_attributes; + + property.id = SWVDEC_PROPERTY_ID_FRAME_ATTRIBUTES; + + p_frame_attributes->color_format = SWVDEC_COLOR_FORMAT_SEMIPLANAR_NV12; + + p_frame_attributes->semiplanar.stride = m_frame_attributes.stride; + p_frame_attributes->semiplanar.offset_uv = (m_frame_attributes.stride * + m_frame_attributes.scanlines); + + p_frame_attributes->size = m_frame_attributes.size; + + if ((retval_swvdec = swvdec_setproperty(m_swvdec_handle, &property)) != + SWVDEC_STATUS_SUCCESS) + { + retval = retval_swvdec2omx(retval_swvdec); + } + + return retval; +} + +/** + * @brief Get SwVdec frame dimensions and set OMX component frame dimensions. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::get_frame_dimensions_swvdec() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + SWVDEC_PROPERTY property; + + SWVDEC_STATUS retval_swvdec; + + property.id = SWVDEC_PROPERTY_ID_FRAME_DIMENSIONS; + + if ((retval_swvdec = swvdec_getproperty(m_swvdec_handle, &property)) != + SWVDEC_STATUS_SUCCESS) + { + retval = retval_swvdec2omx(retval_swvdec); + } + else + { + m_frame_dimensions.width = property.info.frame_dimensions.width; + m_frame_dimensions.height = property.info.frame_dimensions.height; + } + + return retval; +} + +/** + * @brief Get SwVdec frame attributes and set OMX component frame attributes. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::get_frame_attributes_swvdec() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + SWVDEC_PROPERTY property; + + SWVDEC_STATUS retval_swvdec; + + property.id = SWVDEC_PROPERTY_ID_FRAME_ATTRIBUTES; + + if ((retval_swvdec = swvdec_getproperty(m_swvdec_handle, &property)) != + SWVDEC_STATUS_SUCCESS) + { + retval = retval_swvdec2omx(retval_swvdec); + } + else + { + m_frame_attributes.stride = + property.info.frame_attributes.semiplanar.stride; + + m_frame_attributes.scanlines = + (property.info.frame_attributes.semiplanar.offset_uv / + property.info.frame_attributes.semiplanar.stride); + + m_frame_attributes.size = property.info.frame_attributes.size; + } + + return retval; +} + +/** + * @brief Get SwVdec buffer requirements; set input or output port definitions. + * + * @param[in] port_index: Port index. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::get_buffer_requirements_swvdec( + unsigned int port_index) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + SWVDEC_PROPERTY property; + + SWVDEC_STATUS retval_swvdec; + + SWVDEC_BUFFER_REQ *p_buffer_req; + + if (port_index == OMX_CORE_PORT_INDEX_IP) + { + property.id = SWVDEC_PROPERTY_ID_BUFFER_REQ_IP; + + p_buffer_req = &property.info.buffer_req_ip; + + if ((retval_swvdec = swvdec_getproperty(m_swvdec_handle, &property)) != + SWVDEC_STATUS_SUCCESS) + { + retval = retval_swvdec2omx(retval_swvdec); + goto get_buffer_requirements_swvdec_exit; + } + + m_port_ip.def.nBufferSize = p_buffer_req->size; + m_port_ip.def.nBufferCountMin = p_buffer_req->mincount; + m_port_ip.def.nBufferCountActual = MAX(p_buffer_req->mincount, + OMX_SWVDEC_IP_BUFFER_COUNT); + m_port_ip.def.nBufferAlignment = p_buffer_req->alignment; + + OMX_SWVDEC_LOG_HIGH("ip port: %d bytes x %d, %d-byte aligned", + m_port_ip.def.nBufferSize, + m_port_ip.def.nBufferCountActual, + m_port_ip.def.nBufferAlignment); + } + else if (port_index == OMX_CORE_PORT_INDEX_OP) + { + property.id = SWVDEC_PROPERTY_ID_BUFFER_REQ_OP; + + p_buffer_req = &property.info.buffer_req_op; + + if ((retval_swvdec = swvdec_getproperty(m_swvdec_handle, &property)) != + SWVDEC_STATUS_SUCCESS) + { + retval = retval_swvdec2omx(retval_swvdec); + goto get_buffer_requirements_swvdec_exit; + } + + if (m_sync_frame_decoding_mode) + { + // only 1 output buffer for sync frame decoding mode + p_buffer_req->mincount = 1; + } + + m_port_op.def.nBufferSize = p_buffer_req->size; + m_port_op.def.nBufferCountMin = p_buffer_req->mincount; + m_port_op.def.nBufferCountActual = p_buffer_req->mincount; + m_port_op.def.nBufferAlignment = p_buffer_req->alignment; + + OMX_SWVDEC_LOG_HIGH("op port: %d bytes x %d, %d-byte aligned", + m_port_op.def.nBufferSize, + m_port_op.def.nBufferCountActual, + m_port_op.def.nBufferAlignment); + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid", port_index); + retval = OMX_ErrorBadPortIndex; + } + +get_buffer_requirements_swvdec_exit: + return retval; +} + +/** + * @brief Allocate input buffer, and input buffer info array if ncessary. + * + * @param[in,out] pp_buffer_hdr: Pointer to pointer to buffer header type + * structure. + * @param[in] p_app_data: Pointer to IL client app data. + * @param[in] size: Size of buffer to be allocated in bytes. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::buffer_allocate_ip( + OMX_BUFFERHEADERTYPE **pp_buffer_hdr, + OMX_PTR p_app_data, + OMX_U32 size) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + unsigned int ii; + + if (size != m_port_ip.def.nBufferSize) + { + OMX_SWVDEC_LOG_ERROR("requested size (%d bytes) not equal to " + "configured size (%d bytes)", + size, + m_port_ip.def.nBufferSize); + retval = OMX_ErrorBadParameter; + goto buffer_allocate_ip_exit; + } + + if (m_buffer_array_ip == NULL) + { + // input buffer info array not allocated; allocate here + + OMX_SWVDEC_LOG_HIGH("allocating buffer info array, %d element%s", + m_port_ip.def.nBufferCountActual, + (m_port_ip.def.nBufferCountActual > 1) ? "s" : ""); + + if ((retval = buffer_allocate_ip_info_array()) != OMX_ErrorNone) + { + goto buffer_allocate_ip_exit; + } + } + + for (ii = 0; ii < m_port_ip.def.nBufferCountActual; ii++) + { + if (m_buffer_array_ip[ii].buffer_populated == false) + { + OMX_SWVDEC_LOG_LOW("buffer %d not populated", ii); + break; + } + } + + if (ii < m_port_ip.def.nBufferCountActual) + { + int pmem_fd = -1; + + unsigned char *bufferaddr; + + OMX_SWVDEC_LOG_HIGH("ip buffer %d: %d bytes being allocated", + ii, + size); + + m_buffer_array_ip[ii].ion_info.ion_fd_device = + ion_memory_alloc_map(&m_buffer_array_ip[ii].ion_info.ion_alloc_data, + &m_buffer_array_ip[ii].ion_info.ion_fd_data, + size, + m_port_ip.def.nBufferAlignment); + + if (m_buffer_array_ip[ii].ion_info.ion_fd_device < 0) + { + retval = OMX_ErrorInsufficientResources; + goto buffer_allocate_ip_exit; + } + + pmem_fd = m_buffer_array_ip[ii].ion_info.ion_fd_data.fd; + + bufferaddr = (unsigned char *) mmap(NULL, + size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + pmem_fd, + 0); + + if (bufferaddr == MAP_FAILED) + { + OMX_SWVDEC_LOG_ERROR("mmap() failed for fd %d of size %d", + pmem_fd, + size); + close(pmem_fd); + ion_memory_free(&m_buffer_array_ip[ii].ion_info); + retval = OMX_ErrorInsufficientResources; + goto buffer_allocate_ip_exit; + } + + *pp_buffer_hdr = &m_buffer_array_ip[ii].buffer_header; + + m_buffer_array_ip[ii].buffer_payload.bufferaddr = bufferaddr; + m_buffer_array_ip[ii].buffer_payload.pmem_fd = pmem_fd; + m_buffer_array_ip[ii].buffer_payload.buffer_len = size; + m_buffer_array_ip[ii].buffer_payload.mmaped_size = size; + m_buffer_array_ip[ii].buffer_payload.offset = 0; + + m_buffer_array_ip[ii].buffer_swvdec.p_buffer = bufferaddr; + m_buffer_array_ip[ii].buffer_swvdec.size = size; + m_buffer_array_ip[ii].buffer_swvdec.p_client_data = + (void *) ((unsigned long) ii); + + m_buffer_array_ip[ii].buffer_populated = true; + + OMX_SWVDEC_LOG_HIGH("ip buffer %d: %p, %d bytes", + ii, + bufferaddr, + size); + + (*pp_buffer_hdr)->pBuffer = (OMX_U8 *) bufferaddr; + (*pp_buffer_hdr)->nSize = sizeof(OMX_BUFFERHEADERTYPE); + (*pp_buffer_hdr)->nVersion.nVersion = OMX_SPEC_VERSION; + (*pp_buffer_hdr)->nAllocLen = size; + (*pp_buffer_hdr)->pAppPrivate = p_app_data; + (*pp_buffer_hdr)->nInputPortIndex = OMX_CORE_PORT_INDEX_IP; + (*pp_buffer_hdr)->pInputPortPrivate = + (void *) &(m_buffer_array_ip[ii].buffer_payload); + + m_port_ip.populated = port_ip_populated(); + m_port_ip.unpopulated = OMX_FALSE; + } + else + { + OMX_SWVDEC_LOG_ERROR("all %d ip buffers allocated", + m_port_ip.def.nBufferCountActual); + retval = OMX_ErrorInsufficientResources; + } + +buffer_allocate_ip_exit: + return retval; +} + +/** + * @brief Allocate output buffer, and output buffer info array if necessary. + * + * @param[in,out] pp_buffer_hdr: Pointer to pointer to buffer header type + * structure. + * @param[in] p_app_data: Pointer to IL client app data. + * @param[in] size: Size of buffer to be allocated in bytes. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::buffer_allocate_op( + OMX_BUFFERHEADERTYPE **pp_buffer_hdr, + OMX_PTR p_app_data, + OMX_U32 size) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + unsigned int ii; + + if (size != m_port_op.def.nBufferSize) + { + OMX_SWVDEC_LOG_ERROR("requested size (%d bytes) not equal to " + "configured size (%d bytes)", + size, + m_port_op.def.nBufferSize); + retval = OMX_ErrorBadParameter; + goto buffer_allocate_op_exit; + } + + if (m_buffer_array_op == NULL) + { + // output buffer info array not allocated; allocate here + + OMX_SWVDEC_LOG_HIGH("allocating buffer info array, %d element%s", + m_port_op.def.nBufferCountActual, + (m_port_op.def.nBufferCountActual > 1) ? "s" : ""); + + if ((retval = buffer_allocate_op_info_array()) != OMX_ErrorNone) + { + goto buffer_allocate_op_exit; + } + } + + for (ii = 0; ii < m_port_op.def.nBufferCountActual; ii++) + { + if (m_buffer_array_op[ii].buffer_populated == false) + { + OMX_SWVDEC_LOG_LOW("buffer %d not populated", ii); + break; + } + } + + if (ii < m_port_op.def.nBufferCountActual) + { + int pmem_fd = -1; + + unsigned char *bufferaddr; + + OMX_SWVDEC_LOG_HIGH("op buffer %d: %d bytes being allocated", + ii, + size); + + m_buffer_array_op[ii].ion_info.ion_fd_device = + ion_memory_alloc_map(&m_buffer_array_op[ii].ion_info.ion_alloc_data, + &m_buffer_array_op[ii].ion_info.ion_fd_data, + size, + m_port_op.def.nBufferAlignment); + + if (m_buffer_array_op[ii].ion_info.ion_fd_device < 0) + { + retval = OMX_ErrorInsufficientResources; + goto buffer_allocate_op_exit; + } + + pmem_fd = m_buffer_array_op[ii].ion_info.ion_fd_data.fd; + + bufferaddr = (unsigned char *) mmap(NULL, + size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + pmem_fd, + 0); + + if (bufferaddr == MAP_FAILED) + { + OMX_SWVDEC_LOG_ERROR("mmap() failed for fd %d of size %d", + pmem_fd, + size); + close(pmem_fd); + ion_memory_free(&m_buffer_array_op[ii].ion_info); + retval = OMX_ErrorInsufficientResources; + goto buffer_allocate_op_exit; + } + + *pp_buffer_hdr = &m_buffer_array_op[ii].buffer_header; + + m_buffer_array_op[ii].buffer_payload.bufferaddr = bufferaddr; + m_buffer_array_op[ii].buffer_payload.pmem_fd = pmem_fd; + m_buffer_array_op[ii].buffer_payload.buffer_len = size; + m_buffer_array_op[ii].buffer_payload.mmaped_size = size; + m_buffer_array_op[ii].buffer_payload.offset = 0; + + m_buffer_array_op[ii].buffer_swvdec.p_buffer = bufferaddr; + m_buffer_array_op[ii].buffer_swvdec.size = size; + m_buffer_array_op[ii].buffer_swvdec.p_client_data = + (void *) ((unsigned long) ii); + + m_buffer_array_op[ii].buffer_populated = true; + + OMX_SWVDEC_LOG_HIGH("op buffer %d: %p, %d bytes", + ii, + bufferaddr, + size); + + (*pp_buffer_hdr)->pBuffer = (OMX_U8 *) bufferaddr; + (*pp_buffer_hdr)->nSize = sizeof(OMX_BUFFERHEADERTYPE); + (*pp_buffer_hdr)->nVersion.nVersion = OMX_SPEC_VERSION; + (*pp_buffer_hdr)->nAllocLen = size; + (*pp_buffer_hdr)->pAppPrivate = p_app_data; + (*pp_buffer_hdr)->nOutputPortIndex = OMX_CORE_PORT_INDEX_OP; + (*pp_buffer_hdr)->pOutputPortPrivate = + (void *) &(m_buffer_array_op[ii].buffer_payload); + + m_port_op.populated = port_op_populated(); + m_port_op.unpopulated = OMX_FALSE; + } + else + { + OMX_SWVDEC_LOG_ERROR("all %d op buffers allocated", + m_port_op.def.nBufferCountActual); + retval = OMX_ErrorInsufficientResources; + } + +buffer_allocate_op_exit: + return retval; +} + +/** + * @brief Allocate input buffer info array. + */ +OMX_ERRORTYPE omx_swvdec::buffer_allocate_ip_info_array() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + unsigned int ii; + + OMX_BUFFERHEADERTYPE *p_buffer_hdr; + + if (m_buffer_array_ip != NULL) + { + OMX_SWVDEC_LOG_ERROR("buffer info array already allocated"); + retval = OMX_ErrorInsufficientResources; + goto buffer_allocate_ip_hdr_exit; + } + + // input buffer info array not allocated; allocate here + + OMX_SWVDEC_LOG_HIGH("allocating buffer info array, %d element%s", + m_port_ip.def.nBufferCountActual, + (m_port_ip.def.nBufferCountActual > 1) ? "s" : ""); + + m_buffer_array_ip = + (OMX_SWVDEC_BUFFER_INFO *) calloc(sizeof(OMX_SWVDEC_BUFFER_INFO), + m_port_ip.def.nBufferCountActual); + + if (m_buffer_array_ip == NULL) + { + OMX_SWVDEC_LOG_ERROR("failed to allocate buffer info array; " + "%d element%s, %d bytes requested", + m_port_ip.def.nBufferCountActual, + (m_port_ip.def.nBufferCountActual > 1) ? "s" : "", + sizeof(OMX_SWVDEC_BUFFER_INFO) * + m_port_ip.def.nBufferCountActual); + retval = OMX_ErrorInsufficientResources; + goto buffer_allocate_ip_hdr_exit; + } + + for (ii = 0; ii < m_port_ip.def.nBufferCountActual; ii++) + { + p_buffer_hdr = &m_buffer_array_ip[ii].buffer_header; + + // reset file descriptors + + m_buffer_array_ip[ii].buffer_payload.pmem_fd = -1; + m_buffer_array_ip[ii].ion_info.ion_fd_device = -1; + + m_buffer_array_ip[ii].buffer_swvdec.p_client_data = + (void *) ((unsigned long) ii); + + p_buffer_hdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + p_buffer_hdr->nVersion.nVersion = OMX_SPEC_VERSION; + p_buffer_hdr->nOutputPortIndex = OMX_CORE_PORT_INDEX_IP; + p_buffer_hdr->pOutputPortPrivate = + (void *) &(m_buffer_array_ip[ii].buffer_payload); + } + +buffer_allocate_ip_hdr_exit: + return retval; +} + +/** + * @brief Allocate output buffer info array. + */ +OMX_ERRORTYPE omx_swvdec::buffer_allocate_op_info_array() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + unsigned int ii; + + OMX_BUFFERHEADERTYPE *p_buffer_hdr; + + if (m_buffer_array_op != NULL) + { + OMX_SWVDEC_LOG_ERROR("buffer info array already allocated"); + retval = OMX_ErrorInsufficientResources; + goto buffer_allocate_op_hdr_exit; + } + + // output buffer info array not allocated; allocate here + + OMX_SWVDEC_LOG_HIGH("allocating buffer info array, %d element%s", + m_port_op.def.nBufferCountActual, + (m_port_op.def.nBufferCountActual > 1) ? "s" : ""); + + m_buffer_array_op = + (OMX_SWVDEC_BUFFER_INFO *) calloc(sizeof(OMX_SWVDEC_BUFFER_INFO), + m_port_op.def.nBufferCountActual); + + if (m_buffer_array_op == NULL) + { + OMX_SWVDEC_LOG_ERROR("failed to allocate buffer info array; " + "%d element%s, %d bytes requested", + m_port_op.def.nBufferCountActual, + (m_port_op.def.nBufferCountActual > 1) ? "s" : "", + sizeof(OMX_SWVDEC_BUFFER_INFO) * + m_port_op.def.nBufferCountActual); + retval = OMX_ErrorInsufficientResources; + goto buffer_allocate_op_hdr_exit; + } + + for (ii = 0; ii < m_port_op.def.nBufferCountActual; ii++) + { + p_buffer_hdr = &m_buffer_array_op[ii].buffer_header; + + // reset file descriptors + + m_buffer_array_op[ii].buffer_payload.pmem_fd = -1; + m_buffer_array_op[ii].ion_info.ion_fd_device = -1; + + m_buffer_array_op[ii].buffer_swvdec.p_client_data = + (void *) ((unsigned long) ii); + + p_buffer_hdr->nSize = sizeof(OMX_BUFFERHEADERTYPE); + p_buffer_hdr->nVersion.nVersion = OMX_SPEC_VERSION; + p_buffer_hdr->nOutputPortIndex = OMX_CORE_PORT_INDEX_OP; + p_buffer_hdr->pOutputPortPrivate = + (void *) &(m_buffer_array_op[ii].buffer_payload); + } + +buffer_allocate_op_hdr_exit: + return retval; +} + +/** + * @brief Use buffer allocated by IL client; allocate output buffer info array + * if necessary. + * + * @param[in,out] pp_buffer_hdr: Pointer to pointer to buffer header type + * structure. + * @param[in] p_app_data: Pointer to IL client app data. + * @param[in] size: Size of buffer to be allocated in bytes. + * @param[in] p_buffer: Pointer to buffer to be used. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::buffer_use_op( + OMX_BUFFERHEADERTYPE **pp_buffer_hdr, + OMX_PTR p_app_data, + OMX_U32 size, + OMX_U8 *p_buffer) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + unsigned int ii; + + (void) size; + + if (m_buffer_array_op == NULL) + { + // output buffer info array not allocated; allocate here + + OMX_SWVDEC_LOG_HIGH("allocating buffer info array, %d element%s", + m_port_op.def.nBufferCountActual, + (m_port_op.def.nBufferCountActual > 1) ? "s" : ""); + + if ((retval = buffer_allocate_op_info_array()) != OMX_ErrorNone) + { + goto buffer_use_op_exit; + } + } + + if (m_meta_buffer_mode && (m_meta_buffer_array == NULL)) + { + // meta buffer info array not allocated; allocate here + + OMX_SWVDEC_LOG_HIGH("allocating meta buffer info array, %d element%s", + m_port_op.def.nBufferCountActual, + (m_port_op.def.nBufferCountActual > 1) ? "s" : ""); + + if ((retval = meta_buffer_array_allocate()) != OMX_ErrorNone) + { + goto buffer_use_op_exit; + } + } + + for (ii = 0; ii < m_port_op.def.nBufferCountActual; ii++) + { + if (m_buffer_array_op[ii].buffer_populated == false) + { + OMX_SWVDEC_LOG_LOW("buffer %d not populated", ii); + break; + } + } + + if (ii < m_port_op.def.nBufferCountActual) + { + struct vdec_bufferpayload *p_buffer_payload; + + SWVDEC_BUFFER *p_buffer_swvdec; + + *pp_buffer_hdr = &m_buffer_array_op[ii].buffer_header; + p_buffer_payload = &m_buffer_array_op[ii].buffer_payload; + p_buffer_swvdec = &m_buffer_array_op[ii].buffer_swvdec; + + if (m_meta_buffer_mode) + { + p_buffer_swvdec->size = m_port_op.def.nBufferSize; + p_buffer_swvdec->p_client_data = (void *) ((unsigned long) ii); + + m_buffer_array_op[ii].buffer_populated = true; + + (*pp_buffer_hdr)->pBuffer = p_buffer; + (*pp_buffer_hdr)->pAppPrivate = p_app_data; + (*pp_buffer_hdr)->nAllocLen = + sizeof(struct VideoDecoderOutputMetaData); + + OMX_SWVDEC_LOG_HIGH("op buffer %d: %p (meta buffer)", + ii, + *pp_buffer_hdr); + + m_port_op.populated = port_op_populated(); + m_port_op.unpopulated = OMX_FALSE; + } + else if (m_android_native_buffers) + { + private_handle_t *p_handle; + + OMX_U8 *p_buffer_mapped; + + p_handle = (private_handle_t *) p_buffer; + + if (((OMX_U32) p_handle->size) < m_port_op.def.nBufferSize) + { + OMX_SWVDEC_LOG_ERROR("requested size (%d bytes) not equal to " + "configured size (%d bytes)", + p_handle->size, + m_port_op.def.nBufferSize); + + retval = OMX_ErrorBadParameter; + goto buffer_use_op_exit; + } + + m_port_op.def.nBufferSize = p_handle->size; + + p_buffer_mapped = (OMX_U8 *) mmap(NULL, + p_handle->size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + p_handle->fd, + 0); + + if (p_buffer_mapped == MAP_FAILED) + { + OMX_SWVDEC_LOG_ERROR("mmap() failed for fd %d of size %d", + p_handle->fd, + p_handle->size); + + retval = OMX_ErrorInsufficientResources; + goto buffer_use_op_exit; + } + + p_buffer_payload->bufferaddr = p_buffer_mapped; + p_buffer_payload->pmem_fd = p_handle->fd; + p_buffer_payload->buffer_len = p_handle->size; + p_buffer_payload->mmaped_size = p_handle->size; + p_buffer_payload->offset = 0; + + p_buffer_swvdec->p_buffer = p_buffer_mapped; + p_buffer_swvdec->size = m_port_op.def.nBufferSize; + p_buffer_swvdec->p_client_data = (void *) ((unsigned long) ii); + + m_buffer_array_op[ii].buffer_populated = true; + + (*pp_buffer_hdr)->pBuffer = (m_android_native_buffers ? + ((OMX_U8 *) p_handle) : + p_buffer_mapped); + (*pp_buffer_hdr)->pAppPrivate = p_app_data; + (*pp_buffer_hdr)->nAllocLen = m_port_op.def.nBufferSize; + + m_buffer_array_op[ii].ion_info.ion_fd_data.fd = p_handle->fd; + + OMX_SWVDEC_LOG_HIGH("op buffer %d: %p", + ii, + *pp_buffer_hdr); + + m_port_op.populated = port_op_populated(); + m_port_op.unpopulated = OMX_FALSE; + } + else + { + OMX_SWVDEC_LOG_ERROR("neither 'meta buffer mode' nor " + "'android native buffers' enabled"); + retval = OMX_ErrorBadParameter; + } + } + else + { + OMX_SWVDEC_LOG_ERROR("all %d op buffers populated", + m_port_op.def.nBufferCountActual); + retval = OMX_ErrorInsufficientResources; + } + +buffer_use_op_exit: + return retval; +} + +/** + * @brief De-allocate input buffer. + * + * @param[in] p_buffer_hdr: Pointer to buffer header structure. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::buffer_deallocate_ip( + OMX_BUFFERHEADERTYPE *p_buffer_hdr) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + unsigned int ii; + + if (p_buffer_hdr == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_buffer_hdr = NULL"); + retval = OMX_ErrorBadParameter; + goto buffer_deallocate_ip_exit; + } + else if (m_buffer_array_ip == NULL) + { + OMX_SWVDEC_LOG_ERROR("ip buffer array not allocated"); + retval = OMX_ErrorBadParameter; + goto buffer_deallocate_ip_exit; + } + + for (ii = 0; ii < m_port_ip.def.nBufferCountActual; ii++) + { + if (p_buffer_hdr == &(m_buffer_array_ip[ii].buffer_header)) + { + OMX_SWVDEC_LOG_LOW("%p has index %d", + p_buffer_hdr->pBuffer, + ii); + break; + } + } + + if (ii < m_port_ip.def.nBufferCountActual) + { + if (m_buffer_array_ip[ii].buffer_payload.pmem_fd > 0) + { + m_buffer_array_ip[ii].buffer_populated = false; + + m_port_ip.populated = OMX_FALSE; + + munmap(m_buffer_array_ip[ii].buffer_payload.bufferaddr, + m_buffer_array_ip[ii].buffer_payload.mmaped_size); + + close(m_buffer_array_ip[ii].buffer_payload.pmem_fd); + m_buffer_array_ip[ii].buffer_payload.pmem_fd = -1; + + ion_memory_free(&m_buffer_array_ip[ii].ion_info); + + // check if all buffers are unpopulated + for (ii = 0; ii < m_port_ip.def.nBufferCountActual; ii++) + { + if (m_buffer_array_ip[ii].buffer_populated) + break; + } + + // if no buffers are populated, de-allocate input buffer info array + if (ii == m_port_ip.def.nBufferCountActual) + { + buffer_deallocate_ip_info_array(); + m_port_ip.unpopulated = OMX_TRUE; + } + } + else + { + OMX_SWVDEC_LOG_ERROR("%p: pmem_fd %d", + p_buffer_hdr->pBuffer, + m_buffer_array_ip[ii].buffer_payload.pmem_fd); + } + } + else + { + OMX_SWVDEC_LOG_ERROR("%p not found", p_buffer_hdr->pBuffer); + retval = OMX_ErrorBadParameter; + } + +buffer_deallocate_ip_exit: + return retval; +} + +/** + * @brief De-allocate output buffer. + * + * @param[in] p_buffer_hdr: Pointer to buffer header structure. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::buffer_deallocate_op( + OMX_BUFFERHEADERTYPE *p_buffer_hdr) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + unsigned int ii; + + if (p_buffer_hdr == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_buffer_hdr = NULL"); + retval = OMX_ErrorBadParameter; + goto buffer_deallocate_op_exit; + } + else if (m_buffer_array_op == NULL) + { + OMX_SWVDEC_LOG_ERROR("op buffer array not allocated"); + retval = OMX_ErrorBadParameter; + goto buffer_deallocate_op_exit; + } + + for (ii = 0; ii < m_port_op.def.nBufferCountActual; ii++) + { + if (p_buffer_hdr == &(m_buffer_array_op[ii].buffer_header)) + { + OMX_SWVDEC_LOG_LOW("%p has index %d", + p_buffer_hdr->pBuffer, + ii); + break; + } + } + + if (ii < m_port_op.def.nBufferCountActual) + { + assert(m_buffer_array_op[ii].buffer_payload.pmem_fd > 0); + + if (m_meta_buffer_mode) + { + // do nothing; munmap() & close() done in FBD or RR + } + else if (m_android_native_buffers) + { + munmap(m_buffer_array_op[ii].buffer_payload.bufferaddr, + m_buffer_array_op[ii].buffer_payload.mmaped_size); + m_buffer_array_op[ii].buffer_payload.pmem_fd = -1; + } + else if (m_sync_frame_decoding_mode) + { + munmap(m_buffer_array_op[ii].buffer_payload.bufferaddr, + m_buffer_array_op[ii].buffer_payload.mmaped_size); + close(m_buffer_array_op[ii].buffer_payload.pmem_fd); + m_buffer_array_op[ii].buffer_payload.pmem_fd = -1; + ion_memory_free(&m_buffer_array_op[ii].ion_info); + } + else + { + assert(0); + } + + m_buffer_array_op[ii].buffer_populated = false; + + m_port_op.populated = OMX_FALSE; + + // check if all buffers are unpopulated + for (ii = 0; ii < m_port_op.def.nBufferCountActual; ii++) + { + if (m_buffer_array_op[ii].buffer_populated) + break; + } + + // if no buffers are populated, de-allocate output buffer info array + if (ii == m_port_op.def.nBufferCountActual) + { + buffer_deallocate_op_info_array(); + m_port_op.unpopulated = OMX_TRUE; + + if (m_meta_buffer_mode) + { + meta_buffer_array_deallocate(); + } + } + } + else + { + OMX_SWVDEC_LOG_ERROR("%p not found", p_buffer_hdr->pBuffer); + retval = OMX_ErrorBadParameter; + } + +buffer_deallocate_op_exit: + return retval; +} + +/** + * @brief De-allocate input buffer info array. + */ +void omx_swvdec::buffer_deallocate_ip_info_array() +{ + assert(m_buffer_array_ip != NULL); + + free(m_buffer_array_ip); + m_buffer_array_ip = NULL; +} + +/** + * @brief De-allocate output buffer info array. + */ +void omx_swvdec::buffer_deallocate_op_info_array() +{ + assert(m_buffer_array_op != NULL); + + free(m_buffer_array_op); + m_buffer_array_op = NULL; +} + +/** + * @brief Allocate meta buffer info array. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::meta_buffer_array_allocate() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + m_meta_buffer_array = ((OMX_SWVDEC_META_BUFFER_INFO *) + calloc(sizeof(OMX_SWVDEC_META_BUFFER_INFO), + m_port_op.def.nBufferCountActual)); + + if (m_meta_buffer_array == NULL) + { + OMX_SWVDEC_LOG_ERROR("failed to allocate meta_buffer info array; " + "%d element%s, %d bytes requested", + m_port_op.def.nBufferCountActual, + (m_port_op.def.nBufferCountActual > 1) ? "s" : "", + sizeof(OMX_SWVDEC_META_BUFFER_INFO) * + m_port_op.def.nBufferCountActual); + + retval = OMX_ErrorInsufficientResources; + } + + return retval; +} + +/** + * @brief De-allocate meta buffer info array. + */ +void omx_swvdec::meta_buffer_array_deallocate() +{ + assert(m_meta_buffer_array != NULL); + + free(m_meta_buffer_array); + m_meta_buffer_array = NULL; +} + +/** + * @brief Add meta buffer reference. + * + * @param[in] index: + * @param[in] fd: + * @param[in] offset: + */ +void omx_swvdec::meta_buffer_ref_add(unsigned int index, + unsigned int fd, + unsigned int offset) +{ + pthread_mutex_lock(&m_meta_buffer_array_mutex); + + if ((m_meta_buffer_array[index].dup_fd != 0) && + (m_meta_buffer_array[index].fd != fd) && + (m_meta_buffer_array[index].offset != offset)) + { + OMX_SWVDEC_LOG_LOW("index %d taken by fd %d, offset %d", + index, + m_meta_buffer_array[index].fd, + m_meta_buffer_array[index].offset); + } + else + { + if (m_meta_buffer_array[index].dup_fd == 0) + { + m_meta_buffer_array[index].fd = fd; + m_meta_buffer_array[index].dup_fd = dup(fd); + m_meta_buffer_array[index].offset = offset; + } + + m_meta_buffer_array[index].ref_count++; + } + + pthread_mutex_unlock(&m_meta_buffer_array_mutex); +} + +/** + * @brief Remove meta buffer reference. + * + * @param[in] fd: + * @param[in] offset: + */ +void omx_swvdec::meta_buffer_ref_remove(unsigned int fd, + unsigned int offset) +{ + unsigned int ii; + + pthread_mutex_lock(&m_meta_buffer_array_mutex); + + for (ii = 0; ii < m_port_op.def.nBufferCountActual; ii++) + { + if ((m_meta_buffer_array[ii].fd == fd) && + (m_meta_buffer_array[ii].offset == offset)) + { + m_meta_buffer_array[ii].ref_count--; + + if (m_meta_buffer_array[ii].ref_count == 0) + { + close(m_meta_buffer_array[ii].dup_fd); + + m_meta_buffer_array[ii].fd = 0; + m_meta_buffer_array[ii].dup_fd = 0; + m_meta_buffer_array[ii].offset = 0; + + munmap(m_buffer_array_op[ii].buffer_payload.bufferaddr, + m_buffer_array_op[ii].buffer_payload.mmaped_size); + + m_buffer_array_op[ii].buffer_payload.bufferaddr = NULL; + m_buffer_array_op[ii].buffer_payload.offset = 0; + m_buffer_array_op[ii].buffer_payload.mmaped_size = 0; + + m_buffer_array_op[ii].buffer_swvdec.p_buffer = NULL; + m_buffer_array_op[ii].buffer_swvdec.size = 0; + } + + break; + } + } + + assert(ii < m_port_op.def.nBufferCountActual); + + pthread_mutex_unlock(&m_meta_buffer_array_mutex); +} + +/** + * @brief Check if ip port is populated, i.e., if all ip buffers are populated. + * + * @retval true + * @retval false + */ +OMX_BOOL omx_swvdec::port_ip_populated() +{ + OMX_BOOL retval = OMX_FALSE; + + if (m_buffer_array_ip != NULL) + { + unsigned int ii; + + for (ii = 0; ii < m_port_ip.def.nBufferCountActual; ii++) + { + if (m_buffer_array_ip[ii].buffer_populated == false) + { + break; + } + } + + if (ii == m_port_ip.def.nBufferCountActual) + { + retval = OMX_TRUE; + } + } + + return retval; +} + +/** + * @brief Check if op port is populated, i.e., if all op buffers are populated. + * + * @retval true + * @retval false + */ +OMX_BOOL omx_swvdec::port_op_populated() +{ + OMX_BOOL retval = OMX_FALSE; + + if (m_buffer_array_op != NULL) + { + unsigned int ii; + + for (ii = 0; ii < m_port_op.def.nBufferCountActual; ii++) + { + if (m_buffer_array_op[ii].buffer_populated == false) + { + break; + } + } + + if (ii == m_port_op.def.nBufferCountActual) + { + retval = OMX_TRUE; + } + } + + return retval; +} + +/** + * @brief Flush input, output, or both input & output ports. + * + * @param[in] port_index: Index of port to flush. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::flush(unsigned int port_index) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (((port_index == OMX_CORE_PORT_INDEX_IP) && + m_port_ip.flush_inprogress) || + ((port_index == OMX_CORE_PORT_INDEX_OP) && + m_port_op.flush_inprogress) || + ((port_index == OMX_ALL) && + m_port_ip.flush_inprogress && + m_port_op.flush_inprogress)) + { + OMX_SWVDEC_LOG_HIGH("flush port %d already in progress", port_index); + } + else + { + SWVDEC_FLUSH_TYPE swvdec_flush_type; + + SWVDEC_STATUS retval_swvdec; + + if (port_index == OMX_CORE_PORT_INDEX_IP) + { + m_port_ip.flush_inprogress = OMX_TRUE; + + // no separate SwVdec flush type for input + } + else if (port_index == OMX_CORE_PORT_INDEX_OP) + { + m_port_op.flush_inprogress = OMX_TRUE; + + swvdec_flush_type = (m_port_ip.flush_inprogress ? + SWVDEC_FLUSH_TYPE_ALL : + SWVDEC_FLUSH_TYPE_OP); + + if ((retval_swvdec = swvdec_flush(m_swvdec_handle, + swvdec_flush_type)) != + SWVDEC_STATUS_SUCCESS) + { + retval = retval_swvdec2omx(retval_swvdec); + } + } + else if (port_index == OMX_ALL) + { + m_port_ip.flush_inprogress = OMX_TRUE; + m_port_op.flush_inprogress = OMX_TRUE; + + swvdec_flush_type = SWVDEC_FLUSH_TYPE_ALL; + + if ((retval_swvdec = swvdec_flush(m_swvdec_handle, + swvdec_flush_type)) != + SWVDEC_STATUS_SUCCESS) + { + retval = retval_swvdec2omx(retval_swvdec); + } + } + else + { + assert(0); + } + } + + return retval; +} + +/** + * @brief Allocate & map ION memory. + */ +int omx_swvdec::ion_memory_alloc_map(struct ion_allocation_data *p_alloc_data, + struct ion_fd_data *p_fd_data, + OMX_U32 size, + OMX_U32 alignment) +{ + int fd = -EINVAL; + int rc = -EINVAL; + + if ((p_alloc_data == NULL) || (p_fd_data == NULL) || (size == 0)) + { + OMX_SWVDEC_LOG_ERROR("invalid arguments"); + goto ion_memory_alloc_map_exit; + } + + if ((fd = open("/dev/ion", O_RDONLY)) < 0) + { + OMX_SWVDEC_LOG_ERROR("failed to open ion device; fd = %d", fd); + goto ion_memory_alloc_map_exit; + } + + p_alloc_data->len = size; + p_alloc_data->align = (alignment < 4096) ? 4096 : alignment; + p_alloc_data->heap_id_mask = ION_HEAP(ION_IOMMU_HEAP_ID); + p_alloc_data->flags = 0; + + OMX_SWVDEC_LOG_LOW("heap_id_mask 0x%08x, len %d, align %d", + p_alloc_data->heap_id_mask, + p_alloc_data->len, + p_alloc_data->align); + + rc = ioctl(fd, ION_IOC_ALLOC, p_alloc_data); + + if (rc || (p_alloc_data->handle == 0)) + { + OMX_SWVDEC_LOG_ERROR("ioctl() for allocation failed"); + close(fd); + fd = -ENOMEM; + goto ion_memory_alloc_map_exit; + } + + p_fd_data->handle = p_alloc_data->handle; + + if (ioctl(fd, ION_IOC_MAP, p_fd_data)) + { + struct vdec_ion ion_buf_info; + + OMX_SWVDEC_LOG_ERROR("ioctl() for mapping failed"); + + ion_buf_info.ion_alloc_data = *p_alloc_data; + ion_buf_info.ion_fd_device = fd; + ion_buf_info.ion_fd_data = *p_fd_data; + + ion_memory_free(&ion_buf_info); + + p_fd_data->fd = -1; + close(fd); + fd = -ENOMEM; + goto ion_memory_alloc_map_exit; + } + +ion_memory_alloc_map_exit: + return fd; +} + +/** + * @brief Free ION memory. + */ +void omx_swvdec::ion_memory_free(struct vdec_ion *p_ion_buf_info) +{ + if (p_ion_buf_info == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_ion_buf_info = NULL"); + goto ion_memory_free_exit; + } + + if (ioctl(p_ion_buf_info->ion_fd_device, + ION_IOC_FREE, + &p_ion_buf_info->ion_alloc_data.handle)) + { + OMX_SWVDEC_LOG_ERROR("ioctl() for freeing failed"); + } + + close(p_ion_buf_info->ion_fd_device); + + p_ion_buf_info->ion_fd_device = -1; + p_ion_buf_info->ion_alloc_data.handle = 0; + p_ion_buf_info->ion_fd_data.fd = -1; + +ion_memory_free_exit: + return; +} + +/** + * ---------------------------- + * component callback functions + * ---------------------------- + */ + +/** + * @brief Empty buffer done callback. + * + * @param[in] p_buffer_ip: Pointer to input buffer structure. + */ +void omx_swvdec::swvdec_empty_buffer_done(SWVDEC_BUFFER *p_buffer_ip) +{ + unsigned long index = (unsigned long) p_buffer_ip->p_client_data; + + async_post_event(OMX_SWVDEC_EVENT_EBD, + (unsigned long) &m_buffer_array_ip[index].buffer_header, + index); +} + +/** + * @brief Fill buffer done callback. + * + * @param[in] p_buffer_op: Pointer to output buffer structure. + */ +void omx_swvdec::swvdec_fill_buffer_done(SWVDEC_BUFFER *p_buffer_op) +{ + unsigned long index = (unsigned long) p_buffer_op->p_client_data; + + OMX_BUFFERHEADERTYPE *p_buffer_hdr; + + if (index < ((unsigned long) m_port_op.def.nBufferCountActual)) + { + p_buffer_hdr = &m_buffer_array_op[index].buffer_header; + + p_buffer_hdr->nFlags = p_buffer_op->flags; + p_buffer_hdr->nTimeStamp = p_buffer_op->timestamp; + p_buffer_hdr->nFilledLen = ((m_meta_buffer_mode && + p_buffer_op->filled_length) ? + p_buffer_hdr->nAllocLen : + p_buffer_op->filled_length); + } + + async_post_event(OMX_SWVDEC_EVENT_FBD, + (unsigned long) &m_buffer_array_op[index].buffer_header, + index); +} + +/** + * @brief Event handler callback. + * + * @param[in] event: Event. + * @param[in] p_data: Pointer to event-specific data. + */ +void omx_swvdec::swvdec_event_handler(SWVDEC_EVENT event, void *p_data) +{ + switch (event) + { + + case SWVDEC_EVENT_FLUSH_ALL_DONE: + { + async_post_event(OMX_SWVDEC_EVENT_FLUSH_PORT_IP, 0, 0); + async_post_event(OMX_SWVDEC_EVENT_FLUSH_PORT_OP, 0, 0); + break; + } + + case SWVDEC_EVENT_FLUSH_OP_DONE: + { + async_post_event(OMX_SWVDEC_EVENT_FLUSH_PORT_OP, 0, 0); + break; + } + + case SWVDEC_EVENT_RELEASE_REFERENCE: + { + SWVDEC_BUFFER *p_buffer_op = (SWVDEC_BUFFER *) p_data; + + unsigned long index = (unsigned long) p_buffer_op->p_client_data; + + OMX_SWVDEC_LOG_LOW("release reference: %p", p_buffer_op->p_buffer); + + assert(index < ((unsigned long) m_port_op.def.nBufferCountActual)); + + if (m_meta_buffer_mode) + { + meta_buffer_ref_remove( + m_buffer_array_op[index].buffer_payload.pmem_fd, + m_buffer_array_op[index].buffer_payload.offset); + } + + break; + } + + case SWVDEC_EVENT_RECONFIG_REQUIRED: + { + async_post_event(OMX_SWVDEC_EVENT_PORT_RECONFIG, 0, 0); + break; + } + + case SWVDEC_EVENT_FATAL_ERROR: + default: + { + async_post_event(OMX_SWVDEC_EVENT_ERROR, OMX_ErrorHardware, 0); + break; + } + + } +} + +/** + * @brief Translate SwVdec status return value to OMX error type return value. + * + * @param[in] retval_swvdec: SwVdec status return value. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::retval_swvdec2omx(SWVDEC_STATUS retval_swvdec) +{ + OMX_ERRORTYPE retval_omx; + + switch (retval_swvdec) + { + + SWVDEC_STATUS_SUCCESS: + retval_omx = OMX_ErrorNone; + break; + + SWVDEC_STATUS_FAILURE: + retval_omx = OMX_ErrorUndefined; + break; + + SWVDEC_STATUS_NULL_POINTER: + SWVDEC_STATUS_INVALID_PARAMETERS: + retval_omx = OMX_ErrorBadParameter; + break; + + SWVDEC_STATUS_INVALID_STATE: + retval_omx = OMX_ErrorInvalidState; + break; + + SWVDEC_STATUS_INSUFFICIENT_RESOURCES: + retval_omx = OMX_ErrorInsufficientResources; + break; + + SWVDEC_STATUS_UNSUPPORTED: + retval_omx = OMX_ErrorUnsupportedSetting; + break; + + SWVDEC_STATUS_NOT_IMPLEMENTED: + retval_omx = OMX_ErrorNotImplemented; + break; + + default: + retval_omx = OMX_ErrorUndefined; + break; + + } + + return retval_omx; +} + +/** + * @brief Create asynchronous thread. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_thread_create() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + pthread_attr_t thread_attributes; + + if (sem_init(&m_async_thread.sem_thread_created, 0, 0)) + { + OMX_SWVDEC_LOG_ERROR("failed to create async thread created semaphore"); + retval = OMX_ErrorInsufficientResources; + } + else if (sem_init(&m_async_thread.sem_event, 0, 0)) + { + OMX_SWVDEC_LOG_ERROR("failed to create async thread event semaphore"); + retval = OMX_ErrorInsufficientResources; + } + else if (pthread_attr_init(&thread_attributes)) + { + OMX_SWVDEC_LOG_ERROR("failed to create thread attributes object"); + retval = OMX_ErrorInsufficientResources; + } + else if (pthread_attr_setdetachstate(&thread_attributes, + PTHREAD_CREATE_JOINABLE)) + { + OMX_SWVDEC_LOG_ERROR("failed to set detach state attribute"); + retval = OMX_ErrorInsufficientResources; + + pthread_attr_destroy(&thread_attributes); + } + else + { + m_async_thread.created = false; + m_async_thread.exit = false; + + if (pthread_create(&m_async_thread.handle, + &thread_attributes, + (void *(*)(void *)) async_thread, + this)) + { + OMX_SWVDEC_LOG_ERROR("failed to create async thread"); + retval = OMX_ErrorInsufficientResources; + + pthread_attr_destroy(&thread_attributes); + } + else + { + if (pthread_setname_np(m_async_thread.handle, "swvdec_async")) + { + // don't return error + OMX_SWVDEC_LOG_ERROR("failed to set async thread name"); + } + + sem_wait(&m_async_thread.sem_thread_created); + m_async_thread.created = true; + } + } + + return retval; +} + +/** + * @brief Destroy asynchronous thread. + */ +void omx_swvdec::async_thread_destroy() +{ + if (m_async_thread.created) + { + m_async_thread.exit = true; + sem_post(&m_async_thread.sem_event); + + pthread_join(m_async_thread.handle, NULL); + m_async_thread.created = false; + } + + m_async_thread.exit = false; + + sem_destroy(&m_async_thread.sem_event); + sem_destroy(&m_async_thread.sem_thread_created); +} + +/** + * @brief Post event to appropriate queue. + * + * @param[in] event_id: Event ID. + * @param[in] event_param1: Event parameter 1. + * @param[in] event_param2: Event parameter 2. + * + * @retval true if post event successful + * @retval false if post event unsuccessful + */ +bool omx_swvdec::async_post_event(unsigned long event_id, + unsigned long event_param1, + unsigned long event_param2) +{ + OMX_SWVDEC_EVENT_INFO event_info; + + bool retval = true; + + event_info.event_id = event_id; + event_info.event_param1 = event_param1; + event_info.event_param2 = event_param2; + + switch (event_id) + { + + case OMX_SWVDEC_EVENT_ETB: + case OMX_SWVDEC_EVENT_EBD: + { + retval = m_queue_port_ip.push(&event_info); + break; + } + + case OMX_SWVDEC_EVENT_FTB: + case OMX_SWVDEC_EVENT_FBD: + { + retval = m_queue_port_op.push(&event_info); + break; + } + + default: + { + retval = m_queue_command.push(&event_info); + break; + } + + } + + if (retval == true) + { + sem_post(&m_async_thread.sem_event); + } + + return retval; +} + +/** + * @brief Asynchronous thread. + * + * @param[in] p_cmp: Pointer to OMX SwVdec component class. + */ +void omx_swvdec::async_thread(void *p_cmp) +{ + if (p_cmp == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_cmp = NULL"); + } + else + { + omx_swvdec *p_omx_swvdec = (omx_swvdec *) p_cmp; + + ASYNC_THREAD *p_async_thread = &p_omx_swvdec->m_async_thread; + + OMX_SWVDEC_LOG_HIGH("created"); + + sem_post(&p_async_thread->sem_thread_created); + + while (p_async_thread->exit == false) + { + sem_wait(&p_async_thread->sem_event); + + if (p_async_thread->exit == true) + { + break; + } + + p_omx_swvdec->async_process_event(p_cmp); + } + } + + OMX_SWVDEC_LOG_HIGH("exiting"); +} + +/** + * @brief Process event. + * + * @param[in] p_cmp: Pointer to OMX SwVdec component class. + */ +void omx_swvdec::async_process_event(void *p_cmp) +{ + omx_swvdec *p_omx_swvdec; + + OMX_SWVDEC_EVENT_INFO event_info; + + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (p_cmp == NULL) + { + OMX_SWVDEC_LOG_ERROR("p_cmp = NULL"); + goto async_process_event_exit; + } + + p_omx_swvdec = (omx_swvdec *) p_cmp; + + // NOTE: queues popped in order of priority; do not change! + + if ((p_omx_swvdec->m_queue_command.pop(&event_info) == false) && + (p_omx_swvdec->m_queue_port_op.pop(&event_info) == false) && + (p_omx_swvdec->m_queue_port_ip.pop(&event_info) == false)) + { + OMX_SWVDEC_LOG_LOW("no event popped"); + goto async_process_event_exit; + } + + switch (event_info.event_id) + { + + case OMX_SWVDEC_EVENT_CMD: + { + OMX_COMMANDTYPE cmd = (OMX_COMMANDTYPE) event_info.event_param1; + OMX_U32 param = (OMX_U32) event_info.event_param2; + + retval = p_omx_swvdec->async_process_event_cmd(cmd, param); + break; + } + + case OMX_SWVDEC_EVENT_CMD_ACK: + { + OMX_COMMANDTYPE cmd = (OMX_COMMANDTYPE) event_info.event_param1; + OMX_U32 param = (OMX_U32) event_info.event_param2; + + retval = p_omx_swvdec->async_process_event_cmd_ack(cmd, param); + break; + } + + case OMX_SWVDEC_EVENT_ERROR: + { + OMX_ERRORTYPE error_code = (OMX_ERRORTYPE) event_info.event_param1; + + retval = p_omx_swvdec->async_process_event_error(error_code); + break; + } + + case OMX_SWVDEC_EVENT_ETB: + { + OMX_BUFFERHEADERTYPE *p_buffer_hdr = + (OMX_BUFFERHEADERTYPE *) event_info.event_param1; + + unsigned int index = event_info.event_param2; + + retval = p_omx_swvdec->async_process_event_etb(p_buffer_hdr, index); + break; + } + + case OMX_SWVDEC_EVENT_FTB: + { + OMX_BUFFERHEADERTYPE *p_buffer_hdr = + (OMX_BUFFERHEADERTYPE *) event_info.event_param1; + + unsigned int index = event_info.event_param2; + + retval = p_omx_swvdec->async_process_event_ftb(p_buffer_hdr, index); + break; + } + + case OMX_SWVDEC_EVENT_EBD: + { + OMX_BUFFERHEADERTYPE *p_buffer_hdr = + (OMX_BUFFERHEADERTYPE *) event_info.event_param1; + + unsigned int index = event_info.event_param2; + + retval = p_omx_swvdec->async_process_event_ebd(p_buffer_hdr, index); + break; + } + + case OMX_SWVDEC_EVENT_FBD: + { + OMX_BUFFERHEADERTYPE *p_buffer_hdr = + (OMX_BUFFERHEADERTYPE *) event_info.event_param1; + + unsigned int index = event_info.event_param2; + + retval = p_omx_swvdec->async_process_event_fbd(p_buffer_hdr, index); + break; + } + + case OMX_SWVDEC_EVENT_EOS: + { + retval = p_omx_swvdec->async_process_event_eos(); + break; + } + + case OMX_SWVDEC_EVENT_FLUSH_PORT_IP: + { + retval = p_omx_swvdec->async_process_event_flush_port_ip(); + break; + } + + case OMX_SWVDEC_EVENT_FLUSH_PORT_OP: + { + retval = p_omx_swvdec->async_process_event_flush_port_op(); + break; + } + + case OMX_SWVDEC_EVENT_PORT_RECONFIG: + { + retval = p_omx_swvdec->async_process_event_port_reconfig(); + break; + } + + default: + { + assert(0); + retval = OMX_ErrorUndefined; + break; + } + + } + + if (retval != OMX_ErrorNone) + { + p_omx_swvdec->async_post_event(OMX_SWVDEC_EVENT_ERROR, retval, 0); + } + +async_process_event_exit: + return; +} + +/** + * @brief Process command event. + * + * @param[in] cmd: Command. + * @param[in] param: Command parameter. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_cmd(OMX_COMMANDTYPE cmd, + OMX_U32 param) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + bool cmd_ack = false; // set to 'true' if command is to be acknowledged + + SWVDEC_STATUS retval_swvdec; + + switch (cmd) + { + + case OMX_CommandStateSet: + { + retval = async_process_event_cmd_state_set(&cmd_ack, + (OMX_STATETYPE) param); + break; + } + + case OMX_CommandFlush: + { + retval = async_process_event_cmd_flush((unsigned int) param); + break; + } + + case OMX_CommandPortDisable: + { + retval = async_process_event_cmd_port_disable(&cmd_ack, + (unsigned int) param); + break; + } + + case OMX_CommandPortEnable: + { + retval = async_process_event_cmd_port_enable(&cmd_ack, + (unsigned int) param); + break; + } + + default: + { + OMX_SWVDEC_LOG_ERROR("cmd '%d' invalid", (int) cmd); + + retval = OMX_ErrorBadParameter; + break; + } + + } // switch (cmd) + + // post appropriate event + + if (retval != OMX_ErrorNone) + { + async_post_event(OMX_SWVDEC_EVENT_ERROR, retval, 0); + } + else if (cmd_ack) + { + async_post_event(OMX_SWVDEC_EVENT_CMD_ACK, cmd, param); + } + + // post to command semaphore + sem_post(&m_sem_cmd); + + return retval; +} + +/** + * @brief Process command acknowledgement event. + * + * @param[in] cmd: Command. + * @param[in] param: Command parameter. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_cmd_ack(OMX_COMMANDTYPE cmd, + OMX_U32 param) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + switch (cmd) + { + + case OMX_CommandStateSet: + { + m_state = (OMX_STATETYPE) param; + + OMX_SWVDEC_LOG_CALLBACK("EventHandler(): OMX_EventCmdComplete, " + "OMX_CommandStateSet, %s", + OMX_STATETYPE_STRING(m_state)); + + m_callback.EventHandler(&m_cmp, + m_app_data, + OMX_EventCmdComplete, + OMX_CommandStateSet, + (OMX_U32) m_state, + NULL); + break; + } + + case OMX_CommandFlush: + case OMX_CommandPortEnable: + case OMX_CommandPortDisable: + { + if ((cmd == OMX_CommandPortEnable) && m_port_reconfig_inprogress) + { + m_port_reconfig_inprogress = false; + } + + OMX_SWVDEC_LOG_CALLBACK("EventHandler(): OMX_EventCmdComplete, " + "%s, port index %d", + OMX_COMMANDTYPE_STRING(cmd), + param); + + m_callback.EventHandler(&m_cmp, + m_app_data, + OMX_EventCmdComplete, + cmd, + param, + NULL); + break; + } + + default: + { + OMX_SWVDEC_LOG_ERROR("cmd '%d' invalid", (int) cmd); + retval = OMX_ErrorBadParameter; + break; + } + + } // switch (cmd) + + return retval; +} + +/** + * @brief Process error event. + * + * @param[in] error_code: Error code. + * + * @retval OMX_ErrorNone + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_error(OMX_ERRORTYPE error_code) +{ + if (error_code == OMX_ErrorInvalidState) + { + m_state = OMX_StateInvalid; + } + + OMX_SWVDEC_LOG_CALLBACK("EventHandler(): OMX_EventError, 0x%08x", + error_code); + + m_callback.EventHandler(&m_cmp, + m_app_data, + OMX_EventError, + (OMX_U32) error_code, + 0, + NULL); + + return OMX_ErrorNone; +} + +/** + * @brief Process OMX_CommandStateSet. + * + * @param[in,out] p_cmd_ack: Pointer to 'command acknowledge' boolean variable. + * @param[in] state_new: New state to which transition is requested. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_cmd_state_set( + bool *p_cmd_ack, + OMX_STATETYPE state_new) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + SWVDEC_STATUS retval_swvdec; + + OMX_SWVDEC_LOG_HIGH("'%s-to-%s' requested", + OMX_STATETYPE_STRING(m_state), + OMX_STATETYPE_STRING(state_new)); + + /** + * Only the following state transitions are allowed via CommandStateSet: + * + * LOADED -> IDLE -> EXECUTING + * LOADED <- IDLE <- EXECUTING + */ + + if (m_state == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("in state %s", OMX_STATETYPE_STRING(m_state)); + retval = OMX_ErrorInvalidState; + } + else if (state_new == OMX_StateInvalid) + { + OMX_SWVDEC_LOG_ERROR("requested transition to state %s", + OMX_STATETYPE_STRING(state_new)); + retval = OMX_ErrorInvalidState; + } + else if ((m_state == OMX_StateLoaded) && + (state_new == OMX_StateIdle)) + { + if ((m_port_ip.populated == OMX_TRUE) && + (m_port_op.populated == OMX_TRUE)) + { + // start SwVdec + if ((retval_swvdec = swvdec_start(m_swvdec_handle)) == + SWVDEC_STATUS_SUCCESS) + { + *p_cmd_ack = true; + } + else + { + OMX_SWVDEC_LOG_ERROR("failed to start SwVdec"); + retval = retval_swvdec2omx(retval_swvdec); + } + } + else + { + m_status_flags |= (1 << PENDING_STATE_LOADED_TO_IDLE); + + OMX_SWVDEC_LOG_LOW("'loaded-to-idle' pending"); + } + } + else if ((m_state == OMX_StateIdle) && + (state_new == OMX_StateExecuting)) + { + *p_cmd_ack = true; + } + else if ((m_state == OMX_StateExecuting) && + (state_new == OMX_StateIdle)) + { + m_status_flags |= (1 << PENDING_STATE_EXECUTING_TO_IDLE); + + OMX_SWVDEC_LOG_LOW("'executing-to-idle' pending"); + + retval = flush(OMX_ALL); + } + else if ((m_state == OMX_StateIdle) && + (state_new == OMX_StateLoaded)) + { + if ((m_port_ip.unpopulated == OMX_TRUE) && + (m_port_op.unpopulated == OMX_TRUE)) + { + // stop SwVdec + if ((retval_swvdec = swvdec_stop(m_swvdec_handle)) == + SWVDEC_STATUS_SUCCESS) + { + *p_cmd_ack = true; + } + else + { + OMX_SWVDEC_LOG_ERROR("failed to stop SwVdec"); + retval = retval_swvdec2omx(retval_swvdec); + } + } + else + { + m_status_flags |= (1 << PENDING_STATE_IDLE_TO_LOADED); + + OMX_SWVDEC_LOG_LOW("'idle-to-loaded' pending"); + } + } + else + { + OMX_SWVDEC_LOG_ERROR("state transition '%s -> %s' illegal", + OMX_STATETYPE_STRING(m_state), + OMX_STATETYPE_STRING(state_new)); + + retval = ((state_new == m_state) ? + OMX_ErrorSameState : + OMX_ErrorIncorrectStateTransition); + } + + return retval; +} + +/** + * @brief Process OMX_CommandFlush. + * + * @param[in] port_index: Index of port to flush. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_cmd_flush(unsigned int port_index) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + OMX_SWVDEC_LOG_HIGH("flush port %d requested", port_index); + + if (port_index == OMX_CORE_PORT_INDEX_IP) + { + m_status_flags |= (1 << PENDING_PORT_FLUSH_IP); + + OMX_SWVDEC_LOG_LOW("ip port flush pending"); + } + else if (port_index == OMX_CORE_PORT_INDEX_OP) + { + m_status_flags |= (1 << PENDING_PORT_FLUSH_OP); + + OMX_SWVDEC_LOG_LOW("op port flush pending"); + } + else if (port_index == OMX_ALL) + { + m_status_flags |= (1 << PENDING_PORT_FLUSH_IP); + m_status_flags |= (1 << PENDING_PORT_FLUSH_OP); + + OMX_SWVDEC_LOG_LOW("ip & op ports flush pending"); + } + + retval = flush(port_index); + + return retval; +} + +/** + * @brief Process OMX_CommandPortDisable. + * + * @param[in,out] p_cmd_ack: Pointer to 'command acknowledge' boolean variable. + * @param[in] port_index: Index of port to disable. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_cmd_port_disable( + bool *p_cmd_ack, + unsigned int port_index) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + OMX_SWVDEC_LOG_HIGH("disable port %d requested", port_index); + + if (port_index == OMX_CORE_PORT_INDEX_IP) + { + if (m_port_ip.enabled == OMX_FALSE) + { + OMX_SWVDEC_LOG_ERROR("ip port already disabled"); + retval = OMX_ErrorBadPortIndex; + } + else + { + m_port_ip.enabled = OMX_FALSE; + + if (m_port_ip.unpopulated) + { + *p_cmd_ack = true; + } + else + { + m_status_flags |= (1 << PENDING_PORT_DISABLE_IP); + + OMX_SWVDEC_LOG_LOW("ip port disable pending"); + + if (m_port_ip.num_pending_buffers) + { + retval = flush(port_index); + } + } + } + } + else if (port_index == OMX_CORE_PORT_INDEX_OP) + { + if (m_port_op.enabled == OMX_FALSE) + { + OMX_SWVDEC_LOG_ERROR("op port already disabled"); + retval = OMX_ErrorBadPortIndex; + } + else + { + m_port_op.enabled = OMX_FALSE; + + if (m_port_op.unpopulated) + { + *p_cmd_ack = true; + } + else + { + m_status_flags |= (1 << PENDING_PORT_DISABLE_OP); + + OMX_SWVDEC_LOG_LOW("op port disable pending"); + + if (m_port_op.num_pending_buffers) + { + retval = flush(port_index); + } + } + } + } + else if (port_index == OMX_ALL) + { + if (m_port_ip.enabled == OMX_FALSE) + { + OMX_SWVDEC_LOG_ERROR("ip port already disabled"); + retval = OMX_ErrorBadPortIndex; + } + else if (m_port_op.enabled == OMX_FALSE) + { + OMX_SWVDEC_LOG_ERROR("op port already disabled"); + retval = OMX_ErrorBadPortIndex; + } + else + { + if (m_port_ip.unpopulated && m_port_op.unpopulated) + { + *p_cmd_ack = true; + } + else + { + m_port_ip.enabled = OMX_FALSE; + m_port_op.enabled = OMX_FALSE; + + if (m_port_ip.unpopulated == OMX_FALSE) + { + m_status_flags |= (1 << PENDING_PORT_DISABLE_IP); + + OMX_SWVDEC_LOG_LOW("ip port disable pending"); + + if (m_port_ip.num_pending_buffers) + { + retval = flush(port_index); + } + } + + if ((retval == OMX_ErrorNone) && + (m_port_op.unpopulated == OMX_FALSE)) + { + m_status_flags |= (1 << PENDING_PORT_DISABLE_OP); + + OMX_SWVDEC_LOG_LOW("op port disable pending"); + + if (m_port_op.num_pending_buffers) + { + retval = flush(port_index); + } + } + } + } + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid"); + retval = OMX_ErrorBadPortIndex; + } + + return retval; +} + +/** + * @brief Process OMX_CommandPortEnable. + * + * @param[in,out] p_cmd_ack: Pointer to 'command acknowledge' boolean variable. + * @param[in] port_index: Index of port to enable. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_cmd_port_enable( + bool *p_cmd_ack, + unsigned int port_index) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + OMX_SWVDEC_LOG_HIGH("enable port %d requested", port_index); + + if (port_index == OMX_CORE_PORT_INDEX_IP) + { + if (m_port_ip.enabled) + { + OMX_SWVDEC_LOG_ERROR("ip port already enabled"); + retval = OMX_ErrorBadPortIndex; + } + else + { + m_port_ip.enabled = OMX_TRUE; + + if (m_port_ip.populated) + { + *p_cmd_ack = true; + } + else + { + m_status_flags |= (1 << PENDING_PORT_ENABLE_IP); + + OMX_SWVDEC_LOG_LOW("ip port enable pending"); + } + } + } + else if (port_index == OMX_CORE_PORT_INDEX_OP) + { + if (m_port_op.enabled) + { + OMX_SWVDEC_LOG_ERROR("op port already enabled"); + retval = OMX_ErrorBadPortIndex; + } + else + { + m_port_op.enabled = OMX_TRUE; + + if (m_port_op.populated) + { + *p_cmd_ack = true; + } + else + { + m_status_flags |= (1 << PENDING_PORT_ENABLE_OP); + + OMX_SWVDEC_LOG_LOW("op port enable pending"); + } + } + } + else if (port_index == OMX_ALL) + { + if (m_port_ip.enabled) + { + OMX_SWVDEC_LOG_ERROR("ip port already enabled"); + retval = OMX_ErrorBadPortIndex; + } + else if (m_port_op.enabled) + { + OMX_SWVDEC_LOG_ERROR("op port already enabled"); + retval = OMX_ErrorBadPortIndex; + } + else + { + m_port_ip.enabled = OMX_TRUE; + m_port_op.enabled = OMX_TRUE; + + if (m_port_ip.populated && m_port_op.populated) + { + *p_cmd_ack = true; + } + else if (m_port_ip.populated == false) + { + m_status_flags |= (1 << PENDING_PORT_ENABLE_IP); + + OMX_SWVDEC_LOG_LOW("ip port enable pending"); + } + else if (m_port_op.populated == false) + { + m_status_flags |= (1 << PENDING_PORT_ENABLE_OP); + + OMX_SWVDEC_LOG_LOW("op port enable pending"); + } + } + } + else + { + OMX_SWVDEC_LOG_ERROR("port index '%d' invalid"); + retval = OMX_ErrorBadPortIndex; + } + + return retval; +} + +/** + * @brief Process ETB event. + * + * @param[in] p_buffer_hdr: Pointer to buffer header. + * @param[in] index: Index of buffer in input buffer info array. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_etb( + OMX_BUFFERHEADERTYPE *p_buffer_hdr, + unsigned int index) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + m_port_ip.num_pending_buffers++; + + if ((p_buffer_hdr->nFilledLen == 0) && + ((p_buffer_hdr->nFlags & OMX_BUFFERFLAG_EOS) == 0)) + { + OMX_SWVDEC_LOG_HIGH("returning %p, buffer %p; " + "zero length & no EOS flag", + p_buffer_hdr, + p_buffer_hdr->pBuffer); + + async_post_event(OMX_SWVDEC_EVENT_EBD, + (unsigned long) p_buffer_hdr, + (unsigned long) index); + } + else if (m_port_ip.flush_inprogress) + { + OMX_SWVDEC_LOG_HIGH("returning %p, buffer %p; " + "ip port flush in progress", + p_buffer_hdr, + p_buffer_hdr->pBuffer); + + async_post_event(OMX_SWVDEC_EVENT_EBD, + (unsigned long) p_buffer_hdr, + (unsigned long) index); + } + else + { + SWVDEC_STATUS retval_swvdec; + + SWVDEC_BUFFER *p_buffer_swvdec = + &(m_buffer_array_ip[index].buffer_swvdec); + + if (p_buffer_hdr->nFilledLen && + ((p_buffer_hdr->nFlags & OMX_BUFFERFLAG_CODECCONFIG) == 0)) + { + m_ts_list.push(p_buffer_hdr->nTimeStamp); + } + + assert(p_buffer_swvdec->p_buffer == p_buffer_hdr->pBuffer); + + p_buffer_swvdec->flags = p_buffer_hdr->nFlags; + p_buffer_swvdec->timestamp = p_buffer_hdr->nTimeStamp; + p_buffer_swvdec->filled_length = p_buffer_hdr->nFilledLen; + + m_diag.dump_ip(p_buffer_swvdec->p_buffer, + p_buffer_swvdec->filled_length); + + retval_swvdec = swvdec_emptythisbuffer(m_swvdec_handle, + p_buffer_swvdec); + + if (retval_swvdec != SWVDEC_STATUS_SUCCESS) + { + retval = retval_swvdec2omx(retval_swvdec); + } + } + + return retval; +} + +/** + * @brief Process FTB event. + * + * @param[in] p_buffer_hdr: Pointer to buffer header. + * @param[in] index: Index of buffer in output buffer info array. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_ftb( + OMX_BUFFERHEADERTYPE *p_buffer_hdr, + unsigned int index) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + m_port_op.num_pending_buffers++; + + if (m_port_op.flush_inprogress) + { + OMX_SWVDEC_LOG_HIGH("returning %p, buffer %p; " + "op port flush in progress", + p_buffer_hdr, + m_buffer_array_op[index].buffer_swvdec.p_buffer); + + async_post_event(OMX_SWVDEC_EVENT_FBD, + (unsigned long) p_buffer_hdr, + (unsigned long) index); + } + else + { + SWVDEC_STATUS retval_swvdec; + + SWVDEC_BUFFER *p_buffer_swvdec = + &(m_buffer_array_op[index].buffer_swvdec); + + retval_swvdec = swvdec_fillthisbuffer(m_swvdec_handle, p_buffer_swvdec); + + if (retval_swvdec != SWVDEC_STATUS_SUCCESS) + { + retval = retval_swvdec2omx(retval_swvdec); + } + } + + return retval; +} + +/** + * @brief Process EBD event. + * + * @param[in] p_buffer_hdr: Pointer to buffer header. + * @param[in] index: Index of buffer in output buffer info array. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_ebd( + OMX_BUFFERHEADERTYPE *p_buffer_hdr, + unsigned int index) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (index < m_port_ip.def.nBufferCountActual) + { + m_port_ip.num_pending_buffers--; + + // should ideally be set in swvdec_empty_buffer_done() + p_buffer_hdr->nFilledLen = 0; + + OMX_SWVDEC_LOG_CALLBACK( + "EmptyBufferDone(): %p, buffer %p", + p_buffer_hdr, + m_buffer_array_ip[index].buffer_swvdec.p_buffer); + + m_callback.EmptyBufferDone(&m_cmp, m_app_data, p_buffer_hdr); + } + else + { + OMX_SWVDEC_LOG_ERROR("buffer index '%d' invalid", index); + retval = OMX_ErrorBadParameter; + } + + return retval; +} + +/** + * @brief Process FBD event. + * + * @param[in] p_buffer_hdr: Pointer to buffer header. + * @param[in] index: Index of buffer in output buffer info array. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_fbd( + OMX_BUFFERHEADERTYPE *p_buffer_hdr, + unsigned int index) +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (index < m_port_op.def.nBufferCountActual) + { + OMX_U8 *p_buffer; + + p_buffer = m_buffer_array_op[index].buffer_swvdec.p_buffer; + + m_port_op.num_pending_buffers--; + + if (m_port_op.flush_inprogress) + { + p_buffer_hdr->nFilledLen = 0; + p_buffer_hdr->nTimeStamp = 0; + p_buffer_hdr->nFlags &= ~OMX_BUFFERFLAG_DATACORRUPT; + } + + if (p_buffer_hdr->nFilledLen) + { + if (m_sync_frame_decoding_mode) + { + p_buffer_hdr->nTimeStamp = 0; + } + else + { + if (m_ts_list.pop(&p_buffer_hdr->nTimeStamp) == false) + { + OMX_SWVDEC_LOG_ERROR("failed to pop timestamp from list"); + } + } + + m_diag.dump_op(p_buffer, + m_frame_dimensions.width, + m_frame_dimensions.height, + m_frame_attributes.stride, + m_frame_attributes.scanlines); + } + + if (p_buffer_hdr->nFlags & OMX_BUFFERFLAG_EOS) + { + async_post_event(OMX_SWVDEC_EVENT_EOS, 0, 0); + + m_ts_list.reset(); + } + + if (m_meta_buffer_mode && + ((p_buffer_hdr->nFlags & OMX_BUFFERFLAG_READONLY)) == 0) + { + meta_buffer_ref_remove( + m_buffer_array_op[index].buffer_payload.pmem_fd, + m_buffer_array_op[index].buffer_payload.offset); + } + + OMX_SWVDEC_LOG_CALLBACK( + "FillBufferDone(): %p, buffer %p, " + "flags 0x%08x, timestamp %lld", + p_buffer_hdr, + p_buffer, + p_buffer_hdr->nFlags, + p_buffer_hdr->nTimeStamp); + + m_callback.FillBufferDone(&m_cmp, m_app_data, p_buffer_hdr); + } + else + { + OMX_SWVDEC_LOG_ERROR("buffer index '%d' invalid", index); + retval = OMX_ErrorBadParameter; + } + +async_process_event_fbd_exit: + return retval; +} + +/** + * @brief Process EOS event. + * + * @retval OMX_ErrorNone + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_eos() +{ + OMX_SWVDEC_LOG_CALLBACK("EventHandler(): " + "OMX_EventBufferFlag, port %d, EOS", + OMX_CORE_PORT_INDEX_OP); + + m_callback.EventHandler(&m_cmp, + m_app_data, + OMX_EventBufferFlag, + OMX_CORE_PORT_INDEX_OP, + OMX_BUFFERFLAG_EOS, + NULL); + + return OMX_ErrorNone; +} + +/** + * @brief Process input port flush event. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_flush_port_ip() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + OMX_SWVDEC_EVENT_INFO event_info; + + OMX_BUFFERHEADERTYPE *p_buffer_hdr; + + unsigned int index; + + while (m_queue_port_ip.pop(&event_info)) + { + switch (event_info.event_id) + { + + case OMX_SWVDEC_EVENT_ETB: + { + p_buffer_hdr = (OMX_BUFFERHEADERTYPE *) event_info.event_param1; + index = event_info.event_param2; + + // compensate decrement in async_process_event_ebd() + m_port_ip.num_pending_buffers++; + + retval = async_process_event_ebd(p_buffer_hdr, index); + break; + } + + case OMX_SWVDEC_EVENT_EBD: + { + p_buffer_hdr = (OMX_BUFFERHEADERTYPE *) event_info.event_param1; + index = event_info.event_param2; + + retval = async_process_event_ebd(p_buffer_hdr, index); + break; + } + + default: + { + assert(0); + break; + } + + } + } + + assert(m_port_ip.num_pending_buffers == 0); + + if ((retval == OMX_ErrorNone) && + (m_status_flags & (1 << PENDING_PORT_FLUSH_IP))) + { + m_status_flags &= ~(1 << PENDING_PORT_FLUSH_IP); + + async_post_event(OMX_SWVDEC_EVENT_CMD_ACK, + OMX_CommandFlush, + OMX_CORE_PORT_INDEX_IP); + } + + m_port_ip.flush_inprogress = OMX_FALSE; + + return retval; +} + +/** + * @brief Process output port flush event. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_flush_port_op() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + OMX_SWVDEC_EVENT_INFO event_info; + + OMX_BUFFERHEADERTYPE *p_buffer_hdr; + + unsigned int index; + + while (m_queue_port_op.pop(&event_info)) + { + switch (event_info.event_id) + { + + case OMX_SWVDEC_EVENT_FTB: + { + p_buffer_hdr = (OMX_BUFFERHEADERTYPE *) event_info.event_param1; + index = event_info.event_param2; + + // compensate decrement in async_process_event_fbd() + m_port_op.num_pending_buffers++; + + retval = async_process_event_fbd(p_buffer_hdr, index); + break; + } + + case OMX_SWVDEC_EVENT_FBD: + { + p_buffer_hdr = (OMX_BUFFERHEADERTYPE *) event_info.event_param1; + index = event_info.event_param2; + + retval = async_process_event_fbd(p_buffer_hdr, index); + break; + } + + default: + { + assert(0); + break; + } + + } + } + + assert(m_port_op.num_pending_buffers == 0); + + if ((retval == OMX_ErrorNone) && + (m_status_flags & (1 << PENDING_PORT_FLUSH_OP))) + { + m_status_flags &= ~(1 << PENDING_PORT_FLUSH_OP); + + async_post_event(OMX_SWVDEC_EVENT_CMD_ACK, + OMX_CommandFlush, + OMX_CORE_PORT_INDEX_OP); + } + + if ((retval == OMX_ErrorNone) && + (m_status_flags & (1 << PENDING_STATE_EXECUTING_TO_IDLE))) + { + m_status_flags &= ~(1 << PENDING_STATE_EXECUTING_TO_IDLE); + + async_post_event(OMX_SWVDEC_EVENT_CMD_ACK, + OMX_CommandStateSet, + OMX_StateIdle); + } + + if (m_port_reconfig_inprogress == false) + { + m_ts_list.reset(); + } + + m_port_op.flush_inprogress = OMX_FALSE; + + return retval; +} + +/** + * @brief Process port reconfiguration event. + * + * @retval OMX_ERRORTYPE + */ +OMX_ERRORTYPE omx_swvdec::async_process_event_port_reconfig() +{ + OMX_ERRORTYPE retval = OMX_ErrorNone; + + if (m_port_reconfig_inprogress) + { + OMX_SWVDEC_LOG_ERROR("port reconfiguration in progress"); + retval = OMX_ErrorIncorrectStateOperation; + } + else + { + m_port_reconfig_inprogress = true; + + OMX_SWVDEC_LOG_CALLBACK("EventHandler(): " + "OMX_EventPortSettingsChanged, port %d", + OMX_CORE_PORT_INDEX_OP); + + m_callback.EventHandler(&m_cmp, + m_app_data, + OMX_EventPortSettingsChanged, + OMX_CORE_PORT_INDEX_OP, + 0, + NULL); + } + + return retval; +} diff --git a/mm-video-v4l2/vidc/vdec/src/omx_swvdec_utils.cpp b/mm-video-v4l2/vidc/vdec/src/omx_swvdec_utils.cpp new file mode 100644 index 00000000..d07a63be --- /dev/null +++ b/mm-video-v4l2/vidc/vdec/src/omx_swvdec_utils.cpp @@ -0,0 +1,461 @@ +/** + * @copyright + * + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * @file + * + * omx_swvdec_utils.cpp + * + * @brief + * + * OMX software video decoder utility functions source. + */ + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <pthread.h> + +#include <cutils/properties.h> + +#include "omx_swvdec_utils.h" + +#define OMX_SWVDEC_LOGLEVEL_DEFAULT 2 ///< default OMX SwVdec loglevel + +unsigned int g_omx_swvdec_logmask = (1 << OMX_SWVDEC_LOGLEVEL_DEFAULT) - 1; + ///< global OMX SwVdec logmask variable definition + +/** + * @brief Initialize OMX SwVdec log level & mask. + */ +void omx_swvdec_log_init() +{ + int omx_swvdec_loglevel = OMX_SWVDEC_LOGLEVEL_DEFAULT; + + char property_value[PROPERTY_VALUE_MAX] = {0}; + + if (property_get("omx_swvdec.log.level", property_value, NULL)) + { + omx_swvdec_loglevel = atoi(property_value); + + if (omx_swvdec_loglevel > 3) + omx_swvdec_loglevel = 3; + if (omx_swvdec_loglevel < 0) + omx_swvdec_loglevel = 0; + + OMX_SWVDEC_LOG_LOW( + "omx_swvdec.log.level: %d; %s", + omx_swvdec_loglevel, + (omx_swvdec_loglevel == 3) ? "error, high, & low logs" : + ((omx_swvdec_loglevel == 2) ? "error & high logs" : + ((omx_swvdec_loglevel == 1) ? "error logs" : + "no logs"))); + } + + g_omx_swvdec_logmask = (unsigned int) ((1 << omx_swvdec_loglevel) - 1); +} + +/** + * @brief OMX SwVdec queue constructor. + */ +omx_swvdec_queue::omx_swvdec_queue() +{ + memset(m_queue, 0, sizeof(m_queue)); + + m_count_total = OMX_SWVDEC_QUEUE_ELEMENTS; + m_count_filled = 0; + m_index_write = 0; + m_index_read = 0; + + pthread_mutex_init(&m_mutex, NULL); +} + +/** + * @brief OMX SwVdec queue destructor. + */ +omx_swvdec_queue::~omx_swvdec_queue() +{ + pthread_mutex_destroy(&m_mutex); +} + +/** + * @brief Push event to queue. + * + * @param[in] p_event_info: Pointer to event information structure. + * + * @retval true if push successful + * @retval false if push unsuccessful + */ +bool omx_swvdec_queue::push(OMX_SWVDEC_EVENT_INFO *p_event_info) +{ + bool retval = true; + + pthread_mutex_lock(&m_mutex); + + if (m_count_filled < m_count_total) + { + m_queue[m_index_write] = *p_event_info; + + m_index_write = (m_index_write + 1) % m_count_total; + m_count_filled++; + } + else + { + retval = false; + } + + pthread_mutex_unlock(&m_mutex); + + return retval; +} + +/** + * @brief Pop event from queue. + * + * @param[in,out] p_event_info: Pointer to event information structure. + * + * @retval true if pop successful + * @retval false if pop unsuccessful + */ +bool omx_swvdec_queue::pop(OMX_SWVDEC_EVENT_INFO *p_event_info) +{ + bool retval = true; + + pthread_mutex_lock(&m_mutex); + + if (m_count_filled > 0) + { + *p_event_info = m_queue[m_index_read]; + + memset(&m_queue[m_index_read], 0, sizeof(OMX_SWVDEC_EVENT_INFO)); + + m_index_read = (m_index_read + 1) % m_count_total; + m_count_filled--; + } + else + { + retval = false; + } + + pthread_mutex_unlock(&m_mutex); + + return retval; +} + +/** + * @brief OMX SwVdec timestamp list constructor. + */ +omx_swvdec_ts_list::omx_swvdec_ts_list() +{ + reset(); + + pthread_mutex_init(&m_mutex, NULL); +} + +/** + * @brief OMX SwVdec timestamp list destructor. + */ +omx_swvdec_ts_list::~omx_swvdec_ts_list() +{ + pthread_mutex_destroy(&m_mutex); +} + +/** + * @brief Reset timestamp list. + */ +void omx_swvdec_ts_list::reset() +{ + memset(m_list, 0, sizeof(m_list)); + m_count_filled = 0; +} + +/** + * @brief Push timestamp to list, keeping lowest-valued timestamp at the end. + * + * @param[in] timestamp: Timestamp. + * + * @retval true if push successful + * @retval false if push unsuccessful + */ +bool omx_swvdec_ts_list::push(long long timestamp) +{ + bool retval = true; + + pthread_mutex_lock(&m_mutex); + + if (m_count_filled < OMX_SWVDEC_TS_LIST_ELEMENTS) + { + int index_curr, index_prev; + + long long timestamp_tmp; + + // insert timestamp into list + + m_list[m_count_filled].filled = true; + m_list[m_count_filled].timestamp = timestamp; + m_count_filled++; + + // iterate backwards + + index_curr = m_count_filled - 1; + index_prev = m_count_filled - 2; + + while ((index_curr > 0) && + (m_list[index_curr].timestamp > m_list[index_prev].timestamp)) + { + // swap timestamps + + timestamp_tmp = m_list[index_prev].timestamp; + m_list[index_prev].timestamp = m_list[index_curr].timestamp; + m_list[index_curr].timestamp = timestamp_tmp; + + index_curr--; + index_prev--; + } + } + else + { + retval = false; + } + + pthread_mutex_unlock(&m_mutex); + + return retval; +} + +/** + * @brief Pop timestamp from list. + * + * @param[in,out] p_timestamp: Pointer to timestamp variable. + * + * @retval true if pop successful + * @retval false if pop unsuccessful + */ +bool omx_swvdec_ts_list::pop(long long *p_timestamp) +{ + bool retval; + + pthread_mutex_lock(&m_mutex); + + if (m_count_filled) + { + *p_timestamp = m_list[m_count_filled - 1].timestamp; + m_list[m_count_filled - 1].filled = false; + m_count_filled--; + + retval = true; + } + else + { + retval = false; + } + + pthread_mutex_unlock(&m_mutex); + + return retval; +} + +/** + * @brief OMX SwVdec diagnostics class constructor. + */ +omx_swvdec_diag::omx_swvdec_diag(): + m_dump_ip(0), + m_dump_op(0), + m_filename_ip(NULL), + m_filename_op(NULL), + m_file_ip(NULL), + m_file_op(NULL) +{ + char property_value[PROPERTY_VALUE_MAX] = {0}; + + if (property_get("omx_swvdec.dump.ip", property_value, NULL)) + { + m_dump_ip = atoi(property_value); + OMX_SWVDEC_LOG_LOW("omx_swvdec.dump.ip: %d", m_dump_ip); + } + + if (property_get("omx_swvdec.dump.op", property_value, NULL)) + { + m_dump_op = atoi(property_value); + OMX_SWVDEC_LOG_LOW("omx_swvdec.dump.op: %d", m_dump_op); + } + + if (property_get("omx_swvdec.filename.ip", + property_value, + DIAG_FILENAME_IP)) + { + OMX_SWVDEC_LOG_LOW("omx_swvdec.filename.ip: %s", m_filename_ip); + + m_filename_ip = + (char *) malloc((strlen(property_value) + 1) * sizeof(char)); + + if (m_filename_ip == NULL) + { + OMX_SWVDEC_LOG_ERROR("failed to allocate %d bytes for " + "input filename string", + (strlen(property_value) + 1) * sizeof(char)); + } + else + { + strncpy(m_filename_ip, property_value, strlen(property_value) + 1); + } + } + + if (property_get("omx_swvdec.filename.op", + property_value, + DIAG_FILENAME_OP)) + { + OMX_SWVDEC_LOG_LOW("omx_swvdec.filename.op: %s", m_filename_op); + + m_filename_op = + (char *) malloc((strlen(property_value) + 1) * sizeof(char)); + + if (m_filename_op == NULL) + { + OMX_SWVDEC_LOG_ERROR("failed to allocate %d bytes for " + "output filename string", + (strlen(property_value) + 1) * sizeof(char)); + } + else + { + strncpy(m_filename_op, property_value, strlen(property_value) + 1); + } + } + + if (m_dump_ip && (m_filename_ip != NULL)) + { + if ((m_file_ip = fopen(m_filename_ip, "rb")) == NULL) + { + OMX_SWVDEC_LOG_ERROR("cannot open input file '%s'", m_filename_ip); + m_dump_ip = 0; + } + } + else + { + m_dump_ip = 0; + } + + if (m_dump_op && (m_filename_op != NULL)) + { + if ((m_file_op = fopen(m_filename_op, "rb")) == NULL) + { + OMX_SWVDEC_LOG_ERROR("cannot open output file '%s'", m_filename_op); + m_dump_op = 0; + } + } + else + { + m_dump_op = 0; + } +} + +/** + * @brief OMX SwVdec diagnostics class destructor. + */ +omx_swvdec_diag::~omx_swvdec_diag() +{ + if (m_file_op) + { + fclose(m_file_op); + m_file_op = NULL; + } + + if (m_file_ip) + { + fclose(m_file_ip); + m_file_ip = NULL; + } + + if (m_filename_op) + { + free(m_filename_op); + m_filename_op = NULL; + } + + if (m_filename_ip) + { + free(m_filename_ip); + m_filename_ip = NULL; + } +} + +/** + * @brief Dump input bitstream to file. + * + * @param[in] p_buffer: Pointer to input bitstream buffer. + * @param[in] filled_length: Bitstream buffer's filled length. + */ +void omx_swvdec_diag::dump_ip(unsigned char *p_buffer, + unsigned int filled_length) +{ + if (m_dump_ip) + { + fwrite(p_buffer, sizeof(unsigned char), filled_length, m_file_ip); + } +} + +/** + * @brief Dump output YUV to file. + * + * @param[in] p_buffer: Pointer to output YUV buffer. + * @param[in] width: Frame width. + * @param[in] height: Frame height. + * @param[in] stride: Frame stride. + * @param[in] scanlines: Frame scanlines. + */ +void omx_swvdec_diag::dump_op(unsigned char *p_buffer, + unsigned int width, + unsigned int height, + unsigned int stride, + unsigned int scanlines) +{ + if (m_dump_op) + { + unsigned char *p_buffer_y; + unsigned char *p_buffer_uv; + + unsigned int ii; + + p_buffer_y = p_buffer; + p_buffer_uv = p_buffer + (stride * scanlines); + + for (ii = 0; ii < height; ii++) + { + fwrite(p_buffer_y, sizeof(unsigned char), width, m_file_op); + + p_buffer_y += stride; + } + + for (ii = 0; ii < (height / 2); ii++) + { + fwrite(p_buffer_uv, sizeof(unsigned char), width, m_file_op); + + p_buffer_uv += stride; + } + } +} |